Skip to content

Commit 0f48a69

Browse files
committed
adding webusb support
webusb_serial example enumerated, landing page is loaded correctly.
1 parent 3dd74a3 commit 0f48a69

File tree

4 files changed

+348
-0
lines changed

4 files changed

+348
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*********************************************************************
2+
Adafruit invests time and resources providing this open source code,
3+
please support Adafruit and open-source hardware by purchasing
4+
products from Adafruit!
5+
6+
MIT license, check LICENSE for more information
7+
Copyright (c) 2019 Ha Thach for Adafruit Industries
8+
All text above, and the splash screen below must be included in
9+
any redistribution
10+
*********************************************************************/
11+
12+
#include "Adafruit_TinyUSB.h"
13+
14+
/* This sketch demonstrates WebUSB
15+
*/
16+
17+
// USB WebUSB object
18+
Adafruit_USBD_WebUSB usb_web;
19+
20+
// Landing Page: scheme (0: http, 1: https), url
21+
const tusb_desc_webusb_url_t landingPage = TUD_WEBUSB_URL_DESCRIPTOR(1 /*https*/, "adafruit.github.io/Adafruit_TinyUSB_Arduino/examples/webusb-serial");
22+
23+
// the setup function runs once when you press reset or power the board
24+
void setup()
25+
{
26+
usb_web.begin();
27+
usb_web.setLandingPage(&landingPage);
28+
29+
Serial.begin(115200);
30+
31+
// wait until device mounted
32+
while( !USBDevice.mounted() ) delay(1);
33+
34+
Serial.println("Adafruit TinyUSB WebUSB example");
35+
}
36+
37+
void loop()
38+
{
39+
delay(1000);
40+
digitalWrite(LED_BUILTIN, 1-digitalRead(LED_BUILTIN));
41+
}

src/Adafruit_TinyUSB.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@
2828
#include "Adafruit_USBD_MSC.h"
2929
#include "Adafruit_USBD_HID.h"
3030
#include "Adafruit_USBD_MIDI.h"
31+
#include "Adafruit_USBD_WebUSB.h"
3132

3233
#endif /* ADAFRUIT_TINYUSB_H_ */

src/Adafruit_USBD_WebUSB.cpp

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2019 hathach for Adafruit Industries
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
#include "Adafruit_USBD_WebUSB.h"
26+
27+
#if CFG_TUD_VENDOR
28+
29+
//--------------------------------------------------------------------+
30+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
31+
//--------------------------------------------------------------------+
32+
#define EPOUT 0x00
33+
#define EPIN 0x80
34+
#define EPSIZE 64
35+
36+
enum
37+
{
38+
VENDOR_REQUEST_WEBUSB = 1,
39+
VENDOR_REQUEST_MICROSOFT = 2
40+
};
41+
42+
43+
static Adafruit_USBD_WebUSB* _webusb_dev = NULL;
44+
45+
//--------------------------------------------------------------------+
46+
// BOS Descriptor
47+
//--------------------------------------------------------------------+
48+
49+
/* Microsoft OS 2.0 registry property descriptor
50+
Per MS requirements https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx
51+
device should create DeviceInterfaceGUIDs. It can be done by driver and
52+
in case of real PnP solution device should expose MS "Microsoft OS 2.0
53+
registry property descriptor". Such descriptor can insert any record
54+
into Windows registry per device/configuration/interface. In our case it
55+
will insert "DeviceInterfaceGUIDs" multistring property.
56+
57+
GUID is freshly generated and should be OK to use.
58+
59+
https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/
60+
(Section Microsoft OS compatibility descriptors)
61+
*/
62+
63+
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_WEBUSB_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
64+
65+
#define MS_OS_20_DESC_LEN 0xB2
66+
67+
// BOS Descriptor is required for webUSB
68+
uint8_t const desc_bos[] =
69+
{
70+
// total length, number of device caps
71+
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 2),
72+
73+
// Vendor Code, iLandingPage
74+
TUD_BOS_WEBUSB_DESCRIPTOR(VENDOR_REQUEST_WEBUSB, 1),
75+
76+
// Microsoft OS 2.0 descriptor
77+
TUD_BOS_MS_OS_20_DESCRIPTOR(MS_OS_20_DESC_LEN, VENDOR_REQUEST_MICROSOFT)
78+
};
79+
80+
uint8_t const * tud_descriptor_bos_cb(void)
81+
{
82+
return desc_bos;
83+
}
84+
85+
uint8_t desc_ms_os_20[] =
86+
{
87+
// Set header: length, type, windows version, total length
88+
U16_TO_U8S_LE(0x000A), U16_TO_U8S_LE(MS_OS_20_SET_HEADER_DESCRIPTOR), U32_TO_U8S_LE(0x06030000), U16_TO_U8S_LE(MS_OS_20_DESC_LEN),
89+
90+
// Configuration subset header: length, type, configuration index, reserved, configuration total length
91+
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_CONFIGURATION), 0, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A),
92+
93+
// Function Subset header: length, type, first interface, reserved, subset length
94+
U16_TO_U8S_LE(0x0008), U16_TO_U8S_LE(MS_OS_20_SUBSET_HEADER_FUNCTION), 0 /*itf num*/, 0, U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08),
95+
96+
// MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID
97+
U16_TO_U8S_LE(0x0014), U16_TO_U8S_LE(MS_OS_20_FEATURE_COMPATBLE_ID), 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,
98+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // sub-compatible
99+
100+
// MS OS 2.0 Registry property descriptor: length, type
101+
U16_TO_U8S_LE(MS_OS_20_DESC_LEN-0x0A-0x08-0x08-0x14), U16_TO_U8S_LE(MS_OS_20_FEATURE_REG_PROPERTY),
102+
U16_TO_U8S_LE(0x0007), U16_TO_U8S_LE(0x002A), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
103+
'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00,
104+
'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00, 'D', 0x00, 's', 0x00, 0x00, 0x00,
105+
U16_TO_U8S_LE(0x0050), // wPropertyDataLength
106+
//bPropertyData: “{975F44D9-0D08-43FD-8B3E-127CA8AFFF9D}”.
107+
'{', 0x00, '9', 0x00, '7', 0x00, '5', 0x00, 'F', 0x00, '4', 0x00, '4', 0x00, 'D', 0x00, '9', 0x00, '-', 0x00,
108+
'0', 0x00, 'D', 0x00, '0', 0x00, '8', 0x00, '-', 0x00, '4', 0x00, '3', 0x00, 'F', 0x00, 'D', 0x00, '-', 0x00,
109+
'8', 0x00, 'B', 0x00, '3', 0x00, 'E', 0x00, '-', 0x00, '1', 0x00, '2', 0x00, '7', 0x00, 'C', 0x00, 'A', 0x00,
110+
'8', 0x00, 'A', 0x00, 'F', 0x00, 'F', 0x00, 'F', 0x00, '9', 0x00, 'D', 0x00, '}', 0x00, 0x00, 0x00, 0x00, 0x00
111+
};
112+
113+
TU_VERIFY_STATIC(sizeof(desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size");
114+
115+
//------------- IMPLEMENTATION -------------//
116+
117+
Adafruit_USBD_WebUSB::Adafruit_USBD_WebUSB(void)
118+
{
119+
_connected = false;
120+
_url = NULL;
121+
}
122+
123+
bool Adafruit_USBD_WebUSB::begin(void)
124+
{
125+
if ( !USBDevice.addInterface(*this) ) return false;
126+
127+
// WebUSB requires to change USB version from 2.0 to 2.1
128+
USBDevice.setVersion(0x2010);
129+
130+
_webusb_dev = this;
131+
return true;
132+
}
133+
134+
bool Adafruit_USBD_WebUSB::setLandingPage(const void* url)
135+
{
136+
_url = (const uint8_t*) url;
137+
return true;
138+
}
139+
140+
uint16_t Adafruit_USBD_WebUSB::getDescriptor(uint8_t itfnum, uint8_t* buf, uint16_t bufsize)
141+
{
142+
// usb core will automatically update endpoint number
143+
uint8_t desc[] = { TUD_VENDOR_DESCRIPTOR(itfnum, 0, EPOUT, EPIN, 64) };
144+
uint16_t const len = sizeof(desc);
145+
146+
if ( bufsize < len ) return 0;
147+
memcpy(buf, desc, len);
148+
149+
// update the bFirstInterface in MS OS 2.0 descriptor
150+
// that is binded to WinUSB driver
151+
desc_ms_os_20[0x0a + 0x08 + 4] = itfnum;
152+
153+
return len;
154+
}
155+
156+
int Adafruit_USBD_WebUSB::read (void)
157+
{
158+
return -1;
159+
}
160+
161+
size_t Adafruit_USBD_WebUSB::write (uint8_t b)
162+
{
163+
return 0;
164+
}
165+
166+
int Adafruit_USBD_WebUSB::available (void)
167+
{
168+
return 0;
169+
}
170+
171+
int Adafruit_USBD_WebUSB::peek (void)
172+
{
173+
return -1;
174+
}
175+
176+
void Adafruit_USBD_WebUSB::flush (void)
177+
{
178+
179+
}
180+
181+
extern "C"
182+
{
183+
184+
// Invoked when received VENDOR control request
185+
bool tud_vendor_control_request_cb(uint8_t rhport, tusb_control_request_t const * request)
186+
{
187+
if (!_webusb_dev) return false;
188+
189+
switch (request->bRequest)
190+
{
191+
case VENDOR_REQUEST_WEBUSB:
192+
// match vendor request in BOS descriptor
193+
// Get landing page url
194+
if ( !_webusb_dev->_url ) return false;
195+
return tud_control_xfer(rhport, request, (void*) _webusb_dev->_url, _webusb_dev->_url[0]);
196+
197+
case VENDOR_REQUEST_MICROSOFT:
198+
if ( request->wIndex == 7 )
199+
{
200+
// Get Microsoft OS 2.0 compatible descriptor
201+
uint16_t total_len;
202+
memcpy(&total_len, desc_ms_os_20+8, 2);
203+
204+
return tud_control_xfer(rhport, request, (void*) desc_ms_os_20, total_len);
205+
}else
206+
{
207+
return false;
208+
}
209+
210+
case 0x22:
211+
// Webserial simulate the CDC_REQUEST_SET_CONTROL_LINE_STATE (0x22) to
212+
// connect and disconnect.
213+
_webusb_dev->_connected = (request->wValue != 0);
214+
215+
// Always lit LED if connected
216+
if ( request->wValue )
217+
{
218+
219+
}else
220+
{
221+
222+
}
223+
224+
// response with status OK
225+
return tud_control_status(rhport, request);
226+
227+
default:
228+
// stall unknown request
229+
return false;
230+
}
231+
232+
return true;
233+
}
234+
235+
// Invoked when DATA Stage of VENDOR's request is complete
236+
bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const * request)
237+
{
238+
(void) rhport;
239+
(void) request;
240+
241+
// nothing to do
242+
return true;
243+
}
244+
245+
}
246+
247+
#endif

src/Adafruit_USBD_WebUSB.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2019 hathach for Adafruit Industries
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
#ifndef ADAFRUIT_USBD_WEBUSB_H_
26+
#define ADAFRUIT_USBD_WEBUSB_H_
27+
28+
#include "Adafruit_TinyUSB_Core.h"
29+
30+
class Adafruit_USBD_WebUSB : public Stream, Adafruit_USBD_Interface
31+
{
32+
public:
33+
Adafruit_USBD_WebUSB(void);
34+
35+
bool begin(void);
36+
37+
bool setLandingPage(const void* url);
38+
39+
// Stream interface to use with MIDI Library
40+
virtual int read ( void );
41+
virtual size_t write ( uint8_t b );
42+
virtual int available ( void );
43+
virtual int peek ( void );
44+
virtual void flush ( void );
45+
46+
// from Adafruit_USBD_Interface
47+
virtual uint16_t getDescriptor(uint8_t itfnum, uint8_t* buf, uint16_t bufsize);
48+
49+
private:
50+
bool _connected;
51+
const uint8_t* _url;
52+
53+
// Make all tinyusb callback friend to access private data
54+
friend bool tud_vendor_control_request_cb(uint8_t rhport, tusb_control_request_t const * request);
55+
friend bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const * request);
56+
};
57+
58+
59+
#endif /* ADAFRUIT_USBD_WEBUSB_H_ */

0 commit comments

Comments
 (0)