#include "webusb_task.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include "bsp/board.h" #include "hardware.h" #include "hardware/irq.h" #include "hardware/uart.h" #include "i2c_peripheral.h" #include "pico/stdlib.h" #include "tusb.h" #include "uart_task.h" #include "usb_descriptors.h" #include "version.h" uint16_t webusb_status[CFG_TUD_VENDOR] = {0x0000}; bool webusb_status_changed[CFG_TUD_VENDOR] = {false}; uint16_t webusb_esp32_status = 0x0000; bool webusb_esp32_reset_requested = false; bool webusb_esp32_reset_mode = false; bool webusb_esp32_baudrate_override_requested = false; uint32_t webusb_esp32_baudrate_override_value = 0; bool webusb_esp32_mode_change_requested = false; uint8_t webusb_esp32_mode_change_target = 0; uint16_t webusb_fpga_status = 0x0000; bool webusb_fpga_baudrate_override_requested = false; uint32_t webusb_fpga_baudrate_override_value = 0; void webusb_task() { if (webusb_esp32_reset_requested) { esp32_reset(webusb_esp32_reset_mode); // Value controls the mode: 1 for download mode, 0 for normal mode webusb_esp32_reset_requested = false; } if (webusb_esp32_baudrate_override_requested) { // Set baudrate of ESP32 UART in WebUSB mode webusb_set_uart_baudrate(0, webusb_esp32_baudrate_override_value); webusb_esp32_baudrate_override_requested = false; } if (webusb_fpga_baudrate_override_requested) { // Set baudrate of FPGA UART in WebUSB mode webusb_set_uart_baudrate(1, webusb_fpga_baudrate_override_value); webusb_fpga_baudrate_override_requested = false; } if (webusb_esp32_mode_change_requested) { i2c_set_webusb_mode(webusb_esp32_mode_change_target); // Set ESP32 WebUSB mode webusb_esp32_mode_change_requested = false; } // Data transfer for (uint8_t idx = 0; idx < CFG_TUD_VENDOR; idx++) { int available = tud_vendor_n_available(idx); if (available > 0) { uint8_t buffer[256]; uint32_t length = tud_vendor_n_read(idx, buffer, sizeof(buffer)); if (idx == WEBUSB_IDX_ESP32) { uart_write_blocking(UART_ESP32, buffer, length); } else if (idx == WEBUSB_IDX_FPGA) { uart_write_blocking(UART_FPGA, buffer, length); } } } } #define WEBUSB_LANDING_PAGE_URL "mch2022.badge.team" tusb_desc_webusb_url_t desc_url = {.bLength = 3 + sizeof(WEBUSB_LANDING_PAGE_URL) - 1, .bDescriptorType = 3, // WEBUSB URL type .bScheme = 1, // 0: http, 1: https .url = WEBUSB_LANDING_PAGE_URL}; bool get_webusb_connected(uint8_t idx) { if (idx == WEBUSB_IDX_ESP32) return webusb_esp32_status & 0x0001; if (idx == WEBUSB_IDX_FPGA) return webusb_fpga_status & 0x0001; return false; } uint16_t get_webusb_status(uint8_t idx) { if (idx == WEBUSB_IDX_ESP32) return webusb_esp32_status; if (idx == WEBUSB_IDX_FPGA) return webusb_fpga_status; return 0x0000; } bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) { if (stage != CONTROL_STAGE_SETUP) return true; // nothing to with DATA & ACK stage 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 == 7) { // 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 == 0x22) { // Set status if (request->wIndex == ITF_NUM_VENDOR_0) { webusb_esp32_status = request->wValue; return tud_control_status(rhport, request); } else if (request->wIndex == ITF_NUM_VENDOR_1) { webusb_fpga_status = request->wValue; return tud_control_status(rhport, request); } } if (request->bRequest == 0x23) { // Reset ESP32 if (request->wIndex == ITF_NUM_VENDOR_0) { webusb_esp32_reset_requested = true; webusb_esp32_reset_mode = request->wValue; return tud_control_status(rhport, request); } } if (request->bRequest == 0x24) { // Set baudrate if (request->wIndex == ITF_NUM_VENDOR_0) { webusb_esp32_baudrate_override_requested = true; webusb_esp32_baudrate_override_value = (request->wValue) * 100; return tud_control_status(rhport, request); } else if (request->wIndex == ITF_NUM_VENDOR_1) { webusb_fpga_baudrate_override_requested = true; webusb_fpga_baudrate_override_value = (request->wValue) * 100; return tud_control_status(rhport, request); } } if (request->bRequest == 0x25) { // Set mode if (request->wIndex == ITF_NUM_VENDOR_0) { webusb_esp32_mode_change_requested = true; webusb_esp32_mode_change_target = request->wValue & 0xFF; return tud_control_status(rhport, request); } } if (request->bRequest == 0x26) { // Get mode if (request->wIndex == ITF_NUM_VENDOR_0) { return tud_control_xfer(rhport, request, (void*) &webusb_esp32_mode_change_target, 1); } } if (request->bRequest == 0x27) { // Get firmware version uint8_t version = FW_VERSION; return tud_control_xfer(rhport, request, (void*) &version, 1); } break; } default: break; } return false; // stall unknown request } bool tud_vendor_control_complete_cb(uint8_t rhport, tusb_control_request_t const* request) { (void) rhport; (void) request; return true; }