| 
									
										
										
										
											2023-03-17 16:12:49 +07:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2019-07-11 23:12:53 +07:00
										 |  |  |  * 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. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-10 11:23:44 +07:00
										 |  |  | /* This example demonstrates WebUSB as web serial with browser with WebUSB support (e.g Chrome).
 | 
					
						
							|  |  |  |  * After enumerated successfully, browser will pop-up notification | 
					
						
							|  |  |  |  * with URL to landing page, click on it to test | 
					
						
							|  |  |  |  *  - Click "Connect" and select device, When connected the on-board LED will litted up. | 
					
						
							|  |  |  |  *  - Any charters received from either webusb/Serial will be echo back to webusb and Serial | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Note: | 
					
						
							|  |  |  |  * - The WebUSB landing page notification is currently disabled in Chrome | 
					
						
							|  |  |  |  * on Windows due to Chromium issue 656702 (https://crbug.com/656702). You have to
 | 
					
						
							|  |  |  |  * go to landing page (below) to test | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * - On Windows 7 and prior: You need to use Zadig tool to manually bind the | 
					
						
							|  |  |  |  * WebUSB interface with the WinUSB driver for Chrome to access. From windows 8 and 10, this | 
					
						
							|  |  |  |  * is done automatically by firmware. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * - On Linux/macOS, udev permission may need to be updated by | 
					
						
							|  |  |  |  *   - copying '/examples/device/99-tinyusb.rules' file to /etc/udev/rules.d/ then | 
					
						
							|  |  |  |  *   - run 'sudo udevadm control --reload-rules && sudo udevadm trigger' | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-11 23:12:53 +07:00
										 |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "bsp/board.h"
 | 
					
						
							|  |  |  | #include "tusb.h"
 | 
					
						
							| 
									
										
										
										
											2019-07-26 11:36:30 +07:00
										 |  |  | #include "usb_descriptors.h"
 | 
					
						
							| 
									
										
										
										
											2019-07-11 23:12:53 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // MACRO CONSTANT TYPEDEF PROTYPES
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Blink pattern
 | 
					
						
							|  |  |  |  * - 250 ms  : device not mounted | 
					
						
							|  |  |  |  * - 1000 ms : device mounted | 
					
						
							|  |  |  |  * - 2500 ms : device is suspended | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | enum  { | 
					
						
							|  |  |  |   BLINK_NOT_MOUNTED = 250, | 
					
						
							| 
									
										
										
										
											2019-07-26 11:43:34 +07:00
										 |  |  |   BLINK_MOUNTED     = 1000, | 
					
						
							|  |  |  |   BLINK_SUSPENDED   = 2500, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   BLINK_ALWAYS_ON   = UINT32_MAX, | 
					
						
							|  |  |  |   BLINK_ALWAYS_OFF  = 0 | 
					
						
							| 
									
										
										
										
											2019-07-11 23:12:53 +07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-12 01:55:33 +07:00
										 |  |  | #define URL  "example.tinyusb.org/webusb-serial/index.html"
 | 
					
						
							| 
									
										
										
										
											2019-07-26 11:36:30 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | const tusb_desc_webusb_url_t desc_url = | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   .bLength         = 3 + sizeof(URL) - 1, | 
					
						
							|  |  |  |   .bDescriptorType = 3, // WEBUSB URL type
 | 
					
						
							|  |  |  |   .bScheme         = 1, // 0: http, 1: https
 | 
					
						
							|  |  |  |   .url             = URL | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool web_serial_connected = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //------------- prototypes -------------//
 | 
					
						
							| 
									
										
										
										
											2019-07-11 23:12:53 +07:00
										 |  |  | void led_blinking_task(void); | 
					
						
							| 
									
										
										
										
											2019-07-12 19:38:04 +07:00
										 |  |  | void cdc_task(void); | 
					
						
							| 
									
										
										
										
											2019-07-25 16:52:20 +07:00
										 |  |  | void webserial_task(void); | 
					
						
							| 
									
										
										
										
											2019-07-11 23:12:53 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*------------- MAIN -------------*/ | 
					
						
							|  |  |  | int main(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   board_init(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-06 22:41:04 +07:00
										 |  |  |   // init device stack on configured roothub port
 | 
					
						
							|  |  |  |   tud_init(BOARD_TUD_RHPORT); | 
					
						
							| 
									
										
										
										
											2019-07-11 23:12:53 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |   while (1) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     tud_task(); // tinyusb device task
 | 
					
						
							| 
									
										
										
										
											2019-07-12 19:38:04 +07:00
										 |  |  |     cdc_task(); | 
					
						
							| 
									
										
										
										
											2019-07-25 16:52:20 +07:00
										 |  |  |     webserial_task(); | 
					
						
							| 
									
										
										
										
											2019-07-11 23:12:53 +07:00
										 |  |  |     led_blinking_task(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-26 20:14:56 +07:00
										 |  |  | // send characters to both CDC and WebUSB
 | 
					
						
							|  |  |  | void echo_all(uint8_t buf[], uint32_t count) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   // echo to web serial
 | 
					
						
							|  |  |  |   if ( web_serial_connected ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     tud_vendor_write(buf, count); | 
					
						
							| 
									
										
										
										
											2023-03-30 11:34:39 -05:00
										 |  |  |     tud_vendor_write_flush(); | 
					
						
							| 
									
										
										
										
											2019-07-26 20:14:56 +07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // echo to cdc
 | 
					
						
							|  |  |  |   if ( tud_cdc_connected() ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     for(uint32_t i=0; i<count; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       tud_cdc_write_char(buf[i]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if ( buf[i] == '\r' ) tud_cdc_write_char('\n'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     tud_cdc_write_flush(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-11 23:12:53 +07:00
										 |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // Device callbacks
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Invoked when device is mounted
 | 
					
						
							|  |  |  | void tud_mount_cb(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   blink_interval_ms = BLINK_MOUNTED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Invoked when device is unmounted
 | 
					
						
							|  |  |  | void tud_umount_cb(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   blink_interval_ms = BLINK_NOT_MOUNTED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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; | 
					
						
							|  |  |  |   blink_interval_ms = BLINK_SUSPENDED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Invoked when usb bus is resumed
 | 
					
						
							|  |  |  | void tud_resume_cb(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   blink_interval_ms = BLINK_MOUNTED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2019-07-26 11:36:30 +07:00
										 |  |  | // WebUSB use vendor class
 | 
					
						
							| 
									
										
										
										
											2019-07-11 23:12:53 +07:00
										 |  |  | //--------------------------------------------------------------------+
 | 
					
						
							| 
									
										
										
										
											2019-07-26 11:36:30 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-20 15:50:11 +07:00
										 |  |  | // 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) | 
					
						
							| 
									
										
										
										
											2019-07-26 11:36:30 +07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-11-20 15:50:11 +07:00
										 |  |  |   // nothing to with DATA & ACK stage
 | 
					
						
							| 
									
										
										
										
											2021-03-10 11:31:50 +07:00
										 |  |  |   if (stage != CONTROL_STAGE_SETUP) return true; | 
					
						
							| 
									
										
										
										
											2020-11-20 15:50:11 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-10 11:31:50 +07:00
										 |  |  |   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
 | 
					
						
							| 
									
										
										
										
											2021-10-17 16:26:27 +07:00
										 |  |  |           return tud_control_xfer(rhport, request, (void*)(uintptr_t) &desc_url, desc_url.bLength); | 
					
						
							| 
									
										
										
										
											2021-03-10 11:31:50 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         case VENDOR_REQUEST_MICROSOFT: | 
					
						
							|  |  |  |           if ( request->wIndex == 7 ) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             // Get Microsoft OS 2.0 compatible descriptor
 | 
					
						
							|  |  |  |             uint16_t total_len; | 
					
						
							|  |  |  |             memcpy(&total_len, desc_ms_os_20+8, 2); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-17 16:26:27 +07:00
										 |  |  |             return tud_control_xfer(rhport, request, (void*)(uintptr_t) desc_ms_os_20, total_len); | 
					
						
							| 
									
										
										
										
											2021-03-10 11:31:50 +07:00
										 |  |  |           }else | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         default: break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case TUSB_REQ_TYPE_CLASS: | 
					
						
							|  |  |  |       if (request->bRequest == 0x22) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         // Webserial simulate the CDC_REQUEST_SET_CONTROL_LINE_STATE (0x22) to connect and disconnect.
 | 
					
						
							|  |  |  |         web_serial_connected = (request->wValue != 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Always lit LED if connected
 | 
					
						
							|  |  |  |         if ( web_serial_connected ) | 
					
						
							| 
									
										
										
										
											2021-02-10 22:14:29 -05:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2021-03-10 11:31:50 +07:00
										 |  |  |           board_led_write(true); | 
					
						
							|  |  |  |           blink_interval_ms = BLINK_ALWAYS_ON; | 
					
						
							| 
									
										
										
										
											2021-02-10 01:05:37 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-12 01:55:33 +07:00
										 |  |  |           tud_vendor_write_str("\r\nWebUSB interface connected\r\n"); | 
					
						
							| 
									
										
										
										
											2023-03-30 11:34:39 -05:00
										 |  |  |           tud_vendor_write_flush(); | 
					
						
							| 
									
										
										
										
											2021-02-10 22:14:29 -05:00
										 |  |  |         }else | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2021-03-10 11:31:50 +07:00
										 |  |  |           blink_interval_ms = BLINK_MOUNTED; | 
					
						
							| 
									
										
										
										
											2021-02-10 01:05:37 -05:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-02-10 22:14:29 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-10 11:31:50 +07:00
										 |  |  |         // response with status OK
 | 
					
						
							|  |  |  |         return tud_control_status(rhport, request); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     break; | 
					
						
							| 
									
										
										
										
											2021-02-10 01:05:37 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-10 11:31:50 +07:00
										 |  |  |     default: break; | 
					
						
							| 
									
										
										
										
											2019-07-26 11:36:30 +07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-07-30 00:34:25 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-10 01:05:37 -05:00
										 |  |  |   // stall unknown request
 | 
					
						
							|  |  |  |   return false; | 
					
						
							| 
									
										
										
										
											2019-07-26 11:36:30 +07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-25 16:52:20 +07:00
										 |  |  | void webserial_task(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-26 11:36:30 +07:00
										 |  |  |   if ( web_serial_connected ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     if ( tud_vendor_available() ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       uint8_t buf[64]; | 
					
						
							|  |  |  |       uint32_t count = tud_vendor_read(buf, sizeof(buf)); | 
					
						
							| 
									
										
										
										
											2019-07-11 23:12:53 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-26 11:36:30 +07:00
										 |  |  |       // echo back to both web serial and cdc
 | 
					
						
							|  |  |  |       echo_all(buf, count); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-07-25 16:52:20 +07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-07-11 23:12:53 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-26 11:36:30 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-12 19:38:04 +07:00
										 |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // USB CDC
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | void cdc_task(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if ( tud_cdc_connected() ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // connected and there are data available
 | 
					
						
							|  |  |  |     if ( tud_cdc_available() ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       uint8_t buf[64]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       uint32_t count = tud_cdc_read(buf, sizeof(buf)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-26 11:36:30 +07:00
										 |  |  |       // echo back to both web serial and cdc
 | 
					
						
							|  |  |  |       echo_all(buf, count); | 
					
						
							| 
									
										
										
										
											2019-07-12 19:38:04 +07:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Invoked when cdc when line state changed e.g connected/disconnected
 | 
					
						
							|  |  |  | void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   (void) itf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // connected
 | 
					
						
							|  |  |  |   if ( dtr && rts ) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // print initial message when connected
 | 
					
						
							| 
									
										
										
										
											2019-07-30 00:48:31 +07:00
										 |  |  |     tud_cdc_write_str("\r\nTinyUSB WebUSB device example\r\n"); | 
					
						
							| 
									
										
										
										
											2019-07-12 19:38:04 +07:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Invoked when CDC interface received data from host
 | 
					
						
							|  |  |  | void tud_cdc_rx_cb(uint8_t itf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   (void) itf; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-07-11 23:12:53 +07:00
										 |  |  | 
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | // BLINKING TASK
 | 
					
						
							|  |  |  | //--------------------------------------------------------------------+
 | 
					
						
							|  |  |  | void led_blinking_task(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   static uint32_t start_ms = 0; | 
					
						
							|  |  |  |   static bool led_state = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Blink every interval ms
 | 
					
						
							|  |  |  |   if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time
 | 
					
						
							|  |  |  |   start_ms += blink_interval_ms; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   board_led_write(led_state); | 
					
						
							|  |  |  |   led_state = 1 - led_state; // toggle
 | 
					
						
							|  |  |  | } |