forked from espressif/arduino-esp32
Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
c45cff5f83 | |||
b1d072df9f | |||
929cf2c2d5 | |||
87853353db | |||
e265bd0d7c | |||
94809ce38b | |||
29455a0447 | |||
78499c459b | |||
ce680708ec | |||
90c01dab77 | |||
000d967db3 | |||
44dd99f5a5 | |||
b580bb23fd | |||
a7ea737f30 | |||
2af8cc3485 | |||
e5bd18d6aa | |||
a4118ea889 | |||
c4fcab28e4 | |||
0acbe781f5 | |||
0b0dfab3cf | |||
5fd737925f | |||
5bb8177aa1 | |||
be84c8219c | |||
31127f4260 | |||
4365a45401 | |||
023ae75b97 | |||
c5a1f3efd7 | |||
9406f8e464 | |||
65eafd16b5 | |||
d5a98f9a39 | |||
3780b5c924 | |||
1775dd1faa | |||
6972695d95 | |||
e0e5c88658 | |||
6e47e18a1b | |||
34125cee1d | |||
ee24736042 | |||
5458df0a54 | |||
e12d8c8ff1 |
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
16
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
This entire section can be deleted if all items are checked.
|
||||
|
||||
*By completing this PR sufficiently, you help us to improve the quality of Release Notes*
|
||||
|
||||
### Checklist
|
||||
|
||||
1. [ ] Please provide specific title of the PR describing the change, including the component name (eg."Update of Documentation link on Readme.md")
|
||||
2. [ ] Please provide related links (eg. Issue, other Project, submodule PR..)
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
## Summary
|
||||
Please describe your proposed PR and what it contains.
|
||||
|
||||
## Impact
|
||||
Please describe impact of your PR and it's function.
|
38
.github/workflows/docs.yml
vendored
Normal file
38
.github/workflows/docs.yml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
name: ReadTheDocs CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- release/*
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- '.github/workflows/docs.yml'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- '.github/workflows/docs.yml'
|
||||
|
||||
jobs:
|
||||
|
||||
build-docs:
|
||||
name: Build ReadTheDocs
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.x'
|
||||
- name: Build
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install python3-pip python3-setuptools
|
||||
# GitHub CI installs pip3 and setuptools outside the path.
|
||||
# Update the path to include them and run.
|
||||
PATH=/home/runner/.local/bin:$PATH pip3 install --user -r ./docs/requirements.txt
|
||||
cd ./docs && PATH=/home/runner/.local/bin:$PATH SPHINXOPTS="-W" make html
|
@ -34,6 +34,9 @@ set(CORE_SRCS
|
||||
cores/esp32/StreamString.cpp
|
||||
cores/esp32/USB.cpp
|
||||
cores/esp32/USBCDC.cpp
|
||||
cores/esp32/USBMSC.cpp
|
||||
cores/esp32/FirmwareMSC.cpp
|
||||
cores/esp32/firmware_msc_fat.c
|
||||
cores/esp32/wiring_pulse.c
|
||||
cores/esp32/wiring_shift.c
|
||||
cores/esp32/WMath.cpp
|
||||
@ -73,6 +76,14 @@ set(LIBRARY_SRCS
|
||||
libraries/Ticker/src/Ticker.cpp
|
||||
libraries/Update/src/Updater.cpp
|
||||
libraries/Update/src/HttpsOTAUpdate.cpp
|
||||
libraries/USB/src/USBHID.cpp
|
||||
libraries/USB/src/USBHIDMouse.cpp
|
||||
libraries/USB/src/USBHIDKeyboard.cpp
|
||||
libraries/USB/src/USBHIDGamepad.cpp
|
||||
libraries/USB/src/USBHIDConsumerControl.cpp
|
||||
libraries/USB/src/USBHIDSystemControl.cpp
|
||||
libraries/USB/src/USBHIDVendor.cpp
|
||||
libraries/USB/src/USBVendor.cpp
|
||||
libraries/WebServer/src/WebServer.cpp
|
||||
libraries/WebServer/src/Parsing.cpp
|
||||
libraries/WebServer/src/detail/mimetable.cpp
|
||||
@ -151,6 +162,7 @@ set(includedirs
|
||||
libraries/SPI/src
|
||||
libraries/Ticker/src
|
||||
libraries/Update/src
|
||||
libraries/USB/src
|
||||
libraries/WebServer/src
|
||||
libraries/WiFiClientSecure/src
|
||||
libraries/WiFi/src
|
||||
|
@ -25,7 +25,7 @@ Now you can install the latest 2.0.0 version from the boards manager.
|
||||
|
||||
Latest Stable Release [](https://github.com/espressif/arduino-esp32/releases/latest/) [](https://github.com/espressif/arduino-esp32/releases/latest/) [](https://github.com/espressif/arduino-esp32/releases/latest/)
|
||||
|
||||
Latest Development Release [](https://github.com/espressif/arduino-esp32/releases/latest/) [](https://github.com/espressif/arduino-esp32/releases/latest/) [](https://github.com/espressif/arduino-esp32/releases/latest/)
|
||||
Latest Development Release [](https://github.com/espressif/arduino-esp32/releases/) [](https://github.com/espressif/arduino-esp32/releases/) [](https://github.com/espressif/arduino-esp32/releases/)
|
||||
|
||||
### Documentation
|
||||
|
||||
|
941
boards.txt
941
boards.txt
File diff suppressed because it is too large
Load Diff
423
cores/esp32/FirmwareMSC.cpp
Normal file
423
cores/esp32/FirmwareMSC.cpp
Normal file
@ -0,0 +1,423 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "FirmwareMSC.h"
|
||||
|
||||
#if CONFIG_TINYUSB_MSC_ENABLED
|
||||
|
||||
#include <cstring>
|
||||
#include "esp_partition.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp32-hal.h"
|
||||
#include "pins_arduino.h"
|
||||
#include "firmware_msc_fat.h"
|
||||
|
||||
#ifndef USB_FW_MSC_VENDOR_ID
|
||||
#define USB_FW_MSC_VENDOR_ID "ESP32" //max 8 chars
|
||||
#endif
|
||||
#ifndef USB_FW_MSC_PRODUCT_ID
|
||||
#define USB_FW_MSC_PRODUCT_ID "Firmware MSC"//max 16 chars
|
||||
#endif
|
||||
#ifndef USB_FW_MSC_PRODUCT_REVISION
|
||||
#define USB_FW_MSC_PRODUCT_REVISION "1.0" //max 4 chars
|
||||
#endif
|
||||
#ifndef USB_FW_MSC_VOLUME_NAME
|
||||
#define USB_FW_MSC_VOLUME_NAME "ESP32-FWMSC" //max 11 chars
|
||||
#endif
|
||||
#ifndef USB_FW_MSC_SERIAL_NUMBER
|
||||
#define USB_FW_MSC_SERIAL_NUMBER 0x00000000
|
||||
#endif
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(ARDUINO_FIRMWARE_MSC_EVENTS);
|
||||
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait);
|
||||
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg);
|
||||
|
||||
//General Variables
|
||||
static uint8_t * msc_ram_disk = NULL;
|
||||
static fat_boot_sector_t * msc_boot = NULL;
|
||||
static uint8_t * msc_table = NULL;
|
||||
static uint16_t msc_table_sectors = 0;
|
||||
static uint16_t msc_total_sectors = 0;
|
||||
static bool mcs_is_fat16 = false;
|
||||
|
||||
//Firmware Read
|
||||
static const esp_partition_t* msc_run_partition = NULL;
|
||||
static uint16_t fw_start_sector = 0;
|
||||
static uint16_t fw_end_sector = 0;
|
||||
static size_t fw_size = 0;
|
||||
static fat_dir_entry_t * fw_entry = NULL;
|
||||
|
||||
//Firmware Write
|
||||
typedef enum {
|
||||
MSC_UPDATE_IDLE,
|
||||
MSC_UPDATE_STARTING,
|
||||
MSC_UPDATE_RUNNING,
|
||||
MSC_UPDATE_END
|
||||
} msc_update_state_t;
|
||||
|
||||
static const esp_partition_t* msc_ota_partition = NULL;
|
||||
static msc_update_state_t msc_update_state = MSC_UPDATE_IDLE;
|
||||
static uint16_t msc_update_start_sector = 0;
|
||||
static uint32_t msc_update_bytes_written = 0;
|
||||
static fat_dir_entry_t * msc_update_entry = NULL;
|
||||
|
||||
static uint32_t get_firmware_size(const esp_partition_t* partition){
|
||||
esp_image_metadata_t data;
|
||||
const esp_partition_pos_t running_pos = {
|
||||
.offset = partition->address,
|
||||
.size = partition->size,
|
||||
};
|
||||
data.start_addr = running_pos.offset;
|
||||
esp_image_verify(ESP_IMAGE_VERIFY, &running_pos, &data);
|
||||
return data.image_len;
|
||||
}
|
||||
|
||||
//Get number of sectors required based on the size of the firmware and OTA partition
|
||||
static size_t msc_update_get_required_disk_sectors(){
|
||||
size_t data_sectors = 16;
|
||||
size_t total_sectors = 0;
|
||||
msc_run_partition = esp_ota_get_running_partition();
|
||||
msc_ota_partition = esp_ota_get_next_update_partition(NULL);
|
||||
if(msc_run_partition){
|
||||
fw_size = get_firmware_size(msc_run_partition);
|
||||
data_sectors += FAT_SIZE_TO_SECTORS(fw_size);
|
||||
log_d("APP size: %u (%u sectors)", fw_size, FAT_SIZE_TO_SECTORS(fw_size));
|
||||
} else {
|
||||
log_w("APP partition not found. Reading disabled");
|
||||
}
|
||||
if(msc_ota_partition){
|
||||
data_sectors += FAT_SIZE_TO_SECTORS(msc_ota_partition->size);
|
||||
log_d("OTA size: %u (%u sectors)", msc_ota_partition->size, FAT_SIZE_TO_SECTORS(msc_ota_partition->size));
|
||||
} else {
|
||||
log_w("OTA partition not found. Writing disabled");
|
||||
}
|
||||
msc_table_sectors = fat_sectors_per_alloc_table(data_sectors, false);
|
||||
total_sectors = data_sectors + msc_table_sectors + 2;
|
||||
if(total_sectors > 0xFF4){
|
||||
log_d("USING FAT16");
|
||||
mcs_is_fat16 = true;
|
||||
total_sectors -= msc_table_sectors;
|
||||
msc_table_sectors = fat_sectors_per_alloc_table(data_sectors, true);
|
||||
total_sectors += msc_table_sectors;
|
||||
} else {
|
||||
log_d("USING FAT12");
|
||||
mcs_is_fat16 = false;
|
||||
}
|
||||
log_d("FAT data sectors: %u", data_sectors);
|
||||
log_d("FAT table sectors: %u", msc_table_sectors);
|
||||
log_d("FAT total sectors: %u (%uKB)", total_sectors, (total_sectors * DISK_SECTOR_SIZE) / 1024);
|
||||
return total_sectors;
|
||||
}
|
||||
|
||||
//setup the ramdisk and add the firmware download file
|
||||
static bool msc_update_setup_disk(const char * volume_label, uint32_t serial_number){
|
||||
msc_total_sectors = msc_update_get_required_disk_sectors();
|
||||
uint8_t ram_sectors = msc_table_sectors + 2;
|
||||
msc_ram_disk = (uint8_t*)calloc(ram_sectors, DISK_SECTOR_SIZE);
|
||||
if(!msc_ram_disk){
|
||||
log_e("Failed to allocate RAM Disk: %u bytes", ram_sectors * DISK_SECTOR_SIZE);
|
||||
return false;
|
||||
}
|
||||
fw_start_sector = ram_sectors;
|
||||
fw_end_sector = fw_start_sector;
|
||||
msc_boot = fat_add_boot_sector(msc_ram_disk, msc_total_sectors, msc_table_sectors, fat_file_system_type(mcs_is_fat16), volume_label, serial_number);
|
||||
msc_table = fat_add_table(msc_ram_disk, msc_boot, mcs_is_fat16);
|
||||
//fat_dir_entry_t * label = fat_add_label(msc_ram_disk, volume_label);
|
||||
if(msc_run_partition){
|
||||
fw_entry = fat_add_root_file(msc_ram_disk, 0, "FIRMWARE", "BIN", fw_size, 2, mcs_is_fat16);
|
||||
fw_end_sector = FAT_SIZE_TO_SECTORS(fw_size) + fw_start_sector;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void msc_update_delete_disk(){
|
||||
fw_entry = NULL;
|
||||
fw_size = 0;
|
||||
fw_end_sector = 0;
|
||||
fw_start_sector = 0;
|
||||
msc_table = NULL;
|
||||
msc_boot = NULL;
|
||||
msc_table_sectors = 0;
|
||||
msc_total_sectors = 0;
|
||||
msc_run_partition = NULL;
|
||||
msc_ota_partition = NULL;
|
||||
msc_update_state = MSC_UPDATE_IDLE;
|
||||
msc_update_start_sector = 0;
|
||||
msc_update_bytes_written = 0;
|
||||
msc_update_entry = NULL;
|
||||
free(msc_ram_disk);
|
||||
msc_ram_disk = NULL;
|
||||
}
|
||||
|
||||
//filter out entries to only include BINs in the root folder
|
||||
static fat_dir_entry_t * msc_update_get_root_bin_entry(uint8_t index){
|
||||
fat_dir_entry_t * entry = (fat_dir_entry_t *)(msc_ram_disk + ((msc_boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE) + (index * sizeof(fat_dir_entry_t)));
|
||||
fat_lfn_entry_t * lfn = (fat_lfn_entry_t*)entry;
|
||||
|
||||
//empty entry
|
||||
if(entry->file_magic == 0){
|
||||
return NULL;
|
||||
}
|
||||
//long file name
|
||||
if(lfn->attr == 0x0F && lfn->type == 0x00 && lfn->first_cluster == 0x0000){
|
||||
return NULL;
|
||||
}
|
||||
//only files marked as archives
|
||||
if(entry->file_attr != FAT_FILE_ATTR_ARCHIVE){
|
||||
return NULL;
|
||||
}
|
||||
//deleted
|
||||
if(entry->file_magic == 0xE5 || entry->file_magic == 0x05){
|
||||
return NULL;
|
||||
}
|
||||
//not bins
|
||||
if(memcmp("BIN", entry->file_extension, 3)){
|
||||
return NULL;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
//get an empty bin (the host will add an entry for file about to be written with size of zero)
|
||||
static fat_dir_entry_t * msc_update_find_new_bin(){
|
||||
for(uint8_t i=16; i;){
|
||||
i--;
|
||||
fat_dir_entry_t * entry = msc_update_get_root_bin_entry(i);
|
||||
if(entry && entry->file_size == 0){
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//get a bin starting from particular sector
|
||||
static fat_dir_entry_t * msc_update_find_bin(uint16_t sector){
|
||||
for(uint8_t i=16; i; ){
|
||||
i--;
|
||||
fat_dir_entry_t * entry = msc_update_get_root_bin_entry(i);
|
||||
if(entry && entry->data_start_sector == (sector - msc_boot->sectors_per_alloc_table)){
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//write the new data and erase the flash blocks when necessary
|
||||
static esp_err_t msc_update_write(const esp_partition_t *partition, uint32_t offset, void *data, size_t size){
|
||||
esp_err_t err = ESP_OK;
|
||||
if((offset & (SPI_FLASH_SEC_SIZE-1)) == 0){
|
||||
err = esp_partition_erase_range(partition, offset, SPI_FLASH_SEC_SIZE);
|
||||
log_v("ERASE[0x%08X]: %s", offset, (err != ESP_OK)?"FAIL":"OK");
|
||||
if(err != ESP_OK){
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return esp_partition_write(partition, offset, data, size);
|
||||
}
|
||||
|
||||
//called when error was encountered while updating
|
||||
static void msc_update_error(){
|
||||
log_e("UPDATE_ERROR: %u", msc_update_bytes_written);
|
||||
arduino_firmware_msc_event_data_t p = {0};
|
||||
p.error.size = msc_update_bytes_written;
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_ERROR_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
msc_update_state = MSC_UPDATE_IDLE;
|
||||
msc_update_entry = NULL;
|
||||
msc_update_bytes_written = 0;
|
||||
msc_update_start_sector = 0;
|
||||
}
|
||||
|
||||
//called when all firmware bytes have been received
|
||||
static void msc_update_end(){
|
||||
log_d("UPDATE_END: %u", msc_update_entry->file_size);
|
||||
msc_update_state = MSC_UPDATE_END;
|
||||
size_t ota_size = get_firmware_size(msc_ota_partition);
|
||||
if(ota_size != msc_update_entry->file_size){
|
||||
log_e("OTA SIZE MISMATCH %u != %u", ota_size, msc_update_entry->file_size);
|
||||
msc_update_error();
|
||||
return;
|
||||
}
|
||||
if(!ota_size || esp_ota_set_boot_partition(msc_ota_partition) != ESP_OK){
|
||||
log_e("ENABLING OTA PARTITION FAILED");
|
||||
msc_update_error();
|
||||
return;
|
||||
}
|
||||
arduino_firmware_msc_event_data_t p = {0};
|
||||
p.end.size = msc_update_entry->file_size;
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_END_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
static int32_t msc_write(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){
|
||||
//log_d("lba: %u, offset: %u, bufsize: %u", lba, offset, bufsize);
|
||||
if(lba < fw_start_sector){
|
||||
//write to sectors that are in RAM
|
||||
memcpy(msc_ram_disk + (lba * DISK_SECTOR_SIZE) + offset, buffer, bufsize);
|
||||
if(msc_ota_partition && lba == (fw_start_sector - 1)){
|
||||
//monitor the root folder table
|
||||
if(msc_update_state <= MSC_UPDATE_RUNNING){
|
||||
fat_dir_entry_t * update_entry = msc_update_find_new_bin();
|
||||
if(update_entry) {
|
||||
if(msc_update_entry) {
|
||||
log_v("REPLACING ENTRY");
|
||||
} else {
|
||||
log_v("ASSIGNING ENTRY");
|
||||
}
|
||||
if(msc_update_state <= MSC_UPDATE_STARTING){
|
||||
msc_update_state = MSC_UPDATE_STARTING;
|
||||
msc_update_bytes_written = 0;
|
||||
msc_update_start_sector = 0;
|
||||
}
|
||||
msc_update_entry = update_entry;
|
||||
} else if(msc_update_state == MSC_UPDATE_RUNNING){
|
||||
if(!msc_update_entry && msc_update_start_sector){
|
||||
msc_update_entry = msc_update_find_bin(msc_update_start_sector);
|
||||
}
|
||||
if(msc_update_entry && msc_update_bytes_written >= msc_update_entry->file_size){
|
||||
msc_update_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(msc_ota_partition && lba >= msc_update_start_sector){
|
||||
//handle writes to the region where the new firmware will be uploaded
|
||||
arduino_firmware_msc_event_data_t p = {0};
|
||||
if(msc_update_state <= MSC_UPDATE_STARTING && buffer[0] == 0xE9){
|
||||
msc_update_state = MSC_UPDATE_RUNNING;
|
||||
msc_update_start_sector = lba;
|
||||
msc_update_bytes_written = 0;
|
||||
log_d("UPDATE_START: %u (0x%02X)", lba, lba - msc_boot->sectors_per_alloc_table);
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_START_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
if(msc_update_write(msc_ota_partition, ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) == ESP_OK){
|
||||
log_v("UPDATE_WRITE: %u %u", ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, bufsize);
|
||||
msc_update_bytes_written = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset + bufsize;
|
||||
p.write.offset = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset;
|
||||
p.write.size = bufsize;
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_WRITE_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
} else {
|
||||
msc_update_error();
|
||||
return 0;
|
||||
}
|
||||
} else if(msc_update_state == MSC_UPDATE_RUNNING){
|
||||
if(msc_update_entry && msc_update_entry->file_size && msc_update_bytes_written < msc_update_entry->file_size && (msc_update_bytes_written + bufsize) >= msc_update_entry->file_size){
|
||||
bufsize = msc_update_entry->file_size - msc_update_bytes_written;
|
||||
}
|
||||
if(msc_update_write(msc_ota_partition, ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) == ESP_OK){
|
||||
log_v("UPDATE_WRITE: %u %u", ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset, bufsize);
|
||||
msc_update_bytes_written = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset + bufsize;
|
||||
p.write.offset = ((lba - msc_update_start_sector) * DISK_SECTOR_SIZE) + offset;
|
||||
p.write.size = bufsize;
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_WRITE_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
if(msc_update_entry && msc_update_entry->file_size && msc_update_bytes_written >= msc_update_entry->file_size){
|
||||
msc_update_end();
|
||||
}
|
||||
} else {
|
||||
msc_update_error();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
static int32_t msc_read(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){
|
||||
//log_d("lba: %u, offset: %u, bufsize: %u", lba, offset, bufsize);
|
||||
if(lba < fw_start_sector){
|
||||
memcpy(buffer, msc_ram_disk + (lba * DISK_SECTOR_SIZE) + offset, bufsize);
|
||||
} else if(msc_run_partition && lba < fw_end_sector){
|
||||
//read the currently running firmware
|
||||
if(esp_partition_read(msc_run_partition, ((lba - fw_start_sector) * DISK_SECTOR_SIZE) + offset, buffer, bufsize) != ESP_OK){
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
memset(buffer, 0, bufsize);
|
||||
}
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
static bool msc_start_stop(uint8_t power_condition, bool start, bool load_eject){
|
||||
//log_d("power: %u, start: %u, eject: %u", power_condition, start, load_eject);
|
||||
arduino_firmware_msc_event_data_t p = {0};
|
||||
p.power.power_condition = power_condition;
|
||||
p.power.start = start;
|
||||
p.power.load_eject = load_eject;
|
||||
arduino_usb_event_post(ARDUINO_FIRMWARE_MSC_EVENTS, ARDUINO_FIRMWARE_MSC_POWER_EVENT, &p, sizeof(arduino_firmware_msc_event_data_t), portMAX_DELAY);
|
||||
return true;
|
||||
}
|
||||
|
||||
static volatile TaskHandle_t msc_task_handle = NULL;
|
||||
static void msc_task(void *pvParameters){
|
||||
for (;;) {
|
||||
if(msc_update_state == MSC_UPDATE_END){
|
||||
delay(100);
|
||||
esp_restart();
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
msc_task_handle = NULL;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
FirmwareMSC::FirmwareMSC():msc(){}
|
||||
|
||||
FirmwareMSC::~FirmwareMSC(){
|
||||
end();
|
||||
}
|
||||
|
||||
bool FirmwareMSC::begin(){
|
||||
if(msc_ram_disk){
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!msc_update_setup_disk(USB_FW_MSC_VOLUME_NAME, USB_FW_MSC_SERIAL_NUMBER)){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!msc_task_handle){
|
||||
xTaskCreateUniversal(msc_task, "msc_disk", 1024, NULL, 2, (TaskHandle_t*)&msc_task_handle, 0);
|
||||
if(!msc_task_handle){
|
||||
msc_update_delete_disk();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
msc.vendorID(USB_FW_MSC_VENDOR_ID);
|
||||
msc.productID(USB_FW_MSC_PRODUCT_ID);
|
||||
msc.productRevision(USB_FW_MSC_PRODUCT_REVISION);
|
||||
msc.onStartStop(msc_start_stop);
|
||||
msc.onRead(msc_read);
|
||||
msc.onWrite(msc_write);
|
||||
msc.mediaPresent(true);
|
||||
msc.begin(msc_boot->fat12_sector_num, DISK_SECTOR_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FirmwareMSC::end(){
|
||||
msc.end();
|
||||
if(msc_task_handle){
|
||||
vTaskDelete(msc_task_handle);
|
||||
msc_task_handle = NULL;
|
||||
}
|
||||
msc_update_delete_disk();
|
||||
}
|
||||
|
||||
void FirmwareMSC::onEvent(esp_event_handler_t callback){
|
||||
onEvent(ARDUINO_FIRMWARE_MSC_ANY_EVENT, callback);
|
||||
}
|
||||
void FirmwareMSC::onEvent(arduino_firmware_msc_event_t event, esp_event_handler_t callback){
|
||||
arduino_usb_event_handler_register_with(ARDUINO_FIRMWARE_MSC_EVENTS, event, callback, this);
|
||||
}
|
||||
|
||||
#if ARDUINO_USB_MSC_ON_BOOT
|
||||
FirmwareMSC MSC_Update;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_USB_MSC_ENABLED */
|
70
cores/esp32/FirmwareMSC.h
Normal file
70
cores/esp32/FirmwareMSC.h
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include <stdbool.h>
|
||||
#include "USBMSC.h"
|
||||
|
||||
#if CONFIG_TINYUSB_MSC_ENABLED
|
||||
|
||||
#include "esp_event.h"
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_FIRMWARE_MSC_EVENTS);
|
||||
|
||||
typedef enum {
|
||||
ARDUINO_FIRMWARE_MSC_ANY_EVENT = ESP_EVENT_ANY_ID,
|
||||
ARDUINO_FIRMWARE_MSC_START_EVENT = 0,
|
||||
ARDUINO_FIRMWARE_MSC_WRITE_EVENT,
|
||||
ARDUINO_FIRMWARE_MSC_END_EVENT,
|
||||
ARDUINO_FIRMWARE_MSC_ERROR_EVENT,
|
||||
ARDUINO_FIRMWARE_MSC_POWER_EVENT,
|
||||
ARDUINO_FIRMWARE_MSC_MAX_EVENT,
|
||||
} arduino_firmware_msc_event_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
size_t offset;
|
||||
size_t size;
|
||||
} write;
|
||||
struct {
|
||||
uint8_t power_condition;
|
||||
bool start;
|
||||
bool load_eject;
|
||||
} power;
|
||||
struct {
|
||||
size_t size;
|
||||
} end;
|
||||
struct {
|
||||
size_t size;
|
||||
} error;
|
||||
} arduino_firmware_msc_event_data_t;
|
||||
|
||||
class FirmwareMSC {
|
||||
private:
|
||||
USBMSC msc;
|
||||
|
||||
public:
|
||||
FirmwareMSC();
|
||||
~FirmwareMSC();
|
||||
bool begin();
|
||||
void end();
|
||||
void onEvent(esp_event_handler_t callback);
|
||||
void onEvent(arduino_firmware_msc_event_t event, esp_event_handler_t callback);
|
||||
};
|
||||
|
||||
#if ARDUINO_USB_MSC_ON_BOOT
|
||||
extern FirmwareMSC MSC_Update;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_TINYUSB_MSC_ENABLED */
|
@ -5,87 +5,137 @@
|
||||
|
||||
#include "pins_arduino.h"
|
||||
#include "HardwareSerial.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
#ifndef SOC_RX0
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define SOC_RX0 3
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define SOC_RX0 44
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define SOC_RX0 20
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SOC_TX0
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define SOC_TX0 1
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define SOC_TX0 43
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define SOC_TX0 21
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void serialEvent(void) __attribute__((weak));
|
||||
void serialEvent(void) {}
|
||||
|
||||
#if SOC_UART_NUM > 1
|
||||
|
||||
#ifndef RX1
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define RX1 9
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define RX1 18
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define RX1 18
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TX1
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define TX1 10
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define TX1 17
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define TX1 19
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void serialEvent1(void) __attribute__((weak));
|
||||
void serialEvent1(void) {}
|
||||
#endif /* SOC_UART_NUM > 1 */
|
||||
|
||||
#if SOC_UART_NUM > 2
|
||||
#ifndef RX2
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define RX2 16
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef TX2
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define TX2 17
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifndef RX1
|
||||
#define RX1 18
|
||||
#endif
|
||||
|
||||
#ifndef TX1
|
||||
#define TX1 17
|
||||
#endif
|
||||
|
||||
#endif
|
||||
void serialEvent2(void) __attribute__((weak));
|
||||
void serialEvent2(void) {}
|
||||
#endif /* SOC_UART_NUM > 2 */
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
|
||||
HardwareSerial Serial0(0);
|
||||
#else
|
||||
HardwareSerial Serial(0);
|
||||
#endif
|
||||
#if SOC_UART_NUM > 1
|
||||
HardwareSerial Serial1(1);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#endif
|
||||
#if SOC_UART_NUM > 2
|
||||
HardwareSerial Serial2(2);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void serialEventRun(void)
|
||||
{
|
||||
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
|
||||
if(Serial0.available()) serialEvent();
|
||||
#else
|
||||
if(Serial.available()) serialEvent();
|
||||
#endif
|
||||
#if SOC_UART_NUM > 1
|
||||
if(Serial1.available()) serialEvent1();
|
||||
#endif
|
||||
#if SOC_UART_NUM > 2
|
||||
if(Serial2.available()) serialEvent2();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL) {}
|
||||
|
||||
void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd)
|
||||
{
|
||||
if(0 > _uart_nr || _uart_nr > 2) {
|
||||
log_e("Serial number is invalid, please use 0, 1 or 2");
|
||||
if(0 > _uart_nr || _uart_nr >= SOC_UART_NUM) {
|
||||
log_e("Serial number is invalid, please use numers from 0 to %u", SOC_UART_NUM - 1);
|
||||
return;
|
||||
}
|
||||
if(_uart) {
|
||||
end();
|
||||
// in this case it is a begin() over a previous begin() - maybe to change baud rate
|
||||
// thus do not disable debug output
|
||||
end(false);
|
||||
}
|
||||
if(_uart_nr == 0 && rxPin < 0 && txPin < 0) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
rxPin = 3;
|
||||
txPin = 1;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
rxPin = 44;
|
||||
txPin = 43;
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
rxPin = 20;
|
||||
txPin = 21;
|
||||
#endif
|
||||
rxPin = SOC_RX0;
|
||||
txPin = SOC_TX0;
|
||||
}
|
||||
#if SOC_UART_NUM > 1
|
||||
if(_uart_nr == 1 && rxPin < 0 && txPin < 0) {
|
||||
rxPin = RX1;
|
||||
txPin = TX1;
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#endif
|
||||
#if SOC_UART_NUM > 2
|
||||
if(_uart_nr == 2 && rxPin < 0 && txPin < 0) {
|
||||
rxPin = RX2;
|
||||
txPin = TX2;
|
||||
}
|
||||
#endif
|
||||
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, 256, invert, rxfifo_full_thrhd);
|
||||
_tx_pin = txPin;
|
||||
_rx_pin = rxPin;
|
||||
|
||||
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, 256, invert, rxfifo_full_thrhd);
|
||||
if (!baud) {
|
||||
// using baud rate as zero, forces it to try to detect the current baud rate in place
|
||||
uartStartDetectBaudrate(_uart);
|
||||
time_t startMillis = millis();
|
||||
unsigned long detectedBaudRate = 0;
|
||||
@ -93,7 +143,7 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
|
||||
yield();
|
||||
}
|
||||
|
||||
end();
|
||||
end(false);
|
||||
|
||||
if(detectedBaudRate) {
|
||||
delay(100); // Give some time...
|
||||
@ -101,8 +151,6 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
|
||||
} else {
|
||||
log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible");
|
||||
_uart = NULL;
|
||||
_tx_pin = 255;
|
||||
_rx_pin = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -112,21 +160,16 @@ void HardwareSerial::updateBaudRate(unsigned long baud)
|
||||
uartSetBaudRate(_uart, baud);
|
||||
}
|
||||
|
||||
void HardwareSerial::end()
|
||||
void HardwareSerial::end(bool turnOffDebug)
|
||||
{
|
||||
if(uartGetDebug() == _uart_nr) {
|
||||
if(turnOffDebug && uartGetDebug() == _uart_nr) {
|
||||
uartSetDebug(0);
|
||||
}
|
||||
delay(10);
|
||||
log_v("pins %d %d",_tx_pin, _rx_pin);
|
||||
uartEnd(_uart, _tx_pin, _rx_pin);
|
||||
uartEnd(_uart);
|
||||
_uart = 0;
|
||||
}
|
||||
|
||||
size_t HardwareSerial::setRxBufferSize(size_t new_size) {
|
||||
return uartResizeRxBuffer(_uart, new_size);
|
||||
}
|
||||
|
||||
void HardwareSerial::setDebugOutput(bool en)
|
||||
{
|
||||
if(_uart == 0) {
|
||||
@ -212,10 +255,16 @@ uint32_t HardwareSerial::baudRate()
|
||||
}
|
||||
HardwareSerial::operator bool() const
|
||||
{
|
||||
return true;
|
||||
return uartIsDriverInstalled(_uart);
|
||||
}
|
||||
|
||||
void HardwareSerial::setRxInvert(bool invert)
|
||||
{
|
||||
uartSetRxInvert(_uart, invert);
|
||||
}
|
||||
|
||||
void HardwareSerial::setPins(uint8_t rxPin, uint8_t txPin)
|
||||
{
|
||||
uartSetPins(_uart, rxPin, txPin);
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@
|
||||
|
||||
#include "Stream.h"
|
||||
#include "esp32-hal.h"
|
||||
#include "soc/soc_caps.h"
|
||||
|
||||
class HardwareSerial: public Stream
|
||||
{
|
||||
@ -56,7 +57,7 @@ public:
|
||||
HardwareSerial(int uart_nr);
|
||||
|
||||
void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 112);
|
||||
void end();
|
||||
void end(bool turnOffDebug = true);
|
||||
void updateBaudRate(unsigned long baud);
|
||||
int available(void);
|
||||
int availableForWrite(void);
|
||||
@ -98,33 +99,33 @@ public:
|
||||
uint32_t baudRate();
|
||||
operator bool() const;
|
||||
|
||||
size_t setRxBufferSize(size_t);
|
||||
void setDebugOutput(bool);
|
||||
|
||||
void setRxInvert(bool);
|
||||
void setPins(uint8_t rxPin, uint8_t txPin);
|
||||
|
||||
protected:
|
||||
int _uart_nr;
|
||||
uart_t* _uart;
|
||||
uint8_t _tx_pin;
|
||||
uint8_t _rx_pin;
|
||||
};
|
||||
|
||||
extern void serialEventRun(void) __attribute__((weak));
|
||||
|
||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
|
||||
#ifndef ARDUINO_SERIAL_PORT
|
||||
#define ARDUINO_SERIAL_PORT 0
|
||||
#ifndef ARDUINO_USB_CDC_ON_BOOT
|
||||
#define ARDUINO_USB_CDC_ON_BOOT 0
|
||||
#endif
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
|
||||
#include "USB.h"
|
||||
#include "USBCDC.h"
|
||||
extern HardwareSerial Serial0;
|
||||
#else
|
||||
extern HardwareSerial Serial;
|
||||
#endif
|
||||
#if SOC_UART_NUM > 1
|
||||
extern HardwareSerial Serial1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#endif
|
||||
#if SOC_UART_NUM > 2
|
||||
extern HardwareSerial Serial2;
|
||||
#endif
|
||||
#endif
|
||||
|
@ -11,10 +11,13 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "USB.h"
|
||||
|
||||
#if CONFIG_TINYUSB_ENABLED
|
||||
|
||||
#include "esp32-hal.h"
|
||||
#include "esp32-hal-tinyusb.h"
|
||||
#include "USB.h"
|
||||
#if CONFIG_TINYUSB_ENABLED
|
||||
#include "common/tusb_common.h"
|
||||
|
||||
#ifndef USB_VID
|
||||
#define USB_VID USB_ESPRESSIF_VID
|
||||
@ -31,14 +34,16 @@
|
||||
#ifndef USB_SERIAL
|
||||
#define USB_SERIAL "0"
|
||||
#endif
|
||||
#ifndef USB_WEBUSB_ENABLED
|
||||
#define USB_WEBUSB_ENABLED false
|
||||
#endif
|
||||
#ifndef USB_WEBUSB_URL
|
||||
#define USB_WEBUSB_URL "https://espressif.github.io/arduino-esp32/webusb.html"
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_DFU_RUNTIME
|
||||
static uint16_t load_dfu_descriptor(uint8_t * dst, uint8_t * itf)
|
||||
{
|
||||
#define DFU_ATTR_CAN_DOWNLOAD 1
|
||||
#define DFU_ATTR_CAN_UPLOAD 2
|
||||
#define DFU_ATTR_MANIFESTATION_TOLERANT 4
|
||||
#define DFU_ATTR_WILL_DETACH 8
|
||||
#define DFU_ATTRS (DFU_ATTR_CAN_DOWNLOAD | DFU_ATTR_CAN_UPLOAD | DFU_ATTR_MANIFESTATION_TOLERANT)
|
||||
|
||||
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB DFU_RT");
|
||||
@ -120,8 +125,8 @@ ESPUSB::ESPUSB(size_t task_stack_size, uint8_t event_task_priority)
|
||||
,usb_protocol(MISC_PROTOCOL_IAD)
|
||||
,usb_attributes(TUSB_DESC_CONFIG_ATT_SELF_POWERED)
|
||||
,usb_power_ma(500)
|
||||
,webusb_enabled(false)
|
||||
,webusb_url("https://espressif.github.io/arduino-esp32/webusb.html")
|
||||
,webusb_enabled(USB_WEBUSB_ENABLED)
|
||||
,webusb_url(USB_WEBUSB_URL)
|
||||
,_started(false)
|
||||
,_task_stack_size(task_stack_size)
|
||||
,_event_task_priority(event_task_priority)
|
||||
|
@ -14,12 +14,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_TINYUSB_ENABLED
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "esp_event.h"
|
||||
#include "USBCDC.h"
|
||||
|
||||
#include "esp_event.h"
|
||||
#define ARDUINO_USB_ON_BOOT (ARDUINO_USB_CDC_ON_BOOT|ARDUINO_USB_MSC_ON_BOOT|ARDUINO_USB_DFU_ON_BOOT)
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_EVENTS);
|
||||
|
||||
|
@ -11,24 +11,22 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "esp32-hal.h"
|
||||
#include "esp32-hal-tinyusb.h"
|
||||
#include "USB.h"
|
||||
#if CONFIG_TINYUSB_CDC_ENABLED
|
||||
|
||||
#include "USBCDC.h"
|
||||
#if CONFIG_TINYUSB_ENABLED
|
||||
#include "esp32-hal-tinyusb.h"
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(ARDUINO_USB_CDC_EVENTS);
|
||||
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait);
|
||||
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg);
|
||||
|
||||
#if CFG_TUD_CDC
|
||||
#define MAX_USB_CDC_DEVICES 2
|
||||
USBCDC * devices[MAX_USB_CDC_DEVICES] = {NULL, NULL};
|
||||
|
||||
static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf)
|
||||
{
|
||||
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB CDC");
|
||||
// Interface number, string index, attributes, detach timeout, transfer size */
|
||||
uint8_t descriptor[TUD_CDC_DESC_LEN] = {
|
||||
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
|
||||
TUD_CDC_DESCRIPTOR(*itf, str_index, 0x85, 64, 0x03, 0x84, 64)
|
||||
@ -41,7 +39,6 @@ static uint16_t load_cdc_descriptor(uint8_t * dst, uint8_t * itf)
|
||||
// Invoked when line state DTR & RTS are changed via SET_CONTROL_LINE_STATE
|
||||
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
|
||||
{
|
||||
//isr_log_v("itf: %u, dtr: %u, rts: %u", itf, dtr, rts);
|
||||
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
|
||||
devices[itf]->_onLineState(dtr, rts);
|
||||
}
|
||||
@ -50,7 +47,6 @@ void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
|
||||
// Invoked when line coding is change via SET_LINE_CODING
|
||||
void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding)
|
||||
{
|
||||
//isr_log_v("itf: %u, bit_rate: %u, data_bits: %u, stop_bits: %u, parity: %u", itf, p_line_coding->bit_rate, p_line_coding->data_bits, p_line_coding->stop_bits, p_line_coding->parity);
|
||||
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
|
||||
devices[itf]->_onLineCoding(p_line_coding->bit_rate, p_line_coding->stop_bits, p_line_coding->parity, p_line_coding->data_bits);
|
||||
}
|
||||
@ -59,7 +55,6 @@ void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding)
|
||||
// Invoked when received new data
|
||||
void tud_cdc_rx_cb(uint8_t itf)
|
||||
{
|
||||
//isr_log_v("itf: %u", itf);
|
||||
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
|
||||
devices[itf]->_onRX();
|
||||
}
|
||||
@ -72,15 +67,14 @@ void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms){
|
||||
|
||||
// Invoked when space becomes available in TX buffer
|
||||
void tud_cdc_tx_complete_cb(uint8_t itf){
|
||||
//isr_log_v("itf: %u", itf);
|
||||
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL){
|
||||
if(itf < MAX_USB_CDC_DEVICES && devices[itf] != NULL && devices[itf]->tx_sem != NULL){
|
||||
xSemaphoreGive(devices[itf]->tx_sem);
|
||||
devices[itf]->_onTX();
|
||||
}
|
||||
}
|
||||
|
||||
static size_t tinyusb_cdc_write(uint8_t itf, const uint8_t *buffer, size_t size){
|
||||
if(itf >= MAX_USB_CDC_DEVICES){
|
||||
if(itf >= MAX_USB_CDC_DEVICES || devices[itf] == NULL || devices[itf]->tx_sem == NULL){
|
||||
return 0;
|
||||
}
|
||||
if(!tud_cdc_n_connected(itf)){
|
||||
@ -90,8 +84,15 @@ static size_t tinyusb_cdc_write(uint8_t itf, const uint8_t *buffer, size_t size)
|
||||
while(tosend){
|
||||
uint32_t space = tud_cdc_n_write_available(itf);
|
||||
if(!space){
|
||||
delay(1);
|
||||
continue;
|
||||
//make sure that we do not get previous semaphore
|
||||
xSemaphoreTake(devices[itf]->tx_sem, 0);
|
||||
//wait for tx_complete
|
||||
if(xSemaphoreTake(devices[itf]->tx_sem, 200 / portTICK_PERIOD_MS) == pdTRUE){
|
||||
space = tud_cdc_n_write_available(itf);
|
||||
}
|
||||
if(!space){
|
||||
return sofar;
|
||||
}
|
||||
}
|
||||
if(tosend < space){
|
||||
space = tosend;
|
||||
@ -103,7 +104,7 @@ static size_t tinyusb_cdc_write(uint8_t itf, const uint8_t *buffer, size_t size)
|
||||
sofar += sent;
|
||||
tosend -= sent;
|
||||
tud_cdc_n_write_flush(itf);
|
||||
xSemaphoreTake(devices[itf]->tx_sem, portMAX_DELAY);
|
||||
//xSemaphoreTake(devices[itf]->tx_sem, portMAX_DELAY);
|
||||
}
|
||||
return sofar;
|
||||
}
|
||||
@ -113,21 +114,21 @@ static void ARDUINO_ISR_ATTR cdc0_write_char(char c)
|
||||
tinyusb_cdc_write(0, (const uint8_t *)&c, 1);
|
||||
}
|
||||
|
||||
//void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char);
|
||||
|
||||
static void usb_unplugged_cb(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
|
||||
((USBCDC*)arg)->_onUnplugged();
|
||||
}
|
||||
|
||||
USBCDC::USBCDC(uint8_t itfn) : itf(itfn), bit_rate(0), stop_bits(0), parity(0), data_bits(0), dtr(false), rts(false), connected(false), reboot_enable(true), rx_queue(NULL) {
|
||||
USBCDC::USBCDC(uint8_t itfn) : itf(itfn), bit_rate(0), stop_bits(0), parity(0), data_bits(0), dtr(false), rts(false), connected(false), reboot_enable(true), rx_queue(NULL), tx_sem(NULL) {
|
||||
tinyusb_enable_interface(USB_INTERFACE_CDC, TUD_CDC_DESC_LEN, load_cdc_descriptor);
|
||||
if(itf < MAX_USB_CDC_DEVICES){
|
||||
devices[itf] = this;
|
||||
tx_sem = NULL;
|
||||
arduino_usb_event_handler_register_with(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, usb_unplugged_cb, this);
|
||||
}
|
||||
}
|
||||
|
||||
USBCDC::~USBCDC(){
|
||||
end();
|
||||
}
|
||||
|
||||
void USBCDC::onEvent(esp_event_handler_t callback){
|
||||
onEvent(ARDUINO_USB_CDC_ANY_EVENT, callback);
|
||||
}
|
||||
@ -137,6 +138,10 @@ void USBCDC::onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback
|
||||
|
||||
size_t USBCDC::setRxBufferSize(size_t rx_queue_len){
|
||||
if(rx_queue){
|
||||
if(!rx_queue_len){
|
||||
vQueueDelete(rx_queue);
|
||||
rx_queue = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
rx_queue = xQueueCreate(rx_queue_len, sizeof(uint8_t));
|
||||
@ -148,15 +153,19 @@ size_t USBCDC::setRxBufferSize(size_t rx_queue_len){
|
||||
|
||||
void USBCDC::begin(unsigned long baud)
|
||||
{
|
||||
setRxBufferSize(256);//default if not preset
|
||||
if(tx_sem == NULL){
|
||||
tx_sem = xSemaphoreCreateBinary();
|
||||
xSemaphoreTake(tx_sem, 0);
|
||||
}
|
||||
setRxBufferSize(256);//default if not preset
|
||||
devices[itf] = this;
|
||||
}
|
||||
|
||||
void USBCDC::end()
|
||||
{
|
||||
connected = false;
|
||||
devices[itf] = NULL;
|
||||
setRxBufferSize(0);
|
||||
if (tx_sem != NULL) {
|
||||
vSemaphoreDelete(tx_sem);
|
||||
tx_sem = NULL;
|
||||
@ -176,6 +185,11 @@ void USBCDC::_onUnplugged(void){
|
||||
enum { CDC_LINE_IDLE, CDC_LINE_1, CDC_LINE_2, CDC_LINE_3 };
|
||||
void USBCDC::_onLineState(bool _dtr, bool _rts){
|
||||
static uint8_t lineState = CDC_LINE_IDLE;
|
||||
|
||||
if(dtr == _dtr && rts == _rts){
|
||||
return; // Skip duplicate events
|
||||
}
|
||||
|
||||
dtr = _dtr;
|
||||
rts = _rts;
|
||||
|
||||
@ -183,6 +197,11 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){
|
||||
if(!dtr && rts){
|
||||
if(lineState == CDC_LINE_IDLE){
|
||||
lineState++;
|
||||
if(connected){
|
||||
connected = false;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
} else {
|
||||
lineState = CDC_LINE_IDLE;
|
||||
}
|
||||
@ -212,7 +231,7 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){
|
||||
connected = true;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_CONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
} else if(!dtr && !rts && connected){
|
||||
} else if(!dtr && connected){
|
||||
connected = false;
|
||||
arduino_usb_cdc_event_data_t p = {0};
|
||||
arduino_usb_event_post(ARDUINO_USB_CDC_EVENTS, ARDUINO_USB_CDC_DISCONNECTED_EVENT, &p, sizeof(arduino_usb_cdc_event_data_t), portMAX_DELAY);
|
||||
@ -228,7 +247,7 @@ void USBCDC::_onLineState(bool _dtr, bool _rts){
|
||||
void USBCDC::_onLineCoding(uint32_t _bit_rate, uint8_t _stop_bits, uint8_t _parity, uint8_t _data_bits){
|
||||
if(bit_rate != _bit_rate || data_bits != _data_bits || stop_bits != _stop_bits || parity != _parity){
|
||||
// ArduinoIDE sends LineCoding with 1200bps baud to reset the device
|
||||
if(_bit_rate == 1200){
|
||||
if(reboot_enable && _bit_rate == 1200){
|
||||
usb_persist_restart(RESTART_BOOTLOADER);
|
||||
} else {
|
||||
bit_rate = _bit_rate;
|
||||
@ -317,7 +336,7 @@ size_t USBCDC::read(uint8_t *buffer, size_t size)
|
||||
|
||||
void USBCDC::flush(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES){
|
||||
if(itf >= MAX_USB_CDC_DEVICES || tx_sem == NULL){
|
||||
return;
|
||||
}
|
||||
tud_cdc_n_write_flush(itf);
|
||||
@ -325,7 +344,7 @@ void USBCDC::flush(void)
|
||||
|
||||
int USBCDC::availableForWrite(void)
|
||||
{
|
||||
if(itf >= MAX_USB_CDC_DEVICES){
|
||||
if(itf >= MAX_USB_CDC_DEVICES || tx_sem == NULL){
|
||||
return -1;
|
||||
}
|
||||
return tud_cdc_n_write_available(itf);
|
||||
@ -364,10 +383,8 @@ USBCDC::operator bool() const
|
||||
return connected;
|
||||
}
|
||||
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
|
||||
USBCDC Serial(0);
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_TINYUSB_CDC_ENABLED */
|
||||
|
||||
#endif /* CONFIG_TINYUSB_ENABLED */
|
||||
|
@ -13,13 +13,12 @@
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Stream.h"
|
||||
#include "esp32-hal.h"
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_TINYUSB_CDC_ENABLED
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "esp_event.h"
|
||||
#include "Stream.h"
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_CDC_EVENTS);
|
||||
|
||||
@ -54,6 +53,7 @@ class USBCDC: public Stream
|
||||
{
|
||||
public:
|
||||
USBCDC(uint8_t itf=0);
|
||||
~USBCDC();
|
||||
|
||||
void onEvent(esp_event_handler_t callback);
|
||||
void onEvent(arduino_usb_cdc_event_t event, esp_event_handler_t callback);
|
||||
@ -129,7 +129,7 @@ protected:
|
||||
|
||||
};
|
||||
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
#if ARDUINO_USB_CDC_ON_BOOT //Serial used for USB CDC
|
||||
extern USBCDC Serial;
|
||||
#endif
|
||||
|
||||
|
260
cores/esp32/USBMSC.cpp
Normal file
260
cores/esp32/USBMSC.cpp
Normal file
@ -0,0 +1,260 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "USBMSC.h"
|
||||
|
||||
#if CONFIG_TINYUSB_MSC_ENABLED
|
||||
|
||||
#include "esp32-hal-tinyusb.h"
|
||||
|
||||
extern "C" uint16_t tusb_msc_load_descriptor(uint8_t * dst, uint8_t * itf)
|
||||
{
|
||||
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB MSC");
|
||||
uint8_t ep_num = tinyusb_get_free_duplex_endpoint();
|
||||
TU_VERIFY (ep_num != 0);
|
||||
uint8_t descriptor[TUD_MSC_DESC_LEN] = {
|
||||
// Interface number, string index, EP Out & EP In address, EP size
|
||||
TUD_MSC_DESCRIPTOR(*itf, str_index, ep_num, (uint8_t)(0x80 | ep_num), 64)
|
||||
};
|
||||
*itf+=1;
|
||||
memcpy(dst, descriptor, TUD_MSC_DESC_LEN);
|
||||
return TUD_MSC_DESC_LEN;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
bool media_present;
|
||||
uint8_t vendor_id[8];
|
||||
uint8_t product_id[16];
|
||||
uint8_t product_rev[4];
|
||||
uint16_t block_size;
|
||||
uint32_t block_count;
|
||||
bool (*start_stop)(uint8_t power_condition, bool start, bool load_eject);
|
||||
int32_t (*read)(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
|
||||
int32_t (*write)(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
|
||||
} msc_lun_t;
|
||||
|
||||
static const uint8_t MSC_MAX_LUN = 3;
|
||||
static uint8_t MSC_ACTIVE_LUN = 0;
|
||||
static msc_lun_t msc_luns[MSC_MAX_LUN];
|
||||
|
||||
static void cplstr(void *dst, const void * src, size_t max_len){
|
||||
if(!src || !dst || !max_len){
|
||||
return;
|
||||
}
|
||||
size_t l = strlen((const char *)src);
|
||||
if(l > max_len){
|
||||
l = max_len;
|
||||
}
|
||||
memcpy(dst, src, l);
|
||||
}
|
||||
|
||||
// Invoked when received GET_MAX_LUN request, required for multiple LUNs implementation
|
||||
uint8_t tud_msc_get_maxlun_cb(void)
|
||||
{
|
||||
log_v("%u", MSC_ACTIVE_LUN);
|
||||
return MSC_ACTIVE_LUN;
|
||||
}
|
||||
|
||||
// Invoked when received SCSI_CMD_INQUIRY
|
||||
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
|
||||
{
|
||||
log_v("[%u]", lun);
|
||||
cplstr(vendor_id , msc_luns[lun].vendor_id, 8);
|
||||
cplstr(product_id , msc_luns[lun].product_id, 16);
|
||||
cplstr(product_rev, msc_luns[lun].product_rev, 4);
|
||||
}
|
||||
|
||||
// Invoked when received Test Unit Ready command.
|
||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||
bool tud_msc_test_unit_ready_cb(uint8_t lun)
|
||||
{
|
||||
log_v("[%u]: %u", lun, msc_luns[lun].media_present);
|
||||
return msc_luns[lun].media_present; // RAM disk is always ready
|
||||
}
|
||||
|
||||
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
|
||||
// Application update block count and block size
|
||||
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
|
||||
{
|
||||
log_v("[%u]", lun);
|
||||
if(!msc_luns[lun].media_present){
|
||||
*block_count = 0;
|
||||
*block_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
*block_count = msc_luns[lun].block_count;
|
||||
*block_size = msc_luns[lun].block_size;
|
||||
}
|
||||
|
||||
// Invoked when received Start Stop Unit command
|
||||
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
|
||||
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
|
||||
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
|
||||
{
|
||||
log_v("[%u] power: %u, start: %u, eject: %u", lun, power_condition, start, load_eject);
|
||||
if(msc_luns[lun].start_stop){
|
||||
return msc_luns[lun].start_stop(power_condition, start, load_eject);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
|
||||
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
log_v("[%u], lba: %u, offset: %u, bufsize: %u", lun, lba, offset, bufsize);
|
||||
if(!msc_luns[lun].media_present){
|
||||
return 0;
|
||||
}
|
||||
if(msc_luns[lun].read){
|
||||
return msc_luns[lun].read(lba, offset, buffer, bufsize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and return number of written bytes
|
||||
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
log_v("[%u], lba: %u, offset: %u, bufsize: %u", lun, lba, offset, bufsize);
|
||||
if(!msc_luns[lun].media_present){
|
||||
return 0;
|
||||
}
|
||||
if(msc_luns[lun].write){
|
||||
return msc_luns[lun].write(lba, offset, buffer, bufsize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Callback invoked when received an SCSI command not in built-in list below
|
||||
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
|
||||
// - READ10 and WRITE10 has their own callbacks
|
||||
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
|
||||
{
|
||||
// read10 & write10 has their own callback and MUST not be handled here
|
||||
log_v("[%u] cmd: %u, bufsize: %u", lun, scsi_cmd[0], bufsize);
|
||||
|
||||
void const* response = NULL;
|
||||
uint16_t resplen = 0;
|
||||
|
||||
// most scsi handled is input
|
||||
bool in_xfer = true;
|
||||
|
||||
if(!msc_luns[lun].media_present){
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (scsi_cmd[0]) {
|
||||
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
|
||||
// Host is about to read/write etc ... better not to disconnect disk
|
||||
resplen = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Set Sense = Invalid Command Operation
|
||||
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
|
||||
|
||||
// negative means error -> tinyusb could stall and/or response with failed status
|
||||
resplen = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// return resplen must not larger than bufsize
|
||||
if (resplen > bufsize) resplen = bufsize;
|
||||
|
||||
if (response && (resplen > 0)) {
|
||||
if (in_xfer) {
|
||||
memcpy(buffer, response, resplen);
|
||||
} else {
|
||||
// SCSI output
|
||||
}
|
||||
}
|
||||
|
||||
return resplen;
|
||||
}
|
||||
|
||||
USBMSC::USBMSC(){
|
||||
if(MSC_ACTIVE_LUN < MSC_MAX_LUN){
|
||||
_lun = MSC_ACTIVE_LUN;
|
||||
MSC_ACTIVE_LUN++;
|
||||
msc_luns[_lun].media_present = false;
|
||||
msc_luns[_lun].vendor_id[0] = 0;
|
||||
msc_luns[_lun].product_id[0] = 0;
|
||||
msc_luns[_lun].product_rev[0] = 0;
|
||||
msc_luns[_lun].block_size = 0;
|
||||
msc_luns[_lun].block_count = 0;
|
||||
msc_luns[_lun].start_stop = NULL;
|
||||
msc_luns[_lun].read = NULL;
|
||||
msc_luns[_lun].write = NULL;
|
||||
}
|
||||
if(_lun == 0){
|
||||
tinyusb_enable_interface(USB_INTERFACE_MSC, TUD_MSC_DESC_LEN, tusb_msc_load_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
USBMSC::~USBMSC(){
|
||||
end();
|
||||
}
|
||||
|
||||
bool USBMSC::begin(uint32_t block_count, uint16_t block_size){
|
||||
msc_luns[_lun].block_size = block_size;
|
||||
msc_luns[_lun].block_count = block_count;
|
||||
if(!msc_luns[_lun].block_size || !msc_luns[_lun].block_count || !msc_luns[_lun].read || !msc_luns[_lun].write){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void USBMSC::end(){
|
||||
msc_luns[_lun].media_present = false;
|
||||
msc_luns[_lun].vendor_id[0] = 0;
|
||||
msc_luns[_lun].product_id[0] = 0;
|
||||
msc_luns[_lun].product_rev[0] = 0;
|
||||
msc_luns[_lun].block_size = 0;
|
||||
msc_luns[_lun].block_count = 0;
|
||||
msc_luns[_lun].start_stop = NULL;
|
||||
msc_luns[_lun].read = NULL;
|
||||
msc_luns[_lun].write = NULL;
|
||||
}
|
||||
|
||||
void USBMSC::vendorID(const char * vid){
|
||||
cplstr(msc_luns[_lun].vendor_id, vid, 8);
|
||||
}
|
||||
|
||||
void USBMSC::productID(const char * pid){
|
||||
cplstr(msc_luns[_lun].product_id, pid, 16);
|
||||
}
|
||||
|
||||
void USBMSC::productRevision(const char * rev){
|
||||
cplstr(msc_luns[_lun].product_rev, rev, 4);
|
||||
}
|
||||
|
||||
void USBMSC::onStartStop(msc_start_stop_cb cb){
|
||||
msc_luns[_lun].start_stop = cb;
|
||||
}
|
||||
|
||||
void USBMSC::onRead(msc_read_cb cb){
|
||||
msc_luns[_lun].read = cb;
|
||||
}
|
||||
|
||||
void USBMSC::onWrite(msc_write_cb cb){
|
||||
msc_luns[_lun].write = cb;
|
||||
}
|
||||
|
||||
void USBMSC::mediaPresent(bool media_present){
|
||||
msc_luns[_lun].media_present = media_present;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TINYUSB_MSC_ENABLED */
|
51
cores/esp32/USBMSC.h
Normal file
51
cores/esp32/USBMSC.h
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_TINYUSB_MSC_ENABLED
|
||||
|
||||
// Invoked when received Start Stop Unit command
|
||||
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
|
||||
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
|
||||
typedef bool (*msc_start_stop_cb)(uint8_t power_condition, bool start, bool load_eject);
|
||||
|
||||
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
|
||||
typedef int32_t (*msc_read_cb)(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
|
||||
|
||||
// Process data in buffer to disk's storage and return number of written bytes
|
||||
typedef int32_t (*msc_write_cb)(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
|
||||
|
||||
class USBMSC
|
||||
{
|
||||
public:
|
||||
USBMSC();
|
||||
~USBMSC();
|
||||
bool begin(uint32_t block_count, uint16_t block_size);
|
||||
void end();
|
||||
void vendorID(const char * vid);//max 8 chars
|
||||
void productID(const char * pid);//max 16 chars
|
||||
void productRevision(const char * ver);//max 4 chars
|
||||
void mediaPresent(bool media_present);
|
||||
void onStartStop(msc_start_stop_cb cb);
|
||||
void onRead(msc_read_cb cb);
|
||||
void onWrite(msc_write_cb cb);
|
||||
private:
|
||||
uint8_t _lun;
|
||||
};
|
||||
|
||||
#endif /* CONFIG_TINYUSB_MSC_ENABLED */
|
@ -104,8 +104,10 @@ void __analogSetPinAttenuation(uint8_t pin, adc_attenuation_t attenuation)
|
||||
adc1_config_channel_atten(channel, attenuation);
|
||||
}
|
||||
__analogInit();
|
||||
if((__pin_attenuation[pin] != ADC_ATTENDB_MAX) || (attenuation != __analogAttenuation)){
|
||||
__pin_attenuation[pin] = attenuation;
|
||||
}
|
||||
}
|
||||
|
||||
bool __adcAttachPin(uint8_t pin){
|
||||
int8_t channel = digitalPinToAnalogChannel(pin);
|
||||
@ -113,6 +115,7 @@ bool __adcAttachPin(uint8_t pin){
|
||||
log_e("Pin %u is not ADC pin!", pin);
|
||||
return false;
|
||||
}
|
||||
__analogInit();
|
||||
int8_t pad = digitalPinToTouchChannel(pin);
|
||||
if(pad >= 0){
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
|
@ -1848,7 +1848,9 @@ i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size,
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, (address << 1) | I2C_MASTER_WRITE, ACK_CHECK_EN);
|
||||
if(size){
|
||||
i2c_master_write(cmd, buff, size, ACK_CHECK_EN);
|
||||
}
|
||||
//if send stop?
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(i2c->num, cmd, timeOutMillis / portTICK_RATE_MS);
|
||||
|
@ -115,6 +115,10 @@ static void _ledcSetupTimer(uint8_t chan, uint32_t div_num, uint8_t bit_num, boo
|
||||
uint8_t group=(chan/8), timer=((chan/2)%4);
|
||||
static bool tHasStarted = false;
|
||||
static uint16_t _activeChannels = 0;
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
// ESP32-S2 TRM v1.0 on Page 789 -> BIT LEDC_TICK_SEL_TIMERx is 0 for LEDC_PWM_CLK and 1 for REF_TICK
|
||||
apb_clk = 0;
|
||||
#endif
|
||||
if(!tHasStarted) {
|
||||
tHasStarted = true;
|
||||
periph_module_enable(PERIPH_LEDC_MODULE);
|
||||
|
@ -66,6 +66,8 @@ extern "C"
|
||||
#define ARDUHAL_LOG_COLOR_I ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_GREEN)
|
||||
#define ARDUHAL_LOG_COLOR_D ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_CYAN)
|
||||
#define ARDUHAL_LOG_COLOR_V ARDUHAL_LOG_COLOR(ARDUHAL_LOG_COLOR_GRAY)
|
||||
#define ARDUHAL_LOG_COLOR_PRINT(letter) log_printf(ARDUHAL_LOG_COLOR_ ## letter)
|
||||
#define ARDUHAL_LOG_COLOR_PRINT_END log_printf(ARDUHAL_LOG_RESET_COLOR)
|
||||
#else
|
||||
#define ARDUHAL_LOG_COLOR_E
|
||||
#define ARDUHAL_LOG_COLOR_W
|
||||
@ -73,12 +75,15 @@ extern "C"
|
||||
#define ARDUHAL_LOG_COLOR_D
|
||||
#define ARDUHAL_LOG_COLOR_V
|
||||
#define ARDUHAL_LOG_RESET_COLOR
|
||||
#define ARDUHAL_LOG_COLOR_PRINT(letter)
|
||||
#define ARDUHAL_LOG_COLOR_PRINT_END
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
const char * pathToFileName(const char * path);
|
||||
int log_printf(const char *fmt, ...);
|
||||
void log_print_buf(const uint8_t *b, size_t len);
|
||||
|
||||
#define ARDUHAL_SHORT_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter format ARDUHAL_LOG_RESET_COLOR "\r\n"
|
||||
#define ARDUHAL_LOG_FORMAT(letter, format) ARDUHAL_LOG_COLOR_ ## letter "[%6u][" #letter "][%s:%u] %s(): " format ARDUHAL_LOG_RESET_COLOR "\r\n", (unsigned long) (esp_timer_get_time() / 1000ULL), pathToFileName(__FILE__), __LINE__, __FUNCTION__
|
||||
@ -87,78 +92,96 @@ int log_printf(const char *fmt, ...);
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_v(format, ...) log_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__)
|
||||
#define isr_log_v(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(V, format), ##__VA_ARGS__)
|
||||
#define log_buf_v(b,l) do{ARDUHAL_LOG_COLOR_PRINT(V);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
|
||||
#else
|
||||
#define log_v(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_VERBOSE, TAG, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_v(format, ...) do {ets_printf(LOG_FORMAT(V, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#define log_buf_v(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_VERBOSE);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_v(format, ...)
|
||||
#define isr_log_v(format, ...)
|
||||
#define log_buf_v(b,l)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_d(format, ...) log_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__)
|
||||
#define isr_log_d(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(D, format), ##__VA_ARGS__)
|
||||
#define log_buf_d(b,l) do{ARDUHAL_LOG_COLOR_PRINT(D);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
|
||||
#else
|
||||
#define log_d(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_DEBUG, TAG, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_d(format, ...) do {ets_printf(LOG_FORMAT(D, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#define log_buf_d(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_DEBUG);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_d(format, ...)
|
||||
#define isr_log_d(format, ...)
|
||||
#define log_buf_d(b,l)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_i(format, ...) log_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__)
|
||||
#define isr_log_i(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(I, format), ##__VA_ARGS__)
|
||||
#define log_buf_i(b,l) do{ARDUHAL_LOG_COLOR_PRINT(I);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
|
||||
#else
|
||||
#define log_i(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_INFO, TAG, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_i(format, ...) do {ets_printf(LOG_FORMAT(I, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#define log_buf_i(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_INFO);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_i(format, ...)
|
||||
#define isr_log_i(format, ...)
|
||||
#define log_buf_i(b,l)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_WARN
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_w(format, ...) log_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__)
|
||||
#define isr_log_w(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(W, format), ##__VA_ARGS__)
|
||||
#define log_buf_w(b,l) do{ARDUHAL_LOG_COLOR_PRINT(W);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
|
||||
#else
|
||||
#define log_w(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_WARN, TAG, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_w(format, ...) do {ets_printf(LOG_FORMAT(W, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#define log_buf_w(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_WARN);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_w(format, ...)
|
||||
#define isr_log_w(format, ...)
|
||||
#define log_buf_w(b,l)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_ERROR
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_e(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#define isr_log_e(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#define log_buf_e(b,l) do{ARDUHAL_LOG_COLOR_PRINT(E);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
|
||||
#else
|
||||
#define log_e(format, ...) do {log_to_esp(TAG, ESP_LOG_ERROR, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_e(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#define log_buf_e(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_ERROR);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_e(format, ...)
|
||||
#define isr_log_e(format, ...)
|
||||
#define log_buf_e(b,l)
|
||||
#endif
|
||||
|
||||
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_NONE
|
||||
#ifndef USE_ESP_IDF_LOG
|
||||
#define log_n(format, ...) log_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#define isr_log_n(format, ...) ets_printf(ARDUHAL_LOG_FORMAT(E, format), ##__VA_ARGS__)
|
||||
#define log_buf_n(b,l) do{ARDUHAL_LOG_COLOR_PRINT(E);log_print_buf(b,l);ARDUHAL_LOG_COLOR_PRINT_END;}while(0)
|
||||
#else
|
||||
#define log_n(format, ...) do {ESP_LOG_LEVEL_LOCAL(ESP_LOG_ERROR, TAG, format, ##__VA_ARGS__);}while(0)
|
||||
#define isr_log_n(format, ...) do {ets_printf(LOG_FORMAT(E, format), esp_log_timestamp(), TAG, ##__VA_ARGS__);}while(0)
|
||||
#define log_buf_n(b,l) do {ESP_LOG_BUFFER_HEXDUMP(TAG, b, l, ESP_LOG_ERROR);}while(0)
|
||||
#endif
|
||||
#else
|
||||
#define log_n(format, ...)
|
||||
#define isr_log_n(format, ...)
|
||||
#define log_buf_n(b,l)
|
||||
#endif
|
||||
|
||||
#include "esp_log.h"
|
||||
|
@ -44,6 +44,8 @@ static void setTimeZone(long offset, int daylight)
|
||||
/*
|
||||
* configTime
|
||||
* Source: https://github.com/esp8266/Arduino/blob/master/cores/esp8266/time.c
|
||||
* Note: Bundled Arduino lwip supports only ONE ntp server, 2nd and 3rd options are silently ignored
|
||||
* see CONFIG_LWIP_DHCP_MAX_NTP_SERVERS define in ./tools/sdk/esp32/sdkconfig
|
||||
* */
|
||||
void configTime(long gmtOffset_sec, int daylightOffset_sec, const char* server1, const char* server2, const char* server3)
|
||||
{
|
||||
@ -63,6 +65,8 @@ void configTime(long gmtOffset_sec, int daylightOffset_sec, const char* server1,
|
||||
/*
|
||||
* configTzTime
|
||||
* sntp setup using TZ environment variable
|
||||
* Note: Bundled Arduino lwip supports only ONE ntp server, 2nd and 3rd options are silently ignored
|
||||
* see CONFIG_LWIP_DHCP_MAX_NTP_SERVERS define in ./tools/sdk/esp32/sdkconfig
|
||||
* */
|
||||
void configTzTime(const char* tz, const char* server1, const char* server2, const char* server3)
|
||||
{
|
||||
|
@ -119,8 +119,9 @@ void ARDUINO_ISR_ATTR __timerISR(void * arg){
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t timerRead(hw_timer_t *timer){
|
||||
uint64_t inline timerRead(hw_timer_t *timer){
|
||||
timer->dev->update = 1;
|
||||
while (timer->dev->update) {};
|
||||
uint64_t h = timer->dev->cnt_high;
|
||||
uint64_t l = timer->dev->cnt_low;
|
||||
return (h << 32) | l;
|
||||
|
@ -72,20 +72,15 @@ static void configure_pins(usb_hal_context_t *usb)
|
||||
|
||||
esp_err_t tinyusb_driver_install(const tinyusb_config_t *config)
|
||||
{
|
||||
log_i("Driver installation...");
|
||||
|
||||
// Hal init
|
||||
usb_hal_context_t hal = {
|
||||
.use_external_phy = config->external_phy
|
||||
};
|
||||
usb_hal_init(&hal);
|
||||
configure_pins(&hal);
|
||||
|
||||
if (!tusb_init()) {
|
||||
log_e("Can't initialize the TinyUSB stack.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
log_i("Driver installed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -106,6 +101,7 @@ static tusb_str_t WEBUSB_URL = "";
|
||||
static tusb_str_t USB_DEVICE_PRODUCT = "";
|
||||
static tusb_str_t USB_DEVICE_MANUFACTURER = "";
|
||||
static tusb_str_t USB_DEVICE_SERIAL = "";
|
||||
static tusb_str_t USB_DEVICE_LANGUAGE = "\x09\x04";//English (0x0409)
|
||||
|
||||
static uint8_t USB_DEVICE_ATTRIBUTES = 0;
|
||||
static uint16_t USB_DEVICE_POWER = 0;
|
||||
@ -140,7 +136,7 @@ static tusb_desc_device_t tinyusb_device_descriptor = {
|
||||
static uint32_t tinyusb_string_descriptor_len = 4;
|
||||
static char * tinyusb_string_descriptor[MAX_STRING_DESCRIPTORS] = {
|
||||
// array of pointer to string descriptors
|
||||
"\x09\x04", // 0: is supported language is English (0x0409)
|
||||
USB_DEVICE_LANGUAGE, // 0: is supported language
|
||||
USB_DEVICE_MANUFACTURER,// 1: Manufacturer
|
||||
USB_DEVICE_PRODUCT, // 2: Product
|
||||
USB_DEVICE_SERIAL, // 3: Serials, should use chip ID
|
||||
@ -263,7 +259,7 @@ static tinyusb_endpoints_usage_t tinyusb_endpoints;
|
||||
/**
|
||||
* @brief Invoked when received GET CONFIGURATION DESCRIPTOR.
|
||||
*/
|
||||
uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
|
||||
__attribute__ ((weak)) uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
|
||||
{
|
||||
//log_d("%u", index);
|
||||
return tinyusb_config_descriptor;
|
||||
@ -272,7 +268,7 @@ uint8_t const *tud_descriptor_configuration_cb(uint8_t index)
|
||||
/**
|
||||
* @brief Invoked when received GET DEVICE DESCRIPTOR.
|
||||
*/
|
||||
uint8_t const *tud_descriptor_device_cb(void)
|
||||
__attribute__ ((weak)) uint8_t const *tud_descriptor_device_cb(void)
|
||||
{
|
||||
//log_d("");
|
||||
return (uint8_t const *)&tinyusb_device_descriptor;
|
||||
@ -281,7 +277,7 @@ uint8_t const *tud_descriptor_device_cb(void)
|
||||
/**
|
||||
* @brief Invoked when received GET STRING DESCRIPTOR request.
|
||||
*/
|
||||
uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||
__attribute__ ((weak)) uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid)
|
||||
{
|
||||
//log_d("%u (0x%x)", index, langid);
|
||||
static uint16_t _desc_str[127];
|
||||
@ -428,12 +424,6 @@ static bool tinyusb_load_enabled_interfaces(){
|
||||
log_e("Descriptor Load Failed");
|
||||
return false;
|
||||
} else {
|
||||
if(i == USB_INTERFACE_CDC){
|
||||
if(!tinyusb_reserve_out_endpoint(3) ||!tinyusb_reserve_in_endpoint(4) || !tinyusb_reserve_in_endpoint(5)){
|
||||
log_e("CDC Reserve Endpoints Failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
dst += len;
|
||||
}
|
||||
}
|
||||
@ -509,6 +499,7 @@ static void tinyusb_apply_device_config(tinyusb_device_config_t *config){
|
||||
&& (config->usb_class != TUSB_CLASS_CDC)
|
||||
){
|
||||
config->usb_class = TUSB_CLASS_CDC;
|
||||
config->usb_protocol = 0x00;
|
||||
}
|
||||
|
||||
WEBUSB_ENABLED = config->webusb_enabled;
|
||||
@ -563,31 +554,43 @@ static void usb_device_task(void *param) {
|
||||
/*
|
||||
* PUBLIC API
|
||||
* */
|
||||
static const char *tinyusb_interface_names[USB_INTERFACE_MAX] = {"MSC", "DFU", "HID", "VENDOR", "CDC", "MIDI", "CUSTOM"};
|
||||
|
||||
static bool tinyusb_is_initialized = false;
|
||||
|
||||
esp_err_t tinyusb_enable_interface(tinyusb_interface_t interface, uint16_t descriptor_len, tinyusb_descriptor_cb_t cb)
|
||||
{
|
||||
if((interface >= USB_INTERFACE_MAX) || (tinyusb_loaded_interfaces_mask & (1U << interface))){
|
||||
log_e("Interface %u not enabled", interface);
|
||||
if(tinyusb_is_initialized){
|
||||
log_e("TinyUSB has already started! Interface %s not enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if((interface >= USB_INTERFACE_MAX) || (tinyusb_loaded_interfaces_mask & (1U << interface))){
|
||||
log_e("Interface %s invalid or already enabled", (interface >= USB_INTERFACE_MAX)?"":tinyusb_interface_names[interface]);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if(interface == USB_INTERFACE_CDC){
|
||||
if(!tinyusb_reserve_out_endpoint(3) ||!tinyusb_reserve_in_endpoint(4) || !tinyusb_reserve_in_endpoint(5)){
|
||||
log_e("CDC Reserve Endpoints Failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
tinyusb_loaded_interfaces_mask |= (1U << interface);
|
||||
tinyusb_config_descriptor_len += descriptor_len;
|
||||
tinyusb_loaded_interfaces_callbacks[interface] = cb;
|
||||
log_d("Interface %u enabled", interface);
|
||||
log_d("Interface %s enabled", tinyusb_interface_names[interface]);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
|
||||
static bool initialized = false;
|
||||
if(initialized){
|
||||
if(tinyusb_is_initialized){
|
||||
return ESP_OK;
|
||||
}
|
||||
initialized = true;
|
||||
tinyusb_is_initialized = true;
|
||||
|
||||
tinyusb_endpoints.val = 0;
|
||||
//tinyusb_endpoints.val = 0;
|
||||
tinyusb_apply_device_config(config);
|
||||
if (!tinyusb_load_enabled_interfaces()) {
|
||||
initialized = false;
|
||||
tinyusb_is_initialized = false;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
@ -605,7 +608,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
|
||||
}
|
||||
|
||||
if (esp_register_shutdown_handler(usb_persist_shutdown_handler) != ESP_OK) {
|
||||
initialized = false;
|
||||
tinyusb_is_initialized = false;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
@ -614,7 +617,7 @@ esp_err_t tinyusb_init(tinyusb_device_config_t *config) {
|
||||
};
|
||||
esp_err_t err = tinyusb_driver_install(&tusb_cfg);
|
||||
if (err != ESP_OK) {
|
||||
initialized = false;
|
||||
tinyusb_is_initialized = false;
|
||||
return err;
|
||||
}
|
||||
xTaskCreate(usb_device_task, "usbd", 4096, NULL, configMAX_PRIORITIES - 1, NULL);
|
||||
@ -690,84 +693,4 @@ uint8_t tinyusb_get_free_out_endpoint(void){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
void usb_dw_reg_dump(void)
|
||||
{
|
||||
#define USB_PRINT_REG(r) printf("USB0." #r " = 0x%x;\n", USB0.r)
|
||||
#define USB_PRINT_IREG(i, r) printf("USB0.in_ep_reg[%u]." #r " = 0x%x;\n", i, USB0.in_ep_reg[i].r)
|
||||
#define USB_PRINT_OREG(i, r) printf("USB0.out_ep_reg[%u]." #r " = 0x%x;\n", i, USB0.out_ep_reg[i].r)
|
||||
uint8_t i;
|
||||
USB_PRINT_REG(gotgctl);
|
||||
USB_PRINT_REG(gotgint);
|
||||
USB_PRINT_REG(gahbcfg);
|
||||
USB_PRINT_REG(gusbcfg);
|
||||
USB_PRINT_REG(grstctl);
|
||||
USB_PRINT_REG(gintsts);
|
||||
USB_PRINT_REG(gintmsk);
|
||||
USB_PRINT_REG(grxstsr);
|
||||
USB_PRINT_REG(grxstsp);
|
||||
USB_PRINT_REG(grxfsiz);
|
||||
USB_PRINT_REG(gnptxsts);
|
||||
USB_PRINT_REG(gpvndctl);
|
||||
USB_PRINT_REG(ggpio);
|
||||
USB_PRINT_REG(guid);
|
||||
USB_PRINT_REG(gsnpsid);
|
||||
USB_PRINT_REG(ghwcfg1);
|
||||
USB_PRINT_REG(ghwcfg2);
|
||||
USB_PRINT_REG(ghwcfg3);
|
||||
USB_PRINT_REG(ghwcfg4);
|
||||
USB_PRINT_REG(glpmcfg);
|
||||
USB_PRINT_REG(gpwrdn);
|
||||
USB_PRINT_REG(gdfifocfg);
|
||||
USB_PRINT_REG(gadpctl);
|
||||
USB_PRINT_REG(hptxfsiz);
|
||||
USB_PRINT_REG(hcfg);
|
||||
USB_PRINT_REG(hfir);
|
||||
USB_PRINT_REG(hfnum);
|
||||
USB_PRINT_REG(hptxsts);
|
||||
USB_PRINT_REG(haint);
|
||||
USB_PRINT_REG(haintmsk);
|
||||
USB_PRINT_REG(hflbaddr);
|
||||
USB_PRINT_REG(hprt);
|
||||
USB_PRINT_REG(dcfg);
|
||||
USB_PRINT_REG(dctl);
|
||||
USB_PRINT_REG(dsts);
|
||||
USB_PRINT_REG(diepmsk);
|
||||
USB_PRINT_REG(doepmsk);
|
||||
USB_PRINT_REG(daint);
|
||||
USB_PRINT_REG(daintmsk);
|
||||
USB_PRINT_REG(dtknqr1);
|
||||
USB_PRINT_REG(dtknqr2);
|
||||
USB_PRINT_REG(dvbusdis);
|
||||
USB_PRINT_REG(dvbuspulse);
|
||||
USB_PRINT_REG(dtknqr3_dthrctl);
|
||||
USB_PRINT_REG(dtknqr4_fifoemptymsk);
|
||||
USB_PRINT_REG(deachint);
|
||||
USB_PRINT_REG(deachintmsk);
|
||||
USB_PRINT_REG(pcgctrl);
|
||||
USB_PRINT_REG(pcgctrl1);
|
||||
USB_PRINT_REG(gnptxfsiz);
|
||||
for (i = 0; i < 4; i++) {
|
||||
printf("USB0.dieptxf[%u] = 0x%x;\n", i, USB0.dieptxf[i]);
|
||||
}
|
||||
// for (i = 0; i < 16; i++) {
|
||||
// printf("USB0.diepeachintmsk[%u] = 0x%x;\n", i, USB0.diepeachintmsk[i]);
|
||||
// }
|
||||
// for (i = 0; i < 16; i++) {
|
||||
// printf("USB0.doepeachintmsk[%u] = 0x%x;\n", i, USB0.doepeachintmsk[i]);
|
||||
// }
|
||||
for (i = 0; i < 7; i++) {
|
||||
printf("// EP %u:\n", i);
|
||||
USB_PRINT_IREG(i, diepctl);
|
||||
USB_PRINT_IREG(i, diepint);
|
||||
USB_PRINT_IREG(i, dieptsiz);
|
||||
USB_PRINT_IREG(i, diepdma);
|
||||
USB_PRINT_IREG(i, dtxfsts);
|
||||
USB_PRINT_OREG(i, doepctl);
|
||||
USB_PRINT_OREG(i, doepint);
|
||||
USB_PRINT_OREG(i, doeptsiz);
|
||||
USB_PRINT_OREG(i, doepdma);
|
||||
}
|
||||
}
|
||||
*/
|
||||
#endif /* CONFIG_TINYUSB_ENABLED */
|
||||
|
@ -82,11 +82,11 @@ void usb_persist_restart(restart_type_t mode);
|
||||
|
||||
// The following definitions and functions are to be used only by the drivers
|
||||
typedef enum {
|
||||
USB_INTERFACE_CDC,
|
||||
USB_INTERFACE_MSC,
|
||||
USB_INTERFACE_DFU,
|
||||
USB_INTERFACE_HID,
|
||||
USB_INTERFACE_VENDOR,
|
||||
USB_INTERFACE_MSC,
|
||||
USB_INTERFACE_CDC,
|
||||
USB_INTERFACE_MIDI,
|
||||
USB_INTERFACE_CUSTOM,
|
||||
USB_INTERFACE_MAX
|
||||
|
@ -95,6 +95,7 @@ void __touchInit()
|
||||
SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_EN_CLR);
|
||||
//clear touch enable
|
||||
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, 0x0);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_TOUCH_SLP_TIMER_EN);
|
||||
__touchSetCycles(__touchMeasureCycles, __touchSleepCycles);
|
||||
esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, (int)ARDUINO_ISR_FLAG, __touchISR, NULL, &touch_intr_handle);
|
||||
#else
|
||||
|
@ -14,205 +14,88 @@
|
||||
|
||||
#include "esp32-hal-uart.h"
|
||||
#include "esp32-hal.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/uart_reg.h"
|
||||
#include "soc/uart_struct.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/rtc.h"
|
||||
|
||||
#include "driver/uart.h"
|
||||
#include "hal/uart_ll.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "soc/dport_reg.h"
|
||||
#include "esp32/rom/ets_sys.h"
|
||||
#include "esp32/rom/uart.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "soc/dport_reg.h"
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#include "esp32s2/rom/uart.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/ets_sys.h"
|
||||
#include "esp32c3/rom/uart.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "rom/ets_sys.h"
|
||||
#include "rom/uart.h"
|
||||
#include "esp_intr.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define UART_PORTS_NUM 3
|
||||
#define UART_REG_BASE(u) ((u==0)?DR_REG_UART_BASE:( (u==1)?DR_REG_UART1_BASE:( (u==2)?DR_REG_UART2_BASE:0)))
|
||||
#define UART_RXD_IDX(u) ((u==0)?U0RXD_IN_IDX:( (u==1)?U1RXD_IN_IDX:( (u==2)?U2RXD_IN_IDX:0)))
|
||||
#define UART_TXD_IDX(u) ((u==0)?U0TXD_OUT_IDX:( (u==1)?U1TXD_OUT_IDX:( (u==2)?U2TXD_OUT_IDX:0)))
|
||||
#define UART_INTR_SOURCE(u) ((u==0)?ETS_UART0_INTR_SOURCE:( (u==1)?ETS_UART1_INTR_SOURCE:((u==2)?ETS_UART2_INTR_SOURCE:0)))
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define UART_PORTS_NUM 2
|
||||
#define UART_REG_BASE(u) ((u==0)?DR_REG_UART_BASE:( (u==1)?DR_REG_UART1_BASE:0))
|
||||
#define UART_RXD_IDX(u) ((u==0)?U0RXD_IN_IDX:( (u==1)?U1RXD_IN_IDX:0))
|
||||
#define UART_TXD_IDX(u) ((u==0)?U0TXD_OUT_IDX:( (u==1)?U1TXD_OUT_IDX:0))
|
||||
#define UART_INTR_SOURCE(u) ((u==0)?ETS_UART0_INTR_SOURCE:( (u==1)?ETS_UART1_INTR_SOURCE:0))
|
||||
#else
|
||||
#define UART_PORTS_NUM 2
|
||||
#define UART_REG_BASE(u) ((u==0)?DR_REG_UART_BASE:( (u==1)?DR_REG_UART1_BASE:0))
|
||||
#define UART_RXD_IDX(u) ((u==0)?U0RXD_IN_IDX:( (u==1)?U1RXD_IN_IDX:0))
|
||||
#define UART_TXD_IDX(u) ((u==0)?U0TXD_OUT_IDX:( (u==1)?U1TXD_OUT_IDX:0))
|
||||
#define UART_INTR_SOURCE(u) ((u==0)?ETS_UART0_INTR_SOURCE:( (u==1)?ETS_UART1_INTR_SOURCE:0))
|
||||
#endif
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/uart_struct.h"
|
||||
|
||||
static int s_uart_debug_nr = 0;
|
||||
|
||||
struct uart_struct_t {
|
||||
uart_dev_t * dev;
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
xSemaphoreHandle lock;
|
||||
#endif
|
||||
|
||||
uint8_t num;
|
||||
xQueueHandle queue;
|
||||
intr_handle_t intr_handle;
|
||||
bool has_peek;
|
||||
uint8_t peek_byte;
|
||||
|
||||
};
|
||||
|
||||
#if CONFIG_DISABLE_HAL_LOCKS
|
||||
|
||||
#define UART_MUTEX_LOCK()
|
||||
#define UART_MUTEX_UNLOCK()
|
||||
|
||||
static uart_t _uart_bus_array[] = {
|
||||
{&UART0, 0, NULL, NULL},
|
||||
{&UART1, 1, NULL, NULL},
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
{&UART2, 2, NULL, NULL}
|
||||
{0, false, 0},
|
||||
#if SOC_UART_NUM > 1
|
||||
{1, false, 0},
|
||||
#endif
|
||||
#if SOC_UART_NUM > 2
|
||||
{2, false, 0},
|
||||
#endif
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#define UART_MUTEX_LOCK() do {} while (xSemaphoreTake(uart->lock, portMAX_DELAY) != pdPASS)
|
||||
#define UART_MUTEX_UNLOCK() xSemaphoreGive(uart->lock)
|
||||
|
||||
static uart_t _uart_bus_array[] = {
|
||||
{&UART0, NULL, 0, NULL, NULL},
|
||||
{&UART1, NULL, 1, NULL, NULL},
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
{&UART2, NULL, 2, NULL, NULL}
|
||||
{NULL, 0, false, 0},
|
||||
#if SOC_UART_NUM > 1
|
||||
{NULL, 1, false, 0},
|
||||
#endif
|
||||
#if SOC_UART_NUM > 2
|
||||
{NULL, 2, false, 0},
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb);
|
||||
|
||||
static void ARDUINO_ISR_ATTR _uart_isr(void *arg)
|
||||
{
|
||||
uint8_t i, c;
|
||||
BaseType_t xHigherPriorityTaskWoken;
|
||||
uart_t* uart;
|
||||
|
||||
for(i=0;i<UART_PORTS_NUM;i++){
|
||||
uart = &_uart_bus_array[i];
|
||||
if(uart->intr_handle == NULL){
|
||||
continue;
|
||||
}
|
||||
uart->dev->int_clr.rxfifo_full = 1;
|
||||
uart->dev->int_clr.frm_err = 1;
|
||||
uart->dev->int_clr.rxfifo_tout = 1;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while(uart->dev->status.rxfifo_cnt || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
||||
c = uart->dev->fifo.rw_byte;
|
||||
#else
|
||||
uint32_t fifo_reg = UART_FIFO_AHB_REG(i);
|
||||
while(uart->dev->status.rxfifo_cnt) {
|
||||
c = ESP_REG(fifo_reg);
|
||||
#endif
|
||||
if(uart->queue != NULL) {
|
||||
xQueueSendFromISR(uart->queue, &c, &xHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (xHigherPriorityTaskWoken) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
static void uartEnableInterrupt(uart_t* uart, uint8_t rxfifo_full_thrhd)
|
||||
{
|
||||
UART_MUTEX_LOCK();
|
||||
uart->dev->conf1.rxfifo_full_thrhd = rxfifo_full_thrhd;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uart->dev->conf1.rx_tout_thrhd = 2;
|
||||
#else
|
||||
uart->dev->mem_conf.rx_tout_thrhd = 2;
|
||||
#endif
|
||||
uart->dev->conf1.rx_tout_en = 1;
|
||||
uart->dev->int_ena.rxfifo_full = 1;
|
||||
uart->dev->int_ena.frm_err = 1;
|
||||
uart->dev->int_ena.rxfifo_tout = 1;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
|
||||
esp_intr_alloc(UART_INTR_SOURCE(uart->num), (int)ARDUINO_ISR_FLAG, _uart_isr, NULL, &uart->intr_handle);
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
static void uartDisableInterrupt(uart_t* uart)
|
||||
{
|
||||
UART_MUTEX_LOCK();
|
||||
uart->dev->conf1.val = 0;
|
||||
uart->dev->int_ena.val = 0;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
|
||||
esp_intr_free(uart->intr_handle);
|
||||
uart->intr_handle = NULL;
|
||||
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
static void uartDetachRx(uart_t* uart, uint8_t rxPin)
|
||||
bool uartIsDriverInstalled(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
}
|
||||
pinMatrixInDetach(UART_RXD_IDX(uart->num), false, false);
|
||||
uartDisableInterrupt(uart);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uartDetachTx(uart_t* uart, uint8_t txPin)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
if (uart_is_driver_installed(uart->num)) {
|
||||
return true;
|
||||
}
|
||||
pinMatrixOutDetach(txPin, false, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void uartAttachRx(uart_t* uart, uint8_t rxPin, bool inverted, uint8_t rxfifo_full_thrhd)
|
||||
void uartSetPins(uart_t* uart, uint8_t rxPin, uint8_t txPin)
|
||||
{
|
||||
if(uart == NULL || rxPin >= GPIO_PIN_COUNT) {
|
||||
if(uart == NULL || rxPin >= SOC_GPIO_PIN_COUNT || txPin >= SOC_GPIO_PIN_COUNT) {
|
||||
return;
|
||||
}
|
||||
pinMode(rxPin, INPUT);
|
||||
uartEnableInterrupt(uart, rxfifo_full_thrhd);
|
||||
pinMatrixInAttach(rxPin, UART_RXD_IDX(uart->num), inverted);
|
||||
UART_MUTEX_LOCK();
|
||||
ESP_ERROR_CHECK(uart_set_pin(uart->num, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
}
|
||||
|
||||
static void uartAttachTx(uart_t* uart, uint8_t txPin, bool inverted)
|
||||
{
|
||||
if(uart == NULL || txPin >= GPIO_PIN_COUNT) {
|
||||
return;
|
||||
}
|
||||
pinMode(txPin, OUTPUT);
|
||||
pinMatrixOutAttach(txPin, UART_TXD_IDX(uart->num), inverted, false);
|
||||
}
|
||||
|
||||
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted, uint8_t rxfifo_full_thrhd)
|
||||
{
|
||||
if(uart_nr >= UART_PORTS_NUM) {
|
||||
if(uart_nr >= SOC_UART_NUM) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -222,6 +105,10 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
|
||||
|
||||
uart_t* uart = &_uart_bus_array[uart_nr];
|
||||
|
||||
if (uart_is_driver_installed(uart_nr)) {
|
||||
uartEnd(uart);
|
||||
}
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(uart->lock == NULL) {
|
||||
uart->lock = xSemaphoreCreateMutex();
|
||||
@ -231,190 +118,144 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
|
||||
}
|
||||
#endif
|
||||
|
||||
if(queueLen && uart->queue == NULL) {
|
||||
uart->queue = xQueueCreate(queueLen, sizeof(uint8_t)); //initialize the queue
|
||||
if(uart->queue == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
#else
|
||||
if(uart_nr == 1){
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART1_RST);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
} else if(uart_nr == 2){
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART2_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART2_RST);
|
||||
#endif
|
||||
} else {
|
||||
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART_CLK_EN);
|
||||
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART_RST);
|
||||
}
|
||||
#endif
|
||||
uartFlush(uart);
|
||||
uartSetBaudRate(uart, baudrate);
|
||||
UART_MUTEX_LOCK();
|
||||
uart->dev->conf0.val = config;
|
||||
#define TWO_STOP_BITS_CONF 0x3
|
||||
#define ONE_STOP_BITS_CONF 0x1
|
||||
|
||||
if ( uart->dev->conf0.stop_bit_num == TWO_STOP_BITS_CONF) {
|
||||
uart->dev->conf0.stop_bit_num = ONE_STOP_BITS_CONF;
|
||||
uart->dev->rs485_conf.dl1_en = 1;
|
||||
uart_config_t uart_config;
|
||||
uart_config.baud_rate = baudrate;
|
||||
uart_config.data_bits = (config & 0xc) >> 2;
|
||||
uart_config.parity = (config & 0x3);
|
||||
uart_config.stop_bits = (config & 0x30) >> 4;
|
||||
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
|
||||
uart_config.rx_flow_ctrl_thresh = rxfifo_full_thrhd;
|
||||
uart_config.source_clk = UART_SCLK_APB;
|
||||
|
||||
|
||||
ESP_ERROR_CHECK(uart_driver_install(uart_nr, 2*queueLen, 0, 0, NULL, 0));
|
||||
ESP_ERROR_CHECK(uart_param_config(uart_nr, &uart_config));
|
||||
ESP_ERROR_CHECK(uart_set_pin(uart_nr, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||
|
||||
// Is it right or the idea is to swap rx and tx pins?
|
||||
if (inverted) {
|
||||
// invert signal for both Rx and Tx
|
||||
ESP_ERROR_CHECK(uart_set_line_inverse(uart_nr, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV));
|
||||
}
|
||||
|
||||
// tx_idle_num : idle interval after tx FIFO is empty(unit: the time it takes to send one bit under current baudrate)
|
||||
// Setting it to 0 prevents line idle time/delays when sending messages with small intervals
|
||||
uart->dev->idle_conf.tx_idle_num = 0; //
|
||||
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
if(rxPin != -1) {
|
||||
uartAttachRx(uart, rxPin, inverted, rxfifo_full_thrhd);
|
||||
}
|
||||
|
||||
if(txPin != -1) {
|
||||
uartAttachTx(uart, txPin, inverted);
|
||||
}
|
||||
addApbChangeCallback(uart, uart_on_apb_change);
|
||||
uartFlush(uart);
|
||||
return uart;
|
||||
}
|
||||
|
||||
void uartEnd(uart_t* uart, uint8_t txPin, uint8_t rxPin)
|
||||
void uartEnd(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
}
|
||||
removeApbChangeCallback(uart, uart_on_apb_change);
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
if(uart->queue != NULL) {
|
||||
vQueueDelete(uart->queue);
|
||||
uart->queue = NULL;
|
||||
}
|
||||
|
||||
uart->dev->conf0.val = 0;
|
||||
|
||||
uart_driver_delete(uart->num);
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
uartDetachRx(uart, rxPin);
|
||||
uartDetachTx(uart, txPin);
|
||||
}
|
||||
|
||||
size_t uartResizeRxBuffer(uart_t * uart, size_t new_size) {
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
if(uart->queue != NULL) {
|
||||
vQueueDelete(uart->queue);
|
||||
uart->queue = xQueueCreate(new_size, sizeof(uint8_t));
|
||||
if(uart->queue == NULL) {
|
||||
UART_MUTEX_UNLOCK();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
return new_size;
|
||||
}
|
||||
|
||||
void uartSetRxInvert(uart_t* uart, bool invert)
|
||||
{
|
||||
if (uart == NULL)
|
||||
return;
|
||||
|
||||
#if 0
|
||||
// POTENTIAL ISSUE :: original code only set/reset rxd_inv bit
|
||||
// IDF or LL set/reset the whole inv_mask!
|
||||
if (invert)
|
||||
uart->dev->conf0.rxd_inv = 1;
|
||||
ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_RXD_INV));
|
||||
else
|
||||
uart->dev->conf0.rxd_inv = 0;
|
||||
ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_INV_DISABLE));
|
||||
|
||||
#else
|
||||
// this implementation is better over IDF API because it only affects RXD
|
||||
// this is supported in ESP32, ESP32-S2 and ESP32-C3
|
||||
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||
if (invert)
|
||||
hw->conf0.rxd_inv = 1;
|
||||
else
|
||||
hw->conf0.rxd_inv = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint32_t uartAvailable(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || uart->queue == NULL) {
|
||||
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
#ifdef UART_READ_RX_FIFO
|
||||
return (uxQueueMessagesWaiting(uart->queue) + uart->dev->status.rxfifo_cnt) ;
|
||||
#else
|
||||
return uxQueueMessagesWaiting(uart->queue);
|
||||
#endif
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
size_t available;
|
||||
uart_get_buffered_data_len(uart->num, &available);
|
||||
if (uart->has_peek) available++;
|
||||
UART_MUTEX_UNLOCK();
|
||||
return available;
|
||||
}
|
||||
|
||||
|
||||
uint32_t uartAvailableForWrite(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return 0x7f - uart->dev->status.txfifo_cnt;
|
||||
UART_MUTEX_LOCK();
|
||||
uint32_t available = uart_ll_get_txfifo_len(UART_LL_GET_HW(uart->num));
|
||||
UART_MUTEX_UNLOCK();
|
||||
return available;
|
||||
}
|
||||
|
||||
#ifdef UART_READ_RX_FIFO
|
||||
void uartRxFifoToQueue(uart_t* uart)
|
||||
{
|
||||
uint8_t c;
|
||||
UART_MUTEX_LOCK();
|
||||
//disable interrupts
|
||||
uart->dev->int_ena.val = 0;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while (uart->dev->status.rxfifo_cnt || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
||||
c = uart->dev->fifo.rw_byte;
|
||||
#else
|
||||
uint32_t fifo_reg = UART_FIFO_AHB_REG(uart->num);
|
||||
while (uart->dev->status.rxfifo_cnt) {
|
||||
c = ESP_REG(fifo_reg);
|
||||
#endif
|
||||
xQueueSend(uart->queue, &c, 0);
|
||||
}
|
||||
//enable interrupts
|
||||
uart->dev->int_ena.rxfifo_full = 1;
|
||||
uart->dev->int_ena.frm_err = 1;
|
||||
uart->dev->int_ena.rxfifo_tout = 1;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t uartRead(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || uart->queue == NULL) {
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t c;
|
||||
#ifdef UART_READ_RX_FIFO
|
||||
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
|
||||
{
|
||||
uartRxFifoToQueue(uart);
|
||||
uint8_t c = 0;
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
|
||||
if (uart->has_peek) {
|
||||
uart->has_peek = false;
|
||||
c = uart->peek_byte;
|
||||
} else {
|
||||
|
||||
int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_RATE_MS);
|
||||
if (len == 0) {
|
||||
c = 0;
|
||||
}
|
||||
#endif
|
||||
if(xQueueReceive(uart->queue, &c, 0)) {
|
||||
}
|
||||
UART_MUTEX_UNLOCK();
|
||||
return c;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t uartPeek(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || uart->queue == NULL) {
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t c;
|
||||
#ifdef UART_READ_RX_FIFO
|
||||
if ((uxQueueMessagesWaiting(uart->queue) == 0) && (uart->dev->status.rxfifo_cnt > 0))
|
||||
{
|
||||
uartRxFifoToQueue(uart);
|
||||
uint8_t c = 0;
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
|
||||
if (uart->has_peek) {
|
||||
c = uart->peek_byte;
|
||||
} else {
|
||||
int len = uart_read_bytes(uart->num, &c, 1, 20 / portTICK_RATE_MS);
|
||||
if (len == 0) {
|
||||
c = 0;
|
||||
} else {
|
||||
uart->has_peek = true;
|
||||
uart->peek_byte = c;
|
||||
}
|
||||
#endif
|
||||
if(xQueuePeek(uart->queue, &c, 0)) {
|
||||
}
|
||||
UART_MUTEX_UNLOCK();
|
||||
return c;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uartWrite(uart_t* uart, uint8_t c)
|
||||
{
|
||||
@ -422,12 +263,7 @@ void uartWrite(uart_t* uart, uint8_t c)
|
||||
return;
|
||||
}
|
||||
UART_MUTEX_LOCK();
|
||||
while(uart->dev->status.txfifo_cnt >= 0x7E);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uart->dev->fifo.rw_byte = c;
|
||||
#else
|
||||
ESP_REG(UART_FIFO_AHB_REG(uart->num)) = c;
|
||||
#endif
|
||||
uart_write_bytes(uart->num, &c, 1);
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -436,19 +272,9 @@ void uartWriteBuf(uart_t* uart, const uint8_t * data, size_t len)
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32
|
||||
uint32_t fifo_reg = UART_FIFO_AHB_REG(uart->num);
|
||||
#endif
|
||||
while(len) {
|
||||
while(uart->dev->status.txfifo_cnt >= 0x7E);
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uart->dev->fifo.rw_byte = *data++;
|
||||
#else
|
||||
ESP_REG(fifo_reg) = *data++;
|
||||
#endif
|
||||
len--;
|
||||
}
|
||||
uart_write_bytes(uart->num, data, len);
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -464,26 +290,11 @@ void uartFlushTxOnly(uart_t* uart, bool txOnly)
|
||||
}
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
|
||||
ESP_ERROR_CHECK(uart_wait_tx_done(uart->num, portMAX_DELAY));
|
||||
|
||||
if ( !txOnly ) {
|
||||
//Due to hardware issue, we can not use fifo_rst to reset uart fifo.
|
||||
//See description about UART_TXFIFO_RST and UART_RXFIFO_RST in <<esp32_technical_reference_manual>> v2.6 or later.
|
||||
|
||||
// we read the data out and make `fifo_len == 0 && rd_addr == wr_addr`.
|
||||
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
||||
READ_PERI_REG(UART_FIFO_REG(uart->num));
|
||||
ESP_ERROR_CHECK(uart_flush_input(uart->num));
|
||||
}
|
||||
|
||||
xQueueReset(uart->queue);
|
||||
}
|
||||
#else
|
||||
while(uart->dev->status.txfifo_cnt);
|
||||
uart->dev->conf0.txfifo_rst = 1;
|
||||
uart->dev->conf0.txfifo_rst = 0;
|
||||
#endif
|
||||
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
@ -493,100 +304,41 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate)
|
||||
return;
|
||||
}
|
||||
UART_MUTEX_LOCK();
|
||||
uart_ll_set_baudrate(uart->dev, baud_rate);
|
||||
uart_ll_set_baudrate(UART_LL_GET_HW(uart->num), baud_rate);
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
|
||||
static void uart_on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb)
|
||||
{
|
||||
uart_t* uart = (uart_t*)arg;
|
||||
if(ev_type == APB_BEFORE_CHANGE){
|
||||
UART_MUTEX_LOCK();
|
||||
//disabple interrupt
|
||||
uart->dev->int_ena.val = 0;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
// read RX fifo
|
||||
uint8_t c;
|
||||
// BaseType_t xHigherPriorityTaskWoken;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while(uart->dev->status.rxfifo_cnt != 0 || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
|
||||
c = uart->dev->fifo.rw_byte;
|
||||
#else
|
||||
uint32_t fifo_reg = UART_FIFO_AHB_REG(uart->num);
|
||||
while(uart->dev->status.rxfifo_cnt != 0) {
|
||||
c = ESP_REG(fifo_reg);
|
||||
#endif
|
||||
if(uart->queue != NULL ) {
|
||||
xQueueSend(uart->queue, &c, 1); //&xHigherPriorityTaskWoken);
|
||||
}
|
||||
}
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
// wait TX empty
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while(uart->dev->status.txfifo_cnt || uart->dev->status.st_utx_out);
|
||||
#else
|
||||
while(uart->dev->status.txfifo_cnt);
|
||||
#endif
|
||||
} else {
|
||||
//todo:
|
||||
// set baudrate
|
||||
UART_MUTEX_LOCK();
|
||||
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
|
||||
uint32_t baud_rate = ((old_apb<<4)/clk_div);
|
||||
clk_div = ((new_apb<<4)/baud_rate);
|
||||
uart->dev->clk_div.div_int = clk_div>>4 ;
|
||||
uart->dev->clk_div.div_frag = clk_div & 0xf;
|
||||
//enable interrupts
|
||||
uart->dev->int_ena.rxfifo_full = 1;
|
||||
uart->dev->int_ena.frm_err = 1;
|
||||
uart->dev->int_ena.rxfifo_tout = 1;
|
||||
uart->dev->int_clr.val = 0xffffffff;
|
||||
UART_MUTEX_UNLOCK();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t uartGetBaudRate(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t clk_div = (uart->dev->clk_div.div_int << 4) | (uart->dev->clk_div.div_frag & 0x0F);
|
||||
if(!clk_div) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ((getApbFrequency()<<4)/clk_div);
|
||||
UART_MUTEX_LOCK();
|
||||
uint32_t baud_rate = uart_ll_get_baudrate(UART_LL_GET_HW(uart->num));
|
||||
UART_MUTEX_UNLOCK();
|
||||
return baud_rate;
|
||||
}
|
||||
|
||||
static void ARDUINO_ISR_ATTR uart0_write_char(char c)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while(((ESP_REG(0x01C+DR_REG_UART_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) >= 0x7E);
|
||||
ESP_REG(DR_REG_UART_BASE) = c;
|
||||
#else
|
||||
while(UART0.status.txfifo_cnt == 0x7F);
|
||||
WRITE_PERI_REG(UART_FIFO_AHB_REG(0), c);
|
||||
#endif
|
||||
while (uart_ll_get_txfifo_len(&UART0) == 0);
|
||||
uart_ll_write_txfifo(&UART0, (const uint8_t *) &c, 1);
|
||||
}
|
||||
|
||||
#if SOC_UART_NUM > 1
|
||||
static void ARDUINO_ISR_ATTR uart1_write_char(char c)
|
||||
{
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
while(((ESP_REG(0x01C+DR_REG_UART1_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) >= 0x7E);
|
||||
ESP_REG(DR_REG_UART1_BASE) = c;
|
||||
#else
|
||||
while(UART1.status.txfifo_cnt == 0x7F);
|
||||
WRITE_PERI_REG(UART_FIFO_AHB_REG(1), c);
|
||||
#endif
|
||||
while (uart_ll_get_txfifo_len(&UART1) == 0);
|
||||
uart_ll_write_txfifo(&UART1, (const uint8_t *) &c, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#if SOC_UART_NUM > 2
|
||||
static void ARDUINO_ISR_ATTR uart2_write_char(char c)
|
||||
{
|
||||
while(((ESP_REG(0x01C+DR_REG_UART2_BASE) >> UART_TXFIFO_CNT_S) & 0x7F) >= 0x7E);
|
||||
ESP_REG(DR_REG_UART2_BASE) = c;
|
||||
while (uart_ll_get_txfifo_len(&UART2) == 0);
|
||||
uart_ll_write_txfifo(&UART2, (const uint8_t *) &c, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -596,10 +348,12 @@ void uart_install_putc()
|
||||
case 0:
|
||||
ets_install_putc1((void (*)(char)) &uart0_write_char);
|
||||
break;
|
||||
#if SOC_UART_NUM > 1
|
||||
case 1:
|
||||
ets_install_putc1((void (*)(char)) &uart1_write_char);
|
||||
break;
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#endif
|
||||
#if SOC_UART_NUM > 2
|
||||
case 2:
|
||||
ets_install_putc1((void (*)(char)) &uart2_write_char);
|
||||
break;
|
||||
@ -612,7 +366,7 @@ void uart_install_putc()
|
||||
|
||||
void uartSetDebug(uart_t* uart)
|
||||
{
|
||||
if(uart == NULL || uart->num >= UART_PORTS_NUM) {
|
||||
if(uart == NULL || uart->num >= SOC_UART_NUM) {
|
||||
s_uart_debug_nr = -1;
|
||||
//ets_install_putc1(NULL);
|
||||
//return;
|
||||
@ -646,17 +400,19 @@ int log_printf(const char *format, ...)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
vsnprintf(temp, len+1, format, arg);
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){
|
||||
xSemaphoreTake(_uart_bus_array[s_uart_debug_nr].lock, portMAX_DELAY);
|
||||
ets_printf("%s", temp);
|
||||
xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock);
|
||||
} else {
|
||||
ets_printf("%s", temp);
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
||||
vsnprintf(temp, len+1, format, arg);
|
||||
ets_printf("%s", temp);
|
||||
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){
|
||||
xSemaphoreGive(_uart_bus_array[s_uart_debug_nr].lock);
|
||||
}
|
||||
#endif
|
||||
va_end(arg);
|
||||
if(len >= sizeof(loc_buf)){
|
||||
@ -665,48 +421,126 @@ int log_printf(const char *format, ...)
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static void log_print_buf_line(const uint8_t *b, size_t len, size_t total_len){
|
||||
for(size_t i = 0; i<len; i++){
|
||||
log_printf("%s0x%02x,",i?" ":"", b[i]);
|
||||
}
|
||||
if(total_len > 16){
|
||||
for(size_t i = len; i<16; i++){
|
||||
log_printf(" ");
|
||||
}
|
||||
log_printf(" // ");
|
||||
} else {
|
||||
log_printf(" // ");
|
||||
}
|
||||
for(size_t i = 0; i<len; i++){
|
||||
log_printf("%c",((b[i] >= 0x20) && (b[i] < 0x80))?b[i]:'.');
|
||||
}
|
||||
log_printf("\n");
|
||||
}
|
||||
|
||||
void log_print_buf(const uint8_t *b, size_t len){
|
||||
if(!len || !b){
|
||||
return;
|
||||
}
|
||||
for(size_t i = 0; i<len; i+=16){
|
||||
if(len > 16){
|
||||
log_printf("/* 0x%04X */ ", i);
|
||||
}
|
||||
log_print_buf_line(b+i, ((len-i)<16)?(len - i):16, len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* if enough pulses are detected return the minimum high pulse duration + minimum low pulse duration divided by two.
|
||||
* This equals one bit period. If flag is true the function return inmediately, otherwise it waits for enough pulses.
|
||||
*/
|
||||
unsigned long uartBaudrateDetect(uart_t *uart, bool flg)
|
||||
{
|
||||
while(uart->dev->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num)
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||
|
||||
while(hw->rxd_cnt.edge_cnt < 30) { // UART_PULSE_NUM(uart_num)
|
||||
if(flg) return 0;
|
||||
ets_delay_us(1000);
|
||||
}
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
unsigned long ret = ((uart->dev->lowpulse.min_cnt + uart->dev->highpulse.min_cnt) >> 1) + 12;
|
||||
//log_i("lowpulse_min_cnt = %d hightpulse_min_cnt = %d", hw->lowpulse.min_cnt, hw->highpulse.min_cnt);
|
||||
unsigned long ret = ((hw->lowpulse.min_cnt + hw->highpulse.min_cnt) >> 1);
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* To start detection of baud rate with the uart the auto_baud.en bit needs to be cleared and set. The bit period is
|
||||
* detected calling uartBadrateDetect(). The raw baudrate is computed using the UART_CLK_FREQ. The raw baudrate is
|
||||
* rounded to the closed real baudrate.
|
||||
*
|
||||
* ESP32-C3 reports wrong baud rate detection as shown below:
|
||||
*
|
||||
* This will help in a future recall for the C3.
|
||||
* Baud Sent: Baud Read:
|
||||
* 300 --> 19536
|
||||
* 2400 --> 19536
|
||||
* 4800 --> 19536
|
||||
* 9600 --> 28818
|
||||
* 19200 --> 57678
|
||||
* 38400 --> 115440
|
||||
* 57600 --> 173535
|
||||
* 115200 --> 347826
|
||||
* 230400 --> 701754
|
||||
*
|
||||
*
|
||||
*/
|
||||
void uartStartDetectBaudrate(uart_t *uart) {
|
||||
if(!uart) return;
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
uart->dev->auto_baud.glitch_filt = 0x08;
|
||||
uart->dev->auto_baud.en = 0;
|
||||
uart->dev->auto_baud.en = 1;
|
||||
if(uart == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
||||
|
||||
// ESP32-C3 requires further testing
|
||||
// Baud rate detection returns wrong values
|
||||
|
||||
log_e("ESP32-C3 baud rate detection is not supported.");
|
||||
return;
|
||||
|
||||
// Code bellow for C3 kept for future recall
|
||||
//hw->rx_filt.glitch_filt = 0x08;
|
||||
//hw->rx_filt.glitch_filt_en = 1;
|
||||
//hw->conf0.autobaud_en = 0;
|
||||
//hw->conf0.autobaud_en = 1;
|
||||
|
||||
#else
|
||||
hw->auto_baud.glitch_filt = 0x08;
|
||||
hw->auto_baud.en = 0;
|
||||
hw->auto_baud.en = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long
|
||||
uartDetectBaudrate(uart_t *uart)
|
||||
{
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3
|
||||
if(uart == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32C3 // ESP32-C3 requires further testing - Baud rate detection returns wrong values
|
||||
|
||||
static bool uartStateDetectingBaudrate = false;
|
||||
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
|
||||
|
||||
if(!uartStateDetectingBaudrate) {
|
||||
uart->dev->auto_baud.glitch_filt = 0x08;
|
||||
uart->dev->auto_baud.en = 0;
|
||||
uart->dev->auto_baud.en = 1;
|
||||
uartStartDetectBaudrate(uart);
|
||||
uartStateDetectingBaudrate = true;
|
||||
}
|
||||
|
||||
@ -714,11 +548,21 @@ uartDetectBaudrate(uart_t *uart)
|
||||
if (!divisor) {
|
||||
return 0;
|
||||
}
|
||||
// log_i(...) below has been used to check C3 baud rate detection results
|
||||
//log_i("Divisor = %d\n", divisor);
|
||||
//log_i("BAUD RATE based on Positive Pulse %d\n", getApbFrequency()/((hw->pospulse.min_cnt + 1)/2));
|
||||
//log_i("BAUD RATE based on Negative Pulse %d\n", getApbFrequency()/((hw->negpulse.min_cnt + 1)/2));
|
||||
|
||||
uart->dev->auto_baud.en = 0;
|
||||
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32C3
|
||||
//hw->conf0.autobaud_en = 0;
|
||||
#else
|
||||
hw->auto_baud.en = 0;
|
||||
#endif
|
||||
uartStateDetectingBaudrate = false; // Initialize for the next round
|
||||
|
||||
unsigned long baudrate = getApbFrequency() / divisor;
|
||||
//log_i("APB_FREQ = %d\nraw baudrate detected = %d", getApbFrequency(), baudrate);
|
||||
|
||||
static const unsigned long default_rates[] = {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 256000, 460800, 921600, 1843200, 3686400};
|
||||
|
||||
@ -736,17 +580,7 @@ uartDetectBaudrate(uart_t *uart)
|
||||
|
||||
return default_rates[i];
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the status of the RX state machine, if the value is non-zero the state machine is active.
|
||||
*/
|
||||
bool uartRxActive(uart_t* uart) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
return uart->dev->status.st_urx_out != 0;
|
||||
#else
|
||||
log_e("ESP32-C3 baud rate detection is not supported.");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ struct uart_struct_t;
|
||||
typedef struct uart_struct_t uart_t;
|
||||
|
||||
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted, uint8_t rxfifo_full_thrhd);
|
||||
void uartEnd(uart_t* uart, uint8_t rxPin, uint8_t txPin);
|
||||
void uartEnd(uart_t* uart);
|
||||
|
||||
uint32_t uartAvailable(uart_t* uart);
|
||||
uint32_t uartAvailableForWrite(uart_t* uart);
|
||||
@ -68,17 +68,17 @@ void uartFlushTxOnly(uart_t* uart, bool txOnly );
|
||||
void uartSetBaudRate(uart_t* uart, uint32_t baud_rate);
|
||||
uint32_t uartGetBaudRate(uart_t* uart);
|
||||
|
||||
size_t uartResizeRxBuffer(uart_t* uart, size_t new_size);
|
||||
|
||||
void uartSetRxInvert(uart_t* uart, bool invert);
|
||||
|
||||
void uartSetDebug(uart_t* uart);
|
||||
int uartGetDebug();
|
||||
|
||||
bool uartIsDriverInstalled(uart_t* uart);
|
||||
void uartSetPins(uart_t* uart, uint8_t rxPin, uint8_t txPin);
|
||||
|
||||
void uartStartDetectBaudrate(uart_t *uart);
|
||||
unsigned long uartDetectBaudrate(uart_t *uart);
|
||||
|
||||
bool uartRxActive(uart_t* uart);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
204
cores/esp32/firmware_msc_fat.c
Normal file
204
cores/esp32/firmware_msc_fat.c
Normal file
@ -0,0 +1,204 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "firmware_msc_fat.h"
|
||||
//copy up to max_len chars from src to dst and do not terminate
|
||||
static size_t cplstr(void *dst, const void * src, size_t max_len){
|
||||
if(!src || !dst || !max_len){
|
||||
return 0;
|
||||
}
|
||||
size_t l = strlen((const char *)src);
|
||||
if(l > max_len){
|
||||
l = max_len;
|
||||
}
|
||||
memcpy(dst, src, l);
|
||||
return l;
|
||||
}
|
||||
|
||||
//copy up to max_len chars from src to dst, adding spaces up to max_len. do not terminate
|
||||
static void cplstrsp(void *dst, const void * src, size_t max_len){
|
||||
size_t l = cplstr(dst, src, max_len);
|
||||
for(; l < max_len; l++){
|
||||
((uint8_t*)dst)[l] = 0x20;
|
||||
}
|
||||
}
|
||||
|
||||
// FAT12
|
||||
static const char * FAT12_FILE_SYSTEM_TYPE = "FAT12";
|
||||
|
||||
static uint16_t fat12_sectors_per_alloc_table(uint32_t sector_num){
|
||||
uint32_t required_bytes = (((sector_num * 3)+1)/2);
|
||||
return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & DISK_SECTOR_SIZE)?1:0);
|
||||
}
|
||||
|
||||
static uint8_t * fat12_add_table(uint8_t * dst, fat_boot_sector_t * boot){
|
||||
memset(dst+DISK_SECTOR_SIZE, 0, boot->sectors_per_alloc_table * DISK_SECTOR_SIZE);
|
||||
uint8_t * d = dst + DISK_SECTOR_SIZE;
|
||||
d[0] = 0xF8;
|
||||
d[1] = 0xFF;
|
||||
d[2] = 0xFF;
|
||||
return d;
|
||||
}
|
||||
|
||||
static void fat12_set_table_index(uint8_t * table, uint16_t index, uint16_t value){
|
||||
uint16_t offset = (index >> 1) * 3;
|
||||
uint8_t * data = table + offset;
|
||||
if(index & 1){
|
||||
data[2] = (value >> 4) & 0xFF;
|
||||
data[1] = (data[1] & 0xF) | ((value & 0xF) << 4);
|
||||
} else {
|
||||
data[0] = value & 0xFF;
|
||||
data[1] = (data[1] & 0xF0) | ((value >> 8) & 0xF);
|
||||
}
|
||||
}
|
||||
|
||||
//FAT16
|
||||
static const char * FAT16_FILE_SYSTEM_TYPE = "FAT16";
|
||||
|
||||
static uint16_t fat16_sectors_per_alloc_table(uint32_t sector_num){
|
||||
uint32_t required_bytes = sector_num * 2;
|
||||
return (required_bytes / DISK_SECTOR_SIZE) + ((required_bytes & DISK_SECTOR_SIZE)?1:0);
|
||||
}
|
||||
|
||||
static uint8_t * fat16_add_table(uint8_t * dst, fat_boot_sector_t * boot){
|
||||
memset(dst+DISK_SECTOR_SIZE, 0, boot->sectors_per_alloc_table * DISK_SECTOR_SIZE);
|
||||
uint16_t * d = (uint16_t *)(dst + DISK_SECTOR_SIZE);
|
||||
d[0] = 0xFFF8;
|
||||
d[1] = 0xFFFF;
|
||||
return (uint8_t *)d;
|
||||
}
|
||||
|
||||
static void fat16_set_table_index(uint8_t * table, uint16_t index, uint16_t value){
|
||||
uint16_t offset = index * 2;
|
||||
*(uint16_t *)(table + offset) = value;
|
||||
}
|
||||
|
||||
//Interface
|
||||
const char * fat_file_system_type(bool fat16) {
|
||||
return ((fat16)?FAT16_FILE_SYSTEM_TYPE:FAT12_FILE_SYSTEM_TYPE);
|
||||
}
|
||||
|
||||
uint16_t fat_sectors_per_alloc_table(uint32_t sector_num, bool fat16){
|
||||
if(fat16){
|
||||
return fat16_sectors_per_alloc_table(sector_num);
|
||||
}
|
||||
return fat12_sectors_per_alloc_table(sector_num);
|
||||
}
|
||||
|
||||
uint8_t * fat_add_table(uint8_t * dst, fat_boot_sector_t * boot, bool fat16){
|
||||
if(fat16){
|
||||
return fat16_add_table(dst, boot);
|
||||
}
|
||||
return fat12_add_table(dst, boot);
|
||||
}
|
||||
|
||||
void fat_set_table_index(uint8_t * table, uint16_t index, uint16_t value, bool fat16){
|
||||
if(fat16){
|
||||
fat16_set_table_index(table, index, value);
|
||||
} else {
|
||||
fat12_set_table_index(table, index, value);
|
||||
}
|
||||
}
|
||||
|
||||
fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint16_t table_sectors, const char * file_system_type, const char * volume_label, uint32_t serial_number){
|
||||
fat_boot_sector_t *boot = (fat_boot_sector_t*)dst;
|
||||
boot->jump_instruction[0] = 0xEB;
|
||||
boot->jump_instruction[1] = 0x3C;
|
||||
boot->jump_instruction[2] = 0x90;
|
||||
cplstr(boot->oem_name, "MSDOS5.0", 8);
|
||||
boot->bytes_per_sector = DISK_SECTOR_SIZE;
|
||||
boot->sectors_per_cluster = 1;
|
||||
boot->reserved_sectors_count = 1;
|
||||
boot->file_alloc_tables_num = 1;
|
||||
boot->max_root_dir_entries = 16;
|
||||
boot->fat12_sector_num = sector_num;
|
||||
boot->media_descriptor = 0xF8;
|
||||
boot->sectors_per_alloc_table = table_sectors;
|
||||
boot->sectors_per_track = 1;
|
||||
boot->num_heads = 1;
|
||||
boot->hidden_sectors_count = 0;
|
||||
boot->total_sectors_32 = 0;
|
||||
boot->physical_drive_number = 0x00;
|
||||
boot->reserved0 = 0x00;
|
||||
boot->extended_boot_signature = 0x29;
|
||||
boot->serial_number = serial_number;
|
||||
cplstrsp(boot->volume_label, volume_label, 11);
|
||||
memset(boot->reserved, 0, 448);
|
||||
cplstrsp(boot->file_system_type, file_system_type, 8);
|
||||
boot->signature = 0xAA55;
|
||||
return boot;
|
||||
}
|
||||
|
||||
fat_dir_entry_t * fat_add_label(uint8_t * dst, const char * volume_label){
|
||||
fat_boot_sector_t * boot = (fat_boot_sector_t *)dst;
|
||||
fat_dir_entry_t * entry = (fat_dir_entry_t *)(dst + ((boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE));
|
||||
memset(entry, 0, sizeof(fat_dir_entry_t));
|
||||
cplstrsp(entry->volume_label, volume_label, 11);
|
||||
entry->file_attr = FAT_FILE_ATTR_VOLUME_LABEL;
|
||||
return entry;
|
||||
}
|
||||
|
||||
fat_dir_entry_t * fat_add_root_file(uint8_t * dst, uint8_t index, const char * file_name, const char * file_extension, size_t file_size, uint16_t data_start_sector, bool is_fat16){
|
||||
fat_boot_sector_t * boot = (fat_boot_sector_t *)dst;
|
||||
uint8_t * table = dst + DISK_SECTOR_SIZE;
|
||||
fat_dir_entry_t * entry = (fat_dir_entry_t *)(dst + ((boot->sectors_per_alloc_table+1) * DISK_SECTOR_SIZE) + (index * sizeof(fat_dir_entry_t)));
|
||||
memset(entry, 0, sizeof(fat_dir_entry_t));
|
||||
cplstrsp(entry->file_name, file_name, 8);
|
||||
cplstrsp(entry->file_extension, file_extension, 3);
|
||||
entry->file_attr = FAT_FILE_ATTR_ARCHIVE;
|
||||
entry->file_size = file_size;
|
||||
entry->data_start_sector = data_start_sector;
|
||||
entry->extended_attr = 0;
|
||||
|
||||
uint16_t file_sectors = file_size / DISK_SECTOR_SIZE;
|
||||
if(file_size % DISK_SECTOR_SIZE){
|
||||
file_sectors++;
|
||||
}
|
||||
|
||||
uint16_t data_end_sector = data_start_sector + file_sectors;
|
||||
for(uint16_t i=data_start_sector; i<(data_end_sector-1); i++){
|
||||
fat_set_table_index(table, i, i+1, is_fat16);
|
||||
}
|
||||
fat_set_table_index(table, data_end_sector-1, 0xFFFF, is_fat16);
|
||||
|
||||
//Set Firmware Date based on the build time
|
||||
static const char * month_names_short[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
char mstr[8] = {'\0',};
|
||||
const char *str = __DATE__ " " __TIME__;
|
||||
int ms=0, seconds=0, minutes=0, hours=0, year=0, date=0, month=0;
|
||||
int r = sscanf(str,"%s %d %d %d:%d:%d", mstr, &date, &year, &hours, &minutes, &seconds);
|
||||
if(r >= 0){
|
||||
for(int i=0; i<12; i++){
|
||||
if(!strcmp(mstr, month_names_short[i])){
|
||||
month = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
entry->creation_time_ms = FAT_MS2V(seconds, ms);
|
||||
entry->creation_time_hms = FAT_HMS2V(hours, minutes, seconds);
|
||||
entry->creation_time_ymd = FAT_YMD2V(year, month, date);
|
||||
entry->last_access_ymd = entry->creation_time_ymd;
|
||||
entry->last_modified_hms = entry->creation_time_hms;
|
||||
entry->last_modified_ymd = entry->creation_time_ymd;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
uint8_t fat_lfn_checksum(const uint8_t *short_filename){
|
||||
uint8_t sum = 0;
|
||||
for (uint8_t i = 11; i; i--) {
|
||||
sum = ((sum & 1) << 7) + (sum >> 1) + *short_filename++;
|
||||
}
|
||||
return sum;
|
||||
}
|
141
cores/esp32/firmware_msc_fat.h
Normal file
141
cores/esp32/firmware_msc_fat.h
Normal file
@ -0,0 +1,141 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define FAT_U8(v) ((v) & 0xFF)
|
||||
#define FAT_U16(v) FAT_U8(v), FAT_U8((v) >> 8)
|
||||
#define FAT_U32(v) FAT_U8(v), FAT_U8((v) >> 8), FAT_U8((v) >> 16), FAT_U8((v) >> 24)
|
||||
|
||||
#define FAT12_TBL2B(l,h) FAT_U8(l), FAT_U8(((l >> 8) & 0xF) | ((h << 4) & 0xF0)), FAT_U8(h >> 4)
|
||||
|
||||
#define FAT_MS2B(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10)
|
||||
#define FAT_HMS2B(h,m,s) FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x7)|((h) << 3))
|
||||
#define FAT_YMD2B(y,m,d) FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1))
|
||||
|
||||
#define FAT_MS2V(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10)
|
||||
#define FAT_HMS2V(h,m,s) (FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x7)|((h) << 3)) << 8))
|
||||
#define FAT_YMD2V(y,m,d) (FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)) | (FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1)) << 8))
|
||||
|
||||
#define FAT_B2HMS(hms) ((hms >> 11) & 0x1F), ((hms >> 5) & 0x3F), ((hms & 0x1F) << 1)
|
||||
#define FAT_B2YMD(ymd) (((ymd >> 9) & 0x7F) + 1980), ((ymd >> 5) & 0x0F), (ymd & 0x1F)
|
||||
|
||||
#define FAT_FILE_ATTR_READ_ONLY 0x01
|
||||
#define FAT_FILE_ATTR_HIDDEN 0x02
|
||||
#define FAT_FILE_ATTR_SYSTEM 0x04
|
||||
#define FAT_FILE_ATTR_VOLUME_LABEL 0x08
|
||||
#define FAT_FILE_ATTR_SUBDIRECTORY 0x10
|
||||
#define FAT_FILE_ATTR_ARCHIVE 0x20
|
||||
#define FAT_FILE_ATTR_DEVICE 0x40
|
||||
|
||||
static const uint16_t DISK_SECTOR_SIZE = 512;
|
||||
|
||||
#define FAT_SIZE_TO_SECTORS(bytes) ((bytes) / DISK_SECTOR_SIZE) + (((bytes) % DISK_SECTOR_SIZE)?1:0)
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint8_t jump_instruction[3];
|
||||
char oem_name[8];//padded with spaces (0x20)
|
||||
uint16_t bytes_per_sector;//DISK_SECTOR_SIZE usually 512
|
||||
uint8_t sectors_per_cluster;//Allowed values are 1, 2, 4, 8, 16, 32, 64, and 128
|
||||
uint16_t reserved_sectors_count;//At least 1 for this sector, usually 32 for FAT32
|
||||
uint8_t file_alloc_tables_num;//Almost always 2; RAM disks might use 1
|
||||
uint16_t max_root_dir_entries;//FAT12 and FAT16
|
||||
uint16_t fat12_sector_num;//DISK_SECTOR_NUM FAT12 and FAT16
|
||||
uint8_t media_descriptor;
|
||||
uint16_t sectors_per_alloc_table;//FAT12 and FAT16
|
||||
uint16_t sectors_per_track;//A value of 0 may indicate LBA-only access
|
||||
uint16_t num_heads;
|
||||
uint32_t hidden_sectors_count;
|
||||
uint32_t total_sectors_32;
|
||||
uint8_t physical_drive_number;//0x00 for (first) removable media, 0x80 for (first) fixed disk
|
||||
uint8_t reserved0;
|
||||
uint8_t extended_boot_signature;//should be 0x29
|
||||
uint32_t serial_number;//0x1234 => 1234
|
||||
char volume_label[11];//padded with spaces (0x20)
|
||||
char file_system_type[8];//padded with spaces (0x20)
|
||||
uint8_t reserved[448];
|
||||
uint16_t signature;//should be 0xAA55
|
||||
} fat_boot_sector_t;
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
union {
|
||||
struct {
|
||||
char file_name[8];//padded with spaces (0x20)
|
||||
char file_extension[3];//padded with spaces (0x20)
|
||||
};
|
||||
struct {
|
||||
uint8_t file_magic;// 0xE5:deleted, 0x05:will_be_deleted, 0x00:end_marker, 0x2E:dot_marker(. or ..)
|
||||
char file_magic_data[10];
|
||||
};
|
||||
char volume_label[11];//padded with spaces (0x20)
|
||||
};
|
||||
uint8_t file_attr;//mask of FAT_FILE_ATTR_*
|
||||
uint8_t reserved;//always 0
|
||||
uint8_t creation_time_ms;//ms * 10; max 1990 (1s 990ms)
|
||||
uint16_t creation_time_hms; // [5:6:5] => h:m:(s/2)
|
||||
uint16_t creation_time_ymd; // [7:4:5] => (y+1980):m:d
|
||||
uint16_t last_access_ymd;
|
||||
uint16_t extended_attr;
|
||||
uint16_t last_modified_hms;
|
||||
uint16_t last_modified_ymd;
|
||||
uint16_t data_start_sector;
|
||||
uint32_t file_size;
|
||||
} fat_dir_entry_t;
|
||||
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
union {
|
||||
struct {
|
||||
uint8_t number:5;
|
||||
uint8_t reserved0:1;
|
||||
uint8_t llfp:1;
|
||||
uint8_t reserved1:1;
|
||||
} seq;
|
||||
uint8_t seq_num; //0xE5: Deleted Entry
|
||||
};
|
||||
uint16_t name0[5];
|
||||
uint8_t attr; //ALWAYS 0x0F
|
||||
uint8_t type; //ALWAYS 0x00
|
||||
uint8_t dos_checksum;
|
||||
uint16_t name1[6];
|
||||
uint16_t first_cluster; //ALWAYS 0x0000
|
||||
uint16_t name2[2];
|
||||
} fat_lfn_entry_t;
|
||||
|
||||
typedef union {
|
||||
fat_dir_entry_t dir;
|
||||
fat_lfn_entry_t lfn;
|
||||
} fat_entry_t;
|
||||
|
||||
const char * fat_file_system_type(bool fat16);
|
||||
uint16_t fat_sectors_per_alloc_table(uint32_t sector_num, bool fat16);
|
||||
uint8_t * fat_add_table(uint8_t * dst, fat_boot_sector_t * boot, bool fat16);
|
||||
void fat_set_table_index(uint8_t * table, uint16_t index, uint16_t value, bool fat16);
|
||||
fat_boot_sector_t * fat_add_boot_sector(uint8_t * dst, uint16_t sector_num, uint16_t table_sectors, const char * file_system_type, const char * volume_label, uint32_t serial_number);
|
||||
fat_dir_entry_t * fat_add_label(uint8_t * dst, const char * volume_label);
|
||||
fat_dir_entry_t * fat_add_root_file(uint8_t * dst, uint8_t index, const char * file_name, const char * file_extension, size_t file_size, uint16_t data_start_sector, bool is_fat16);
|
||||
uint8_t fat_lfn_checksum(const uint8_t *short_filename);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -2,8 +2,11 @@
|
||||
#include "freertos/task.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "Arduino.h"
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
#if (ARDUINO_USB_CDC_ON_BOOT|ARDUINO_USB_MSC_ON_BOOT|ARDUINO_USB_DFU_ON_BOOT)
|
||||
#include "USB.h"
|
||||
#if ARDUINO_USB_MSC_ON_BOOT
|
||||
#include "FirmwareMSC.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ARDUINO_LOOP_STACK_SIZE
|
||||
@ -47,9 +50,17 @@ void loopTask(void *pvParameters)
|
||||
|
||||
extern "C" void app_main()
|
||||
{
|
||||
#if ARDUINO_SERIAL_PORT //Serial used for USB CDC
|
||||
USB.begin();
|
||||
#if ARDUINO_USB_CDC_ON_BOOT
|
||||
Serial.begin();
|
||||
#endif
|
||||
#if ARDUINO_USB_MSC_ON_BOOT
|
||||
MSC_Update.begin();
|
||||
#endif
|
||||
#if ARDUINO_USB_DFU_ON_BOOT
|
||||
USB.enableDFU();
|
||||
#endif
|
||||
#if ARDUINO_USB_ON_BOOT
|
||||
USB.begin();
|
||||
#endif
|
||||
loopTaskWDTEnabled = false;
|
||||
initArduino();
|
||||
|
@ -30,8 +30,7 @@
|
||||
#include "stdlib_noniso.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
#if !CONFIG_DSP_ANSI && !CONFIG_DSP_OPTIMIZED
|
||||
void reverse(char* begin, char* end) {
|
||||
static void reverse(char* begin, char* end) {
|
||||
char *is = begin;
|
||||
char *ie = end - 1;
|
||||
while(is < ie) {
|
||||
@ -42,9 +41,6 @@ void reverse(char* begin, char* end) {
|
||||
--ie;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void reverse(char* begin, char* end);
|
||||
#endif
|
||||
|
||||
char* ltoa(long value, char* result, int base) {
|
||||
if(base < 2 || base > 16) {
|
||||
|
@ -17,13 +17,11 @@
|
||||
//#include <limits.h>
|
||||
#include "wiring_private.h"
|
||||
#include "pins_arduino.h"
|
||||
|
||||
|
||||
extern uint32_t xthal_get_ccount();
|
||||
#include <hal/cpu_hal.h>
|
||||
|
||||
#define WAIT_FOR_PIN_STATE(state) \
|
||||
while (digitalRead(pin) != (state)) { \
|
||||
if (xthal_get_ccount() - start_cycle_count > timeout_cycles) { \
|
||||
if (cpu_hal_get_cycle_count() - start_cycle_count > timeout_cycles) { \
|
||||
return 0; \
|
||||
} \
|
||||
}
|
||||
@ -36,12 +34,12 @@ unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
|
||||
timeout = max_timeout_us;
|
||||
}
|
||||
const uint32_t timeout_cycles = microsecondsToClockCycles(timeout);
|
||||
const uint32_t start_cycle_count = xthal_get_ccount();
|
||||
const uint32_t start_cycle_count = cpu_hal_get_cycle_count();
|
||||
WAIT_FOR_PIN_STATE(!state);
|
||||
WAIT_FOR_PIN_STATE(state);
|
||||
const uint32_t pulse_start_cycle_count = xthal_get_ccount();
|
||||
const uint32_t pulse_start_cycle_count = cpu_hal_get_cycle_count();
|
||||
WAIT_FOR_PIN_STATE(!state);
|
||||
return clockCyclesToMicroseconds(xthal_get_ccount() - pulse_start_cycle_count);
|
||||
return clockCyclesToMicroseconds(cpu_hal_get_cycle_count() - pulse_start_cycle_count);
|
||||
}
|
||||
|
||||
unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout)
|
||||
|
@ -81,6 +81,12 @@ Add here the third party boards, listed by vendors.
|
||||
creating an `issue on GitHub <https://github.com/espressif/arduino-esp32/issues>`_ and directly
|
||||
link/mention the vendor in the issue description.
|
||||
|
||||
LOLIN
|
||||
*****
|
||||
|
||||
* |board_lolin_d32|
|
||||
* |board_lolin_d32_pro|
|
||||
|
||||
Generic Vendor
|
||||
**************
|
||||
|
||||
@ -104,3 +110,11 @@ Resources
|
||||
.. _ESP32 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf
|
||||
.. _ESP32-S2 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-s2_datasheet_en.pdf
|
||||
.. _ESP32-C3 Datasheet: https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf
|
||||
|
||||
.. |board_lolin_d32| raw:: html
|
||||
|
||||
<a href="https://www.wemos.cc/en/latest/d32/d32.html" target="_blank">LOLIN D32</a>
|
||||
|
||||
.. |board_lolin_d32_pro| raw:: html
|
||||
|
||||
<a href="https://www.wemos.cc/en/latest/d32/d32_pro.html" target="_blank">LOLIN D32 Pro</a>
|
@ -56,7 +56,7 @@ exclude_patterns = []
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'default'
|
||||
html_logo = 'logo_espressif.png'
|
||||
html_logo = '_static/logo_espressif.png'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
|
@ -1,5 +1,5 @@
|
||||
###############
|
||||
Troubleshotting
|
||||
Troubleshooting
|
||||
###############
|
||||
|
||||
Common Issues
|
||||
@ -18,10 +18,36 @@ Building
|
||||
Flashing
|
||||
--------
|
||||
|
||||
* The board is not flashing.
|
||||
Why is my board not flashing/uploading when I try to upload my sketch?
|
||||
**********************************************************************
|
||||
|
||||
If you are trying to upload a new sketch and your board isn't responding, there are some possible reasons.
|
||||
To be able to upload the sketch via serial interface, the ESP32 must be in the download mode. The download mode allows you to upload the sketch over the serial port and to get into it, you need to keep the **GPIO0** in LOW while a resetting (**EN** pin) cycle.
|
||||
|
||||
Possible fatal error message from the Arduino IDE:
|
||||
|
||||
*A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header*
|
||||
|
||||
Here are some steps that you can try to:
|
||||
|
||||
* Check your USB cable and try a new one.
|
||||
* Change the USB port.
|
||||
* Check your power supply.
|
||||
* In some instances, you must keep **GPIO0** LOW during the uploading process via serial interface.
|
||||
* Hold-down the **“BOOT”** button in your ESP32 board while uploading/flashing.
|
||||
|
||||
In some development boards, you can try adding the reset delay circuit, as decribed in the *Power-on Sequence* section on the `ESP32 Hardware Design Guidelines <https://www.espressif.com/sites/default/files/documentation/esp32_hardware_design_guidelines_en.pdf>`_ in order to get into the download mode automatically.
|
||||
|
||||
Hardware
|
||||
--------
|
||||
|
||||
* Power Source
|
||||
* Bad USB cable or charging only cables
|
||||
Why is my computer not detecting my board?
|
||||
**************************************************
|
||||
|
||||
If your board is not detected after connecting into the USB, you can try to:
|
||||
|
||||
* Check if the USB driver is missing. - `USB Driver Download Link <https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers>`_
|
||||
* Check your USB cable and try a new one.
|
||||
* Change the USB port.
|
||||
* Check your power supply.
|
||||
* Check if the board is damaged or defective.
|
||||
|
@ -347,7 +347,7 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef CLASSIC_BT_ENABLED
|
||||
#ifndef CONFIG_BT_CLASSIC_ENABLED
|
||||
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
#endif
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
@ -357,7 +357,7 @@ gatts_event_handler BLEDevice::m_customGattsHandler = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef CLASSIC_BT_ENABLED
|
||||
#ifndef CONFIG_BT_CLASSIC_ENABLED
|
||||
errRc = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (errRc != ESP_OK) {
|
||||
log_e("esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc));
|
||||
|
@ -148,6 +148,10 @@ void setup(){
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
Serial.println("Contacting Time Server");
|
||||
/*
|
||||
Note: Bundled Arduino lwip supports only ONE ntp server, 2nd and 3rd options are silently ignored
|
||||
see CONFIG_LWIP_DHCP_MAX_NTP_SERVERS define in ./tools/sdk/esp32/sdkconfig
|
||||
*/
|
||||
configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
|
||||
struct tm tmstruct ;
|
||||
delay(2000);
|
||||
|
@ -1264,6 +1264,8 @@ int HTTPClient::handleHeaderResponse()
|
||||
log_d("Transfer-Encoding: %s", transferEncoding.c_str());
|
||||
if(transferEncoding.equalsIgnoreCase("chunked")) {
|
||||
_transferEncoding = HTTPC_TE_CHUNKED;
|
||||
} else if(transferEncoding.equalsIgnoreCase("identity")) {
|
||||
_transferEncoding = HTTPC_TE_IDENTITY;
|
||||
} else {
|
||||
return HTTPC_ERROR_ENCODING;
|
||||
}
|
||||
|
@ -17,6 +17,10 @@ WiFiMulti WiFiMulti;
|
||||
|
||||
// Set time via NTP, as required for x.509 validation
|
||||
void setClock() {
|
||||
/*
|
||||
Note: Bundled Arduino lwip supports only ONE ntp server, 2nd and 3rd options are silently ignored
|
||||
see CONFIG_LWIP_DHCP_MAX_NTP_SERVERS define in ./tools/sdk/esp32/sdkconfig
|
||||
*/
|
||||
configTime(0, 0, "pool.ntp.org", "time.nist.gov"); // UTC
|
||||
|
||||
Serial.print(F("Waiting for NTP time sync: "));
|
||||
|
@ -160,6 +160,10 @@ void setup(){
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
Serial.println("Contacting Time Server");
|
||||
/*
|
||||
Note: Bundled Arduino lwip supports only ONE ntp server, 2nd and 3rd options are silently ignored
|
||||
see CONFIG_LWIP_DHCP_MAX_NTP_SERVERS define in ./tools/sdk/esp32/sdkconfig
|
||||
*/
|
||||
configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
|
||||
struct tm tmstruct ;
|
||||
delay(2000);
|
||||
|
@ -164,6 +164,10 @@ void setup(){
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
Serial.println("Contacting Time Server");
|
||||
/*
|
||||
Note: Bundled Arduino lwip supports only ONE ntp server, 2nd and 3rd options are silently ignored
|
||||
see CONFIG_LWIP_DHCP_MAX_NTP_SERVERS define in ./tools/sdk/esp32/sdkconfig
|
||||
*/
|
||||
configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
|
||||
struct tm tmstruct ;
|
||||
delay(2000);
|
||||
|
@ -164,6 +164,10 @@ void setup(){
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
Serial.println("Contacting Time Server");
|
||||
/*
|
||||
Note: Bundled Arduino lwip supports only ONE ntp server, 2nd and 3rd options are silently ignored
|
||||
see CONFIG_LWIP_DHCP_MAX_NTP_SERVERS define in ./tools/sdk/esp32/sdkconfig
|
||||
*/
|
||||
configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
|
||||
struct tm tmstruct ;
|
||||
delay(2000);
|
||||
|
@ -148,6 +148,10 @@ void setup(){
|
||||
Serial.println("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
Serial.println("Contacting Time Server");
|
||||
/*
|
||||
Note: Bundled Arduino lwip supports only ONE ntp server, 2nd and 3rd options are silently ignored
|
||||
see CONFIG_LWIP_DHCP_MAX_NTP_SERVERS define in ./tools/sdk/esp32/sdkconfig
|
||||
*/
|
||||
configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
|
||||
struct tm tmstruct ;
|
||||
delay(2000);
|
||||
|
213
libraries/USB/examples/CompositeDevice/CompositeDevice.ino
Normal file
213
libraries/USB/examples/CompositeDevice/CompositeDevice.ino
Normal file
@ -0,0 +1,213 @@
|
||||
#include "USB.h"
|
||||
#include "USBHIDMouse.h"
|
||||
#include "USBHIDKeyboard.h"
|
||||
#include "USBHIDGamepad.h"
|
||||
#include "USBHIDConsumerControl.h"
|
||||
#include "USBHIDSystemControl.h"
|
||||
#include "USBHIDVendor.h"
|
||||
#include "FirmwareMSC.h"
|
||||
|
||||
#if !ARDUINO_USB_MSC_ON_BOOT
|
||||
FirmwareMSC MSC_Update;
|
||||
#endif
|
||||
#if ARDUINO_USB_CDC_ON_BOOT
|
||||
#define HWSerial Serial0
|
||||
#define USBSerial Serial
|
||||
#else
|
||||
#define HWSerial Serial
|
||||
USBCDC USBSerial;
|
||||
#endif
|
||||
|
||||
USBHID HID;
|
||||
USBHIDKeyboard Keyboard;
|
||||
USBHIDMouse Mouse;
|
||||
USBHIDGamepad Gamepad;
|
||||
USBHIDConsumerControl ConsumerControl;
|
||||
USBHIDSystemControl SystemControl;
|
||||
USBHIDVendor Vendor;
|
||||
|
||||
const int buttonPin = 0;
|
||||
int previousButtonState = HIGH;
|
||||
|
||||
static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
|
||||
if(event_base == ARDUINO_USB_EVENTS){
|
||||
arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data;
|
||||
switch (event_id){
|
||||
case ARDUINO_USB_STARTED_EVENT:
|
||||
HWSerial.println("USB PLUGGED");
|
||||
break;
|
||||
case ARDUINO_USB_STOPPED_EVENT:
|
||||
HWSerial.println("USB UNPLUGGED");
|
||||
break;
|
||||
case ARDUINO_USB_SUSPEND_EVENT:
|
||||
HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en);
|
||||
break;
|
||||
case ARDUINO_USB_RESUME_EVENT:
|
||||
HWSerial.println("USB RESUMED");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(event_base == ARDUINO_USB_CDC_EVENTS){
|
||||
arduino_usb_cdc_event_data_t * data = (arduino_usb_cdc_event_data_t*)event_data;
|
||||
switch (event_id){
|
||||
case ARDUINO_USB_CDC_CONNECTED_EVENT:
|
||||
HWSerial.println("CDC CONNECTED");
|
||||
break;
|
||||
case ARDUINO_USB_CDC_DISCONNECTED_EVENT:
|
||||
HWSerial.println("CDC DISCONNECTED");
|
||||
break;
|
||||
case ARDUINO_USB_CDC_LINE_STATE_EVENT:
|
||||
HWSerial.printf("CDC LINE STATE: dtr: %u, rts: %u\n", data->line_state.dtr, data->line_state.rts);
|
||||
break;
|
||||
case ARDUINO_USB_CDC_LINE_CODING_EVENT:
|
||||
HWSerial.printf("CDC LINE CODING: bit_rate: %u, data_bits: %u, stop_bits: %u, parity: %u\n", data->line_coding.bit_rate, data->line_coding.data_bits, data->line_coding.stop_bits, data->line_coding.parity);
|
||||
break;
|
||||
case ARDUINO_USB_CDC_RX_EVENT:
|
||||
HWSerial.printf("CDC RX [%u]:", data->rx.len);
|
||||
{
|
||||
uint8_t buf[data->rx.len];
|
||||
size_t len = USBSerial.read(buf, data->rx.len);
|
||||
HWSerial.write(buf, len);
|
||||
}
|
||||
HWSerial.println();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(event_base == ARDUINO_FIRMWARE_MSC_EVENTS){
|
||||
arduino_firmware_msc_event_data_t * data = (arduino_firmware_msc_event_data_t*)event_data;
|
||||
switch (event_id){
|
||||
case ARDUINO_FIRMWARE_MSC_START_EVENT:
|
||||
HWSerial.println("MSC Update Start");
|
||||
break;
|
||||
case ARDUINO_FIRMWARE_MSC_WRITE_EVENT:
|
||||
//HWSerial.printf("MSC Update Write %u bytes at offset %u\n", data->write.size, data->write.offset);
|
||||
HWSerial.print(".");
|
||||
break;
|
||||
case ARDUINO_FIRMWARE_MSC_END_EVENT:
|
||||
HWSerial.printf("\nMSC Update End: %u bytes\n", data->end.size);
|
||||
break;
|
||||
case ARDUINO_FIRMWARE_MSC_ERROR_EVENT:
|
||||
HWSerial.printf("MSC Update ERROR! Progress: %u bytes\n", data->error.size);
|
||||
break;
|
||||
case ARDUINO_FIRMWARE_MSC_POWER_EVENT:
|
||||
HWSerial.printf("MSC Update Power: power: %u, start: %u, eject: %u\n", data->power.power_condition, data->power.start, data->power.load_eject);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(event_base == ARDUINO_USB_HID_EVENTS){
|
||||
arduino_usb_hid_event_data_t * data = (arduino_usb_hid_event_data_t*)event_data;
|
||||
switch (event_id){
|
||||
case ARDUINO_USB_HID_SET_PROTOCOL_EVENT:
|
||||
HWSerial.printf("HID SET PROTOCOL: %s\n", data->set_protocol.protocol?"REPORT":"BOOT");
|
||||
break;
|
||||
case ARDUINO_USB_HID_SET_IDLE_EVENT:
|
||||
HWSerial.printf("HID SET IDLE: %u\n", data->set_idle.idle_rate);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(event_base == ARDUINO_USB_HID_KEYBOARD_EVENTS){
|
||||
arduino_usb_hid_keyboard_event_data_t * data = (arduino_usb_hid_keyboard_event_data_t*)event_data;
|
||||
switch (event_id){
|
||||
case ARDUINO_USB_HID_KEYBOARD_LED_EVENT:
|
||||
HWSerial.printf("HID KEYBOARD LED: NumLock:%u, CapsLock:%u, ScrollLock:%u\n", data->numlock, data->capslock, data->scrolllock);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(event_base == ARDUINO_USB_HID_VENDOR_EVENTS){
|
||||
arduino_usb_hid_vendor_event_data_t * data = (arduino_usb_hid_vendor_event_data_t*)event_data;
|
||||
switch (event_id){
|
||||
case ARDUINO_USB_HID_VENDOR_GET_FEATURE_EVENT:
|
||||
HWSerial.printf("HID VENDOR GET FEATURE: len:%u\n", data->len);
|
||||
for(uint16_t i=0; i<data->len; i++){
|
||||
HWSerial.write(data->buffer[i]?data->buffer[i]:'.');
|
||||
}
|
||||
HWSerial.println();
|
||||
break;
|
||||
case ARDUINO_USB_HID_VENDOR_SET_FEATURE_EVENT:
|
||||
HWSerial.printf("HID VENDOR SET FEATURE: len:%u\n", data->len);
|
||||
for(uint16_t i=0; i<data->len; i++){
|
||||
HWSerial.write(data->buffer[i]?data->buffer[i]:'.');
|
||||
}
|
||||
HWSerial.println();
|
||||
break;
|
||||
case ARDUINO_USB_HID_VENDOR_OUTPUT_EVENT:
|
||||
HWSerial.printf("HID VENDOR OUTPUT: len:%u\n", data->len);
|
||||
for(uint16_t i=0; i<data->len; i++){
|
||||
HWSerial.write(Vendor.read());
|
||||
}
|
||||
HWSerial.println();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
HWSerial.begin(115200);
|
||||
HWSerial.setDebugOutput(true);
|
||||
|
||||
USB.onEvent(usbEventCallback);
|
||||
USBSerial.onEvent(usbEventCallback);
|
||||
MSC_Update.onEvent(usbEventCallback);
|
||||
HID.onEvent(usbEventCallback);
|
||||
Keyboard.onEvent(usbEventCallback);
|
||||
Vendor.onEvent(usbEventCallback);
|
||||
|
||||
USBSerial.begin();
|
||||
MSC_Update.begin();
|
||||
Vendor.begin();
|
||||
Mouse.begin();
|
||||
Keyboard.begin();
|
||||
Gamepad.begin();
|
||||
ConsumerControl.begin();
|
||||
SystemControl.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
int buttonState = digitalRead(buttonPin);
|
||||
if (HID.ready() && buttonState != previousButtonState) {
|
||||
previousButtonState = buttonState;
|
||||
if (buttonState == LOW) {
|
||||
HWSerial.println("Button Pressed");
|
||||
USBSerial.println("Button Pressed");
|
||||
Vendor.println("Button Pressed");
|
||||
Mouse.move(10,10);
|
||||
Keyboard.pressRaw(HID_KEY_CAPS_LOCK);
|
||||
Gamepad.leftStick(100,100);
|
||||
ConsumerControl.press(CONSUMER_CONTROL_VOLUME_INCREMENT);
|
||||
//SystemControl.press(SYSTEM_CONTROL_POWER_OFF);
|
||||
} else {
|
||||
Keyboard.releaseRaw(HID_KEY_CAPS_LOCK);
|
||||
Gamepad.leftStick(0,0);
|
||||
ConsumerControl.release();
|
||||
//SystemControl.release();
|
||||
Vendor.println("Button Released");
|
||||
USBSerial.println("Button Released");
|
||||
HWSerial.println("Button Released");
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
|
||||
while(HWSerial.available()){
|
||||
size_t l = HWSerial.available();
|
||||
uint8_t b[l];
|
||||
l = HWSerial.read(b, l);
|
||||
USBSerial.write(b, l);
|
||||
if(HID.ready()){
|
||||
Vendor.write(b,l);
|
||||
}
|
||||
}
|
||||
}
|
0
libraries/USB/examples/ConsumerControl/.skip.esp32
Normal file
0
libraries/USB/examples/ConsumerControl/.skip.esp32
Normal file
21
libraries/USB/examples/ConsumerControl/ConsumerControl.ino
Normal file
21
libraries/USB/examples/ConsumerControl/ConsumerControl.ino
Normal file
@ -0,0 +1,21 @@
|
||||
#include "USB.h"
|
||||
#include "USBHIDConsumerControl.h"
|
||||
USBHIDConsumerControl ConsumerControl;
|
||||
|
||||
const int buttonPin = 0;
|
||||
int previousButtonState = HIGH;
|
||||
|
||||
void setup() {
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
ConsumerControl.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
int buttonState = digitalRead(buttonPin);
|
||||
if ((buttonState != previousButtonState) && (buttonState == LOW)) {
|
||||
ConsumerControl.press(CONSUMER_CONTROL_VOLUME_INCREMENT);
|
||||
ConsumerControl.release();
|
||||
}
|
||||
previousButtonState = buttonState;
|
||||
}
|
0
libraries/USB/examples/CustomHIDDevice/.skip.esp32
Normal file
0
libraries/USB/examples/CustomHIDDevice/.skip.esp32
Normal file
79
libraries/USB/examples/CustomHIDDevice/CustomHIDDevice.ino
Normal file
79
libraries/USB/examples/CustomHIDDevice/CustomHIDDevice.ino
Normal file
@ -0,0 +1,79 @@
|
||||
#include "USB.h"
|
||||
#include "USBHID.h"
|
||||
USBHID HID;
|
||||
|
||||
static const uint8_t report_descriptor[] = { // 8 axis
|
||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||
0x09, 0x04, // Usage (Joystick)
|
||||
0xa1, 0x01, // Collection (Application)
|
||||
0xa1, 0x00, // Collection (Physical)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||
0x09, 0x30, // Usage (X)
|
||||
0x09, 0x31, // Usage (Y)
|
||||
0x09, 0x32, // Usage (Z)
|
||||
0x09, 0x33, // Usage (Rx)
|
||||
0x09, 0x34, // Usage (Ry)
|
||||
0x09, 0x35, // Usage (Rz)
|
||||
0x09, 0x36, // Usage (Slider)
|
||||
0x09, 0x36, // Usage (Slider)
|
||||
0x15, 0x81, // Logical Minimum (-127)
|
||||
0x25, 0x7f, // Logical Maximum (127)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x08, // Report Count (8)
|
||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0xC0, // End Collection
|
||||
0xC0, // End Collection
|
||||
};
|
||||
|
||||
class CustomHIDDevice: public USBHIDDevice {
|
||||
public:
|
||||
CustomHIDDevice(void){
|
||||
static bool initialized = false;
|
||||
if(!initialized){
|
||||
initialized = true;
|
||||
HID.addDevice(this, sizeof(report_descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
void begin(void){
|
||||
HID.begin();
|
||||
}
|
||||
|
||||
uint16_t _onGetDescriptor(uint8_t* buffer){
|
||||
memcpy(buffer, report_descriptor, sizeof(report_descriptor));
|
||||
return sizeof(report_descriptor);
|
||||
}
|
||||
|
||||
bool send(uint8_t * value){
|
||||
return HID.SendReport(0, value, 8);
|
||||
}
|
||||
};
|
||||
|
||||
CustomHIDDevice Device;
|
||||
|
||||
const int buttonPin = 0;
|
||||
int previousButtonState = HIGH;
|
||||
uint8_t axis[8];
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.setDebugOutput(true);
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
Device.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
int buttonState = digitalRead(buttonPin);
|
||||
if (HID.ready() && buttonState != previousButtonState) {
|
||||
previousButtonState = buttonState;
|
||||
if (buttonState == LOW) {
|
||||
Serial.println("Button Pressed");
|
||||
axis[0] = random() & 0xFF;
|
||||
Device.send(axis);
|
||||
} else {
|
||||
Serial.println("Button Released");
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
}
|
0
libraries/USB/examples/FirmwareMSC/.skip.esp32
Normal file
0
libraries/USB/examples/FirmwareMSC/.skip.esp32
Normal file
0
libraries/USB/examples/FirmwareMSC/.skip.esp32c3
Normal file
0
libraries/USB/examples/FirmwareMSC/.skip.esp32c3
Normal file
74
libraries/USB/examples/FirmwareMSC/FirmwareMSC.ino
Normal file
74
libraries/USB/examples/FirmwareMSC/FirmwareMSC.ino
Normal file
@ -0,0 +1,74 @@
|
||||
#include "USB.h"
|
||||
#include "FirmwareMSC.h"
|
||||
|
||||
#if !ARDUINO_USB_MSC_ON_BOOT
|
||||
FirmwareMSC MSC_Update;
|
||||
#endif
|
||||
#if ARDUINO_USB_CDC_ON_BOOT
|
||||
#define HWSerial Serial0
|
||||
#define USBSerial Serial
|
||||
#else
|
||||
#define HWSerial Serial
|
||||
USBCDC USBSerial;
|
||||
#endif
|
||||
|
||||
static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
|
||||
if(event_base == ARDUINO_USB_EVENTS){
|
||||
arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data;
|
||||
switch (event_id){
|
||||
case ARDUINO_USB_STARTED_EVENT:
|
||||
HWSerial.println("USB PLUGGED");
|
||||
break;
|
||||
case ARDUINO_USB_STOPPED_EVENT:
|
||||
HWSerial.println("USB UNPLUGGED");
|
||||
break;
|
||||
case ARDUINO_USB_SUSPEND_EVENT:
|
||||
HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en);
|
||||
break;
|
||||
case ARDUINO_USB_RESUME_EVENT:
|
||||
HWSerial.println("USB RESUMED");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if(event_base == ARDUINO_FIRMWARE_MSC_EVENTS){
|
||||
arduino_firmware_msc_event_data_t * data = (arduino_firmware_msc_event_data_t*)event_data;
|
||||
switch (event_id){
|
||||
case ARDUINO_FIRMWARE_MSC_START_EVENT:
|
||||
HWSerial.println("MSC Update Start");
|
||||
break;
|
||||
case ARDUINO_FIRMWARE_MSC_WRITE_EVENT:
|
||||
//HWSerial.printf("MSC Update Write %u bytes at offset %u\n", data->write.size, data->write.offset);
|
||||
HWSerial.print(".");
|
||||
break;
|
||||
case ARDUINO_FIRMWARE_MSC_END_EVENT:
|
||||
HWSerial.printf("\nMSC Update End: %u bytes\n", data->end.size);
|
||||
break;
|
||||
case ARDUINO_FIRMWARE_MSC_ERROR_EVENT:
|
||||
HWSerial.printf("MSC Update ERROR! Progress: %u bytes\n", data->error.size);
|
||||
break;
|
||||
case ARDUINO_FIRMWARE_MSC_POWER_EVENT:
|
||||
HWSerial.printf("MSC Update Power: power: %u, start: %u, eject: %u", data->power.power_condition, data->power.start, data->power.load_eject);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
HWSerial.begin(115200);
|
||||
HWSerial.setDebugOutput(true);
|
||||
|
||||
USB.onEvent(usbEventCallback);
|
||||
MSC_Update.onEvent(usbEventCallback);
|
||||
MSC_Update.begin();
|
||||
USBSerial.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly
|
||||
}
|
0
libraries/USB/examples/Gamepad/.skip.esp32
Normal file
0
libraries/USB/examples/Gamepad/.skip.esp32
Normal file
0
libraries/USB/examples/Gamepad/.skip.esp32c3
Normal file
0
libraries/USB/examples/Gamepad/.skip.esp32c3
Normal file
21
libraries/USB/examples/Gamepad/Gamepad.ino
Normal file
21
libraries/USB/examples/Gamepad/Gamepad.ino
Normal file
@ -0,0 +1,21 @@
|
||||
#include "USB.h"
|
||||
#include "USBHIDGamepad.h"
|
||||
USBHIDGamepad Gamepad;
|
||||
|
||||
const int buttonPin = 0;
|
||||
int previousButtonState = HIGH;
|
||||
|
||||
void setup() {
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
Gamepad.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
int buttonState = digitalRead(buttonPin);
|
||||
if ((buttonState != previousButtonState) && (buttonState == LOW)) {
|
||||
Gamepad.pressButton(BUTTON_START);
|
||||
Gamepad.releaseButton(BUTTON_START);
|
||||
}
|
||||
previousButtonState = buttonState;
|
||||
}
|
0
libraries/USB/examples/HIDVendor/.skip.esp32
Normal file
0
libraries/USB/examples/HIDVendor/.skip.esp32
Normal file
0
libraries/USB/examples/HIDVendor/.skip.esp32c3
Normal file
0
libraries/USB/examples/HIDVendor/.skip.esp32c3
Normal file
52
libraries/USB/examples/HIDVendor/HIDVendor.ino
Normal file
52
libraries/USB/examples/HIDVendor/HIDVendor.ino
Normal file
@ -0,0 +1,52 @@
|
||||
#include "USB.h"
|
||||
#include "USBHIDVendor.h"
|
||||
USBHIDVendor Vendor;
|
||||
|
||||
const int buttonPin = 0;
|
||||
int previousButtonState = HIGH;
|
||||
|
||||
static void vendorEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
|
||||
if(event_base == ARDUINO_USB_HID_VENDOR_EVENTS){
|
||||
arduino_usb_hid_vendor_event_data_t * data = (arduino_usb_hid_vendor_event_data_t*)event_data;
|
||||
switch (event_id){
|
||||
case ARDUINO_USB_HID_VENDOR_GET_FEATURE_EVENT:
|
||||
Serial.printf("HID VENDOR GET FEATURE: len:%u\n", data->len);
|
||||
break;
|
||||
case ARDUINO_USB_HID_VENDOR_SET_FEATURE_EVENT:
|
||||
Serial.printf("HID VENDOR SET FEATURE: len:%u\n", data->len);
|
||||
for(uint16_t i=0; i<data->len; i++){
|
||||
Serial.printf("0x%02X ",data->buffer);
|
||||
}
|
||||
Serial.println();
|
||||
break;
|
||||
case ARDUINO_USB_HID_VENDOR_OUTPUT_EVENT:
|
||||
Serial.printf("HID VENDOR OUTPUT: len:%u\n", data->len);
|
||||
// for(uint16_t i=0; i<data->len; i++){
|
||||
// Serial.write(Vendor.read());
|
||||
// }
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
Serial.begin(115200);
|
||||
Vendor.onEvent(vendorEventCallback);
|
||||
Vendor.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
int buttonState = digitalRead(buttonPin);
|
||||
if ((buttonState != previousButtonState) && (buttonState == LOW)) {
|
||||
Vendor.println("Hello World!");
|
||||
}
|
||||
previousButtonState = buttonState;
|
||||
while(Vendor.available()){
|
||||
Serial.write(Vendor.read());
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
Keyboard logout
|
||||
|
||||
This sketch demonstrates the Keyboard library.
|
||||
|
||||
When you connect pin 2 to ground, it performs a logout.
|
||||
It uses keyboard combinations to do this, as follows:
|
||||
|
||||
On Windows, CTRL-ALT-DEL followed by ALT-l
|
||||
On Ubuntu, CTRL-ALT-DEL, and ENTER
|
||||
On OSX, CMD-SHIFT-q
|
||||
|
||||
To wake: Spacebar.
|
||||
|
||||
Circuit:
|
||||
- Arduino Leonardo or Micro
|
||||
- wire to connect D2 to ground
|
||||
|
||||
created 6 Mar 2012
|
||||
modified 27 Mar 2012
|
||||
by Tom Igoe
|
||||
|
||||
This example is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/KeyboardLogout
|
||||
*/
|
||||
|
||||
#define OSX 0
|
||||
#define WINDOWS 1
|
||||
#define UBUNTU 2
|
||||
|
||||
#include "USB.h"
|
||||
#include "USBHIDKeyboard.h"
|
||||
USBHIDKeyboard Keyboard;
|
||||
|
||||
// change this to match your platform:
|
||||
int platform = OSX;
|
||||
|
||||
void setup() {
|
||||
// make pin 0 an input and turn on the pull-up resistor so it goes high unless
|
||||
// connected to ground:
|
||||
pinMode(0, INPUT_PULLUP);
|
||||
Keyboard.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
while (digitalRead(0) == HIGH) {
|
||||
// do nothing until pin 2 goes low
|
||||
delay(500);
|
||||
}
|
||||
delay(1000);
|
||||
|
||||
switch (platform) {
|
||||
case OSX:
|
||||
Keyboard.press(KEY_LEFT_GUI);
|
||||
// Shift-Q logs out:
|
||||
Keyboard.press(KEY_LEFT_SHIFT);
|
||||
Keyboard.press('Q');
|
||||
delay(100);
|
||||
Keyboard.releaseAll();
|
||||
// enter:
|
||||
Keyboard.write(KEY_RETURN);
|
||||
break;
|
||||
case WINDOWS:
|
||||
// CTRL-ALT-DEL:
|
||||
Keyboard.press(KEY_LEFT_CTRL);
|
||||
Keyboard.press(KEY_LEFT_ALT);
|
||||
Keyboard.press(KEY_DELETE);
|
||||
delay(100);
|
||||
Keyboard.releaseAll();
|
||||
// ALT-l:
|
||||
delay(2000);
|
||||
Keyboard.press(KEY_LEFT_ALT);
|
||||
Keyboard.press('l');
|
||||
Keyboard.releaseAll();
|
||||
break;
|
||||
case UBUNTU:
|
||||
// CTRL-ALT-DEL:
|
||||
Keyboard.press(KEY_LEFT_CTRL);
|
||||
Keyboard.press(KEY_LEFT_ALT);
|
||||
Keyboard.press(KEY_DELETE);
|
||||
delay(1000);
|
||||
Keyboard.releaseAll();
|
||||
// Enter to confirm logout:
|
||||
Keyboard.write(KEY_RETURN);
|
||||
break;
|
||||
}
|
||||
|
||||
// do nothing:
|
||||
while (true) delay(1000);
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
Keyboard Message test
|
||||
|
||||
For the Arduino Leonardo and Micro.
|
||||
|
||||
Sends a text string when a button is pressed.
|
||||
|
||||
The circuit:
|
||||
- pushbutton attached from pin 0 to ground
|
||||
- 10 kilohm resistor attached from pin 0 to +5V
|
||||
|
||||
created 24 Oct 2011
|
||||
modified 27 Mar 2012
|
||||
by Tom Igoe
|
||||
modified 11 Nov 2013
|
||||
by Scott Fitzgerald
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/KeyboardMessage
|
||||
*/
|
||||
|
||||
#include "USB.h"
|
||||
#include "USBHIDKeyboard.h"
|
||||
USBHIDKeyboard Keyboard;
|
||||
|
||||
const int buttonPin = 0; // input pin for pushbutton
|
||||
int previousButtonState = HIGH; // for checking the state of a pushButton
|
||||
int counter = 0; // button push counter
|
||||
|
||||
void setup() {
|
||||
// make the pushButton pin an input:
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
// initialize control over the keyboard:
|
||||
Keyboard.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// read the pushbutton:
|
||||
int buttonState = digitalRead(buttonPin);
|
||||
// if the button state has changed,
|
||||
if ((buttonState != previousButtonState)
|
||||
// and it's currently pressed:
|
||||
&& (buttonState == LOW)) {
|
||||
// increment the button counter
|
||||
counter++;
|
||||
// type out a message
|
||||
Keyboard.print("You pressed the button ");
|
||||
Keyboard.print(counter);
|
||||
Keyboard.println(" times.");
|
||||
}
|
||||
// save the current button state for comparison next time:
|
||||
previousButtonState = buttonState;
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
Arduino Programs Blink
|
||||
|
||||
This sketch demonstrates the Keyboard library.
|
||||
|
||||
For Leonardo and Due boards only.
|
||||
|
||||
When you connect pin 2 to ground, it creates a new window with a key
|
||||
combination (CTRL-N), then types in the Blink sketch, then auto-formats the
|
||||
text using another key combination (CTRL-T), then uploads the sketch to the
|
||||
currently selected Arduino using a final key combination (CTRL-U).
|
||||
|
||||
Circuit:
|
||||
- Arduino Leonardo, Micro, Due, LilyPad USB, or Yún
|
||||
- wire to connect D2 to ground
|
||||
|
||||
created 5 Mar 2012
|
||||
modified 29 Mar 2012
|
||||
by Tom Igoe
|
||||
modified 3 May 2014
|
||||
by Scott Fitzgerald
|
||||
|
||||
This example is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/KeyboardReprogram
|
||||
*/
|
||||
|
||||
#include "USB.h"
|
||||
#include "USBHIDKeyboard.h"
|
||||
USBHIDKeyboard Keyboard;
|
||||
|
||||
// use this option for OSX.
|
||||
// Comment it out if using Windows or Linux:
|
||||
char ctrlKey = KEY_LEFT_GUI;
|
||||
// use this option for Windows and Linux.
|
||||
// leave commented out if using OSX:
|
||||
// char ctrlKey = KEY_LEFT_CTRL;
|
||||
|
||||
|
||||
void setup() {
|
||||
// make pin 0 an input and turn on the pull-up resistor so it goes high unless
|
||||
// connected to ground:
|
||||
pinMode(0, INPUT_PULLUP);
|
||||
// initialize control over the keyboard:
|
||||
Keyboard.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
while (digitalRead(0) == HIGH) {
|
||||
// do nothing until pin 0 goes low
|
||||
delay(500);
|
||||
}
|
||||
delay(1000);
|
||||
// new document:
|
||||
Keyboard.press(ctrlKey);
|
||||
Keyboard.press('n');
|
||||
delay(100);
|
||||
Keyboard.releaseAll();
|
||||
// wait for new window to open:
|
||||
delay(1000);
|
||||
|
||||
// versions of the Arduino IDE after 1.5 pre-populate new sketches with
|
||||
// setup() and loop() functions let's clear the window before typing anything new
|
||||
// select all
|
||||
Keyboard.press(ctrlKey);
|
||||
Keyboard.press('a');
|
||||
delay(500);
|
||||
Keyboard.releaseAll();
|
||||
// delete the selected text
|
||||
Keyboard.write(KEY_BACKSPACE);
|
||||
delay(500);
|
||||
|
||||
// Type out "blink":
|
||||
Keyboard.println("void setup() {");
|
||||
Keyboard.println("pinMode(13, OUTPUT);");
|
||||
Keyboard.println("}");
|
||||
Keyboard.println();
|
||||
Keyboard.println("void loop() {");
|
||||
Keyboard.println("digitalWrite(13, HIGH);");
|
||||
Keyboard.print("delay(3000);");
|
||||
// 3000 ms is too long. Delete it:
|
||||
for (int keystrokes = 0; keystrokes < 6; keystrokes++) {
|
||||
delay(500);
|
||||
Keyboard.write(KEY_BACKSPACE);
|
||||
}
|
||||
// make it 1000 instead:
|
||||
Keyboard.println("1000);");
|
||||
Keyboard.println("digitalWrite(13, LOW);");
|
||||
Keyboard.println("delay(1000);");
|
||||
Keyboard.println("}");
|
||||
// tidy up:
|
||||
Keyboard.press(ctrlKey);
|
||||
Keyboard.press('t');
|
||||
delay(100);
|
||||
Keyboard.releaseAll();
|
||||
delay(3000);
|
||||
// upload code:
|
||||
Keyboard.press(ctrlKey);
|
||||
Keyboard.press('u');
|
||||
delay(100);
|
||||
Keyboard.releaseAll();
|
||||
|
||||
// wait for the sweet oblivion of reprogramming:
|
||||
while (true)delay(1000);
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
Keyboard test
|
||||
|
||||
Reads a byte from the serial port, sends a keystroke back.
|
||||
The sent keystroke is one higher than what's received, e.g. if you send a,
|
||||
you get b, send A you get B, and so forth.
|
||||
|
||||
The circuit:
|
||||
- none
|
||||
|
||||
created 21 Oct 2011
|
||||
modified 27 Mar 2012
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/KeyboardSerial
|
||||
*/
|
||||
|
||||
#include "USB.h"
|
||||
#include "USBHIDKeyboard.h"
|
||||
USBHIDKeyboard Keyboard;
|
||||
|
||||
void setup() {
|
||||
// open the serial port:
|
||||
Serial.begin(115200);
|
||||
// initialize control over the keyboard:
|
||||
Keyboard.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// check for incoming serial data:
|
||||
if (Serial.available() > 0) {
|
||||
// read incoming serial data:
|
||||
char inChar = Serial.read();
|
||||
// Type the next ASCII value from what you received:
|
||||
Keyboard.write(inChar + 1);
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
KeyboardAndMouseControl
|
||||
|
||||
Hardware:
|
||||
- five pushbuttons attached to D12, D13, D14, D15, D0
|
||||
|
||||
The mouse movement is always relative. This sketch reads four pushbuttons, and
|
||||
uses them to set the movement of the mouse.
|
||||
|
||||
WARNING: When you use the Mouse.move() command, the Arduino takes over your
|
||||
mouse! Make sure you have control before you use the mouse commands.
|
||||
|
||||
created 15 Mar 2012
|
||||
modified 27 Mar 2012
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/KeyboardAndMouseControl
|
||||
*/
|
||||
|
||||
#include "USB.h"
|
||||
#include "USBHIDMouse.h"
|
||||
#include "USBHIDKeyboard.h"
|
||||
USBHIDMouse Mouse;
|
||||
USBHIDKeyboard Keyboard;
|
||||
|
||||
// set pin numbers for the five buttons:
|
||||
const int upButton = 12;
|
||||
const int downButton = 13;
|
||||
const int leftButton = 14;
|
||||
const int rightButton = 15;
|
||||
const int mouseButton = 0;
|
||||
|
||||
void setup() { // initialize the buttons' inputs:
|
||||
pinMode(upButton, INPUT_PULLUP);
|
||||
pinMode(downButton, INPUT_PULLUP);
|
||||
pinMode(leftButton, INPUT_PULLUP);
|
||||
pinMode(rightButton, INPUT_PULLUP);
|
||||
pinMode(mouseButton, INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
// initialize mouse control:
|
||||
Mouse.begin();
|
||||
Keyboard.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// use serial input to control the mouse:
|
||||
if (Serial.available() > 0) {
|
||||
char inChar = Serial.read();
|
||||
|
||||
switch (inChar) {
|
||||
case 'u':
|
||||
// move mouse up
|
||||
Mouse.move(0, -40);
|
||||
break;
|
||||
case 'd':
|
||||
// move mouse down
|
||||
Mouse.move(0, 40);
|
||||
break;
|
||||
case 'l':
|
||||
// move mouse left
|
||||
Mouse.move(-40, 0);
|
||||
break;
|
||||
case 'r':
|
||||
// move mouse right
|
||||
Mouse.move(40, 0);
|
||||
break;
|
||||
case 'm':
|
||||
// perform mouse left click
|
||||
Mouse.click(MOUSE_LEFT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// use the pushbuttons to control the keyboard:
|
||||
if (digitalRead(upButton) == LOW) {
|
||||
Keyboard.write('u');
|
||||
}
|
||||
if (digitalRead(downButton) == LOW) {
|
||||
Keyboard.write('d');
|
||||
}
|
||||
if (digitalRead(leftButton) == LOW) {
|
||||
Keyboard.write('l');
|
||||
}
|
||||
if (digitalRead(rightButton) == LOW) {
|
||||
Keyboard.write('r');
|
||||
}
|
||||
if (digitalRead(mouseButton) == LOW) {
|
||||
Keyboard.write('m');
|
||||
}
|
||||
delay(5);
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
ButtonMouseControl
|
||||
|
||||
Controls the mouse from five pushbuttons on an Arduino Leonardo, Micro or Due.
|
||||
|
||||
Hardware:
|
||||
- five pushbuttons attached to D12, D13, D14, D15, D0
|
||||
|
||||
The mouse movement is always relative. This sketch reads four pushbuttons,
|
||||
and uses them to set the movement of the mouse.
|
||||
|
||||
WARNING: When you use the Mouse.move() command, the Arduino takes over your
|
||||
mouse! Make sure you have control before you use the mouse commands.
|
||||
|
||||
created 15 Mar 2012
|
||||
modified 27 Mar 2012
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/ButtonMouseControl
|
||||
*/
|
||||
|
||||
#include "USB.h"
|
||||
#include "USBHIDMouse.h"
|
||||
USBHIDMouse Mouse;
|
||||
|
||||
|
||||
// set pin numbers for the five buttons:
|
||||
const int upButton = 12;
|
||||
const int downButton = 13;
|
||||
const int leftButton = 14;
|
||||
const int rightButton = 15;
|
||||
const int mouseButton = 0;
|
||||
|
||||
int range = 5; // output range of X or Y movement; affects movement speed
|
||||
int responseDelay = 10; // response delay of the mouse, in ms
|
||||
|
||||
|
||||
void setup() {
|
||||
// initialize the buttons' inputs:
|
||||
pinMode(upButton, INPUT_PULLUP);
|
||||
pinMode(downButton, INPUT_PULLUP);
|
||||
pinMode(leftButton, INPUT_PULLUP);
|
||||
pinMode(rightButton, INPUT_PULLUP);
|
||||
pinMode(mouseButton, INPUT_PULLUP);
|
||||
// initialize mouse control:
|
||||
Mouse.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// read the buttons:
|
||||
int upState = digitalRead(upButton);
|
||||
int downState = digitalRead(downButton);
|
||||
int rightState = digitalRead(rightButton);
|
||||
int leftState = digitalRead(leftButton);
|
||||
int clickState = digitalRead(mouseButton);
|
||||
|
||||
// calculate the movement distance based on the button states:
|
||||
int xDistance = (leftState - rightState) * range;
|
||||
int yDistance = (upState - downState) * range;
|
||||
|
||||
// if X or Y is non-zero, move:
|
||||
if ((xDistance != 0) || (yDistance != 0)) {
|
||||
Mouse.move(xDistance, yDistance, 0);
|
||||
}
|
||||
|
||||
// if the mouse button is pressed:
|
||||
if (clickState == LOW) {
|
||||
// if the mouse is not pressed, press it:
|
||||
if (!Mouse.isPressed(MOUSE_LEFT)) {
|
||||
Mouse.press(MOUSE_LEFT);
|
||||
}
|
||||
}
|
||||
// else the mouse button is not pressed:
|
||||
else {
|
||||
// if the mouse is pressed, release it:
|
||||
if (Mouse.isPressed(MOUSE_LEFT)) {
|
||||
Mouse.release(MOUSE_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
// a delay so the mouse doesn't move too fast:
|
||||
delay(responseDelay);
|
||||
}
|
0
libraries/USB/examples/SystemControl/.skip.esp32
Normal file
0
libraries/USB/examples/SystemControl/.skip.esp32
Normal file
0
libraries/USB/examples/SystemControl/.skip.esp32c3
Normal file
0
libraries/USB/examples/SystemControl/.skip.esp32c3
Normal file
21
libraries/USB/examples/SystemControl/SystemControl.ino
Normal file
21
libraries/USB/examples/SystemControl/SystemControl.ino
Normal file
@ -0,0 +1,21 @@
|
||||
#include "USB.h"
|
||||
#include "USBHIDSystemControl.h"
|
||||
USBHIDSystemControl SystemControl;
|
||||
|
||||
const int buttonPin = 0;
|
||||
int previousButtonState = HIGH;
|
||||
|
||||
void setup() {
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
SystemControl.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
int buttonState = digitalRead(buttonPin);
|
||||
if ((buttonState != previousButtonState) && (buttonState == LOW)) {
|
||||
SystemControl.press(SYSTEM_CONTROL_POWER_OFF);
|
||||
SystemControl.release();
|
||||
}
|
||||
previousButtonState = buttonState;
|
||||
}
|
0
libraries/USB/examples/USBMSC/.skip.esp32
Normal file
0
libraries/USB/examples/USBMSC/.skip.esp32
Normal file
0
libraries/USB/examples/USBMSC/.skip.esp32c3
Normal file
0
libraries/USB/examples/USBMSC/.skip.esp32c3
Normal file
192
libraries/USB/examples/USBMSC/USBMSC.ino
Normal file
192
libraries/USB/examples/USBMSC/USBMSC.ino
Normal file
@ -0,0 +1,192 @@
|
||||
#include "USB.h"
|
||||
#include "USBMSC.h"
|
||||
|
||||
#if ARDUINO_USB_CDC_ON_BOOT
|
||||
#define HWSerial Serial0
|
||||
#define USBSerial Serial
|
||||
#else
|
||||
#define HWSerial Serial
|
||||
USBCDC USBSerial;
|
||||
#endif
|
||||
|
||||
USBMSC MSC;
|
||||
|
||||
#define FAT_U8(v) ((v) & 0xFF)
|
||||
#define FAT_U16(v) FAT_U8(v), FAT_U8((v) >> 8)
|
||||
#define FAT_U32(v) FAT_U8(v), FAT_U8((v) >> 8), FAT_U8((v) >> 16), FAT_U8((v) >> 24)
|
||||
#define FAT_MS2B(s,ms) FAT_U8(((((s) & 0x1) * 1000) + (ms)) / 10)
|
||||
#define FAT_HMS2B(h,m,s) FAT_U8(((s) >> 1)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x7)|((h) << 3))
|
||||
#define FAT_YMD2B(y,m,d) FAT_U8(((d) & 0x1F)|(((m) & 0x7) << 5)), FAT_U8((((m) >> 3) & 0x1)|((((y) - 1980) & 0x7F) << 1))
|
||||
#define FAT_TBL2B(l,h) FAT_U8(l), FAT_U8(((l >> 8) & 0xF) | ((h << 4) & 0xF0)), FAT_U8(h >> 4)
|
||||
|
||||
#define README_CONTENTS "This is tinyusb's MassStorage Class demo.\r\n\r\nIf you find any bugs or get any questions, feel free to file an\r\nissue at github.com/hathach/tinyusb"
|
||||
|
||||
static const uint32_t DISK_SECTOR_COUNT = 2 * 8; // 8KB is the smallest size that windows allow to mount
|
||||
static const uint16_t DISK_SECTOR_SIZE = 512; // Should be 512
|
||||
static const uint16_t DISC_SECTORS_PER_TABLE = 1; //each table sector can fit 170KB (340 sectors)
|
||||
|
||||
static uint8_t msc_disk[DISK_SECTOR_COUNT][DISK_SECTOR_SIZE] =
|
||||
{
|
||||
//------------- Block0: Boot Sector -------------//
|
||||
{
|
||||
// Header (62 bytes)
|
||||
0xEB, 0x3C, 0x90, //jump_instruction
|
||||
'M' , 'S' , 'D' , 'O' , 'S' , '5' , '.' , '0' , //oem_name
|
||||
FAT_U16(DISK_SECTOR_SIZE), //bytes_per_sector
|
||||
FAT_U8(1), //sectors_per_cluster
|
||||
FAT_U16(1), //reserved_sectors_count
|
||||
FAT_U8(1), //file_alloc_tables_num
|
||||
FAT_U16(16), //max_root_dir_entries
|
||||
FAT_U16(DISK_SECTOR_COUNT), //fat12_sector_num
|
||||
0xF8, //media_descriptor
|
||||
FAT_U16(DISC_SECTORS_PER_TABLE), //sectors_per_alloc_table;//FAT12 and FAT16
|
||||
FAT_U16(1), //sectors_per_track;//A value of 0 may indicate LBA-only access
|
||||
FAT_U16(1), //num_heads
|
||||
FAT_U32(0), //hidden_sectors_count
|
||||
FAT_U32(0), //total_sectors_32
|
||||
0x00, //physical_drive_number;0x00 for (first) removable media, 0x80 for (first) fixed disk
|
||||
0x00, //reserved
|
||||
0x29, //extended_boot_signature;//should be 0x29
|
||||
FAT_U32(0x1234), //serial_number: 0x1234 => 1234
|
||||
'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , //volume_label padded with spaces (0x20)
|
||||
'F' , 'A' , 'T' , '1' , '2' , ' ' , ' ' , ' ' , //file_system_type padded with spaces (0x20)
|
||||
|
||||
// Zero up to 2 last bytes of FAT magic code (448 bytes)
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
//boot signature (2 bytes)
|
||||
0x55, 0xAA
|
||||
},
|
||||
|
||||
//------------- Block1: FAT12 Table -------------//
|
||||
{
|
||||
FAT_TBL2B(0xFF8, 0xFFF), FAT_TBL2B(0xFFF, 0x000) // first 2 entries must be 0xFF8 0xFFF, third entry is cluster end of readme file
|
||||
},
|
||||
|
||||
//------------- Block2: Root Directory -------------//
|
||||
{
|
||||
// first entry is volume label
|
||||
'E' , 'S' , 'P' , '3' , '2' , 'S' , '2' , ' ' ,
|
||||
'M' , 'S' , 'C' ,
|
||||
0x08, //FILE_ATTR_VOLUME_LABEL
|
||||
0x00,
|
||||
FAT_MS2B(0,0),
|
||||
FAT_HMS2B(0,0,0),
|
||||
FAT_YMD2B(0,0,0),
|
||||
FAT_YMD2B(0,0,0),
|
||||
FAT_U16(0),
|
||||
FAT_HMS2B(13,42,30), //last_modified_hms
|
||||
FAT_YMD2B(2018,11,5), //last_modified_ymd
|
||||
FAT_U16(0),
|
||||
FAT_U32(0),
|
||||
|
||||
// second entry is readme file
|
||||
'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' ,//file_name[8]; padded with spaces (0x20)
|
||||
'T' , 'X' , 'T' , //file_extension[3]; padded with spaces (0x20)
|
||||
0x20, //file attributes: FILE_ATTR_ARCHIVE
|
||||
0x00, //ignore
|
||||
FAT_MS2B(1,980), //creation_time_10_ms (max 199x10 = 1s 990ms)
|
||||
FAT_HMS2B(13,42,36), //create_time_hms [5:6:5] => h:m:(s/2)
|
||||
FAT_YMD2B(2018,11,5), //create_time_ymd [7:4:5] => (y+1980):m:d
|
||||
FAT_YMD2B(2020,11,5), //last_access_ymd
|
||||
FAT_U16(0), //extended_attributes
|
||||
FAT_HMS2B(13,44,16), //last_modified_hms
|
||||
FAT_YMD2B(2019,11,5), //last_modified_ymd
|
||||
FAT_U16(2), //start of file in cluster
|
||||
FAT_U32(sizeof(README_CONTENTS) - 1) //file size
|
||||
},
|
||||
|
||||
//------------- Block3: Readme Content -------------//
|
||||
README_CONTENTS
|
||||
};
|
||||
|
||||
static int32_t onWrite(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){
|
||||
HWSerial.printf("MSC WRITE: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize);
|
||||
memcpy(msc_disk[lba] + offset, buffer, bufsize);
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
static int32_t onRead(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){
|
||||
HWSerial.printf("MSC READ: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize);
|
||||
memcpy(buffer, msc_disk[lba] + offset, bufsize);
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
static bool onStartStop(uint8_t power_condition, bool start, bool load_eject){
|
||||
HWSerial.printf("MSC START/STOP: power: %u, start: %u, eject: %u\n", power_condition, start, load_eject);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
|
||||
if(event_base == ARDUINO_USB_EVENTS){
|
||||
arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data;
|
||||
switch (event_id){
|
||||
case ARDUINO_USB_STARTED_EVENT:
|
||||
HWSerial.println("USB PLUGGED");
|
||||
break;
|
||||
case ARDUINO_USB_STOPPED_EVENT:
|
||||
HWSerial.println("USB UNPLUGGED");
|
||||
break;
|
||||
case ARDUINO_USB_SUSPEND_EVENT:
|
||||
HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en);
|
||||
break;
|
||||
case ARDUINO_USB_RESUME_EVENT:
|
||||
HWSerial.println("USB RESUMED");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
HWSerial.begin(115200);
|
||||
HWSerial.setDebugOutput(true);
|
||||
|
||||
USB.onEvent(usbEventCallback);
|
||||
MSC.vendorID("ESP32");//max 8 chars
|
||||
MSC.productID("USB_MSC");//max 16 chars
|
||||
MSC.productRevision("1.0");//max 4 chars
|
||||
MSC.onStartStop(onStartStop);
|
||||
MSC.onRead(onRead);
|
||||
MSC.onWrite(onWrite);
|
||||
MSC.mediaPresent(true);
|
||||
MSC.begin(DISK_SECTOR_COUNT, DISK_SECTOR_SIZE);
|
||||
USBSerial.begin();
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#include "USB.h"
|
||||
|
||||
#if ARDUINO_SERIAL_PORT
|
||||
#if ARDUINO_USB_CDC_ON_BOOT
|
||||
#define HWSerial Serial0
|
||||
#define USBSerial Serial
|
||||
#else
|
||||
@ -66,14 +66,8 @@ void setup() {
|
||||
USB.onEvent(usbEventCallback);
|
||||
USBSerial.onEvent(usbEventCallback);
|
||||
|
||||
#if !ARDUINO_SERIAL_PORT
|
||||
USB.enableDFU();
|
||||
USB.webUSB(true);
|
||||
USB.webUSBURL("http://localhost/webusb");
|
||||
USB.productName("ESP32S2-USB");
|
||||
USB.begin();
|
||||
USBSerial.begin();
|
||||
#endif
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
0
libraries/USB/examples/USBVendor/.skip.esp32
Normal file
0
libraries/USB/examples/USBVendor/.skip.esp32
Normal file
0
libraries/USB/examples/USBVendor/.skip.esp32c3
Normal file
0
libraries/USB/examples/USBVendor/.skip.esp32c3
Normal file
191
libraries/USB/examples/USBVendor/USBVendor.ino
Normal file
191
libraries/USB/examples/USBVendor/USBVendor.ino
Normal file
@ -0,0 +1,191 @@
|
||||
#include "USB.h"
|
||||
#include "USBVendor.h"
|
||||
|
||||
#if ARDUINO_USB_CDC_ON_BOOT
|
||||
#define HWSerial Serial0
|
||||
#else
|
||||
#define HWSerial Serial
|
||||
#endif
|
||||
|
||||
USBVendor Vendor;
|
||||
const int buttonPin = 0;
|
||||
|
||||
//CDC Control Requests
|
||||
#define REQUEST_SET_LINE_CODING 0x20
|
||||
#define REQUEST_GET_LINE_CODING 0x21
|
||||
#define REQUEST_SET_CONTROL_LINE_STATE 0x22
|
||||
|
||||
//CDC Line Coding Control Request Structure
|
||||
typedef struct __attribute__ ((packed)) {
|
||||
uint32_t bit_rate;
|
||||
uint8_t stop_bits; //0: 1 stop bit, 1: 1.5 stop bits, 2: 2 stop bits
|
||||
uint8_t parity; //0: None, 1: Odd, 2: Even, 3: Mark, 4: Space
|
||||
uint8_t data_bits; //5, 6, 7, 8 or 16
|
||||
} request_line_coding_t;
|
||||
|
||||
static request_line_coding_t vendor_line_coding = {9600, 0, 0, 8};
|
||||
|
||||
// Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send)
|
||||
static uint8_t vendor_line_state = 0;
|
||||
|
||||
//USB and Vendor events
|
||||
static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
|
||||
if (event_base == ARDUINO_USB_EVENTS) {
|
||||
arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data;
|
||||
switch (event_id) {
|
||||
case ARDUINO_USB_STARTED_EVENT:
|
||||
HWSerial.println("USB PLUGGED");
|
||||
break;
|
||||
case ARDUINO_USB_STOPPED_EVENT:
|
||||
HWSerial.println("USB UNPLUGGED");
|
||||
break;
|
||||
case ARDUINO_USB_SUSPEND_EVENT:
|
||||
HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en);
|
||||
break;
|
||||
case ARDUINO_USB_RESUME_EVENT:
|
||||
HWSerial.println("USB RESUMED");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (event_base == ARDUINO_USB_VENDOR_EVENTS) {
|
||||
arduino_usb_vendor_event_data_t * data = (arduino_usb_vendor_event_data_t*)event_data;
|
||||
switch (event_id) {
|
||||
case ARDUINO_USB_VENDOR_DATA_EVENT:
|
||||
HWSerial.printf("Vendor RX: len:%u\n", data->data.len);
|
||||
for (uint16_t i = 0; i < data->data.len; i++) {
|
||||
HWSerial.write(Vendor.read());
|
||||
}
|
||||
HWSerial.println();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char * strRequestDirections[] = {"OUT", "IN"};
|
||||
static const char * strRequestTypes[] = {"STANDARD", "CLASS", "VENDOR", "INVALID"};
|
||||
static const char * strRequestRecipients[] = {"DEVICE", "INTERFACE", "ENDPOINT", "OTHER"};
|
||||
static const char * strRequestStages[] = {"SETUP", "DATA", "ACK"};
|
||||
|
||||
//Handle USB requests to the vendor interface
|
||||
bool vendorRequestCallback(uint8_t rhport, uint8_t requestStage, arduino_usb_control_request_t const * request) {
|
||||
HWSerial.printf("Vendor Request: Stage: %5s, Direction: %3s, Type: %8s, Recipient: %9s, bRequest: 0x%02x, wValue: 0x%04x, wIndex: %u, wLength: %u\n",
|
||||
strRequestStages[requestStage],
|
||||
strRequestDirections[request->bmRequestDirection],
|
||||
strRequestTypes[request->bmRequestType],
|
||||
strRequestRecipients[request->bmRequestRecipient],
|
||||
request->bRequest, request->wValue, request->wIndex, request->wLength);
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (request->bmRequestDirection == REQUEST_DIRECTION_OUT &&
|
||||
request->bmRequestType == REQUEST_TYPE_STANDARD &&
|
||||
request->bmRequestRecipient == REQUEST_RECIPIENT_INTERFACE &&
|
||||
request->bRequest == 0x0b
|
||||
) {
|
||||
if (requestStage == REQUEST_STAGE_SETUP) {
|
||||
// response with status OK
|
||||
result = Vendor.sendResponse(rhport, request);
|
||||
} else {
|
||||
result = true;
|
||||
}
|
||||
} else
|
||||
//Implement CDC Control Requests
|
||||
if (request->bmRequestType == REQUEST_TYPE_CLASS && request->bmRequestRecipient == REQUEST_RECIPIENT_DEVICE) {
|
||||
switch (request->bRequest) {
|
||||
|
||||
case REQUEST_SET_LINE_CODING: //0x20
|
||||
// Accept only direction OUT with data size 7
|
||||
if (request->wLength != sizeof(request_line_coding_t) || request->bmRequestDirection != REQUEST_DIRECTION_OUT) {
|
||||
break;
|
||||
}
|
||||
if (requestStage == REQUEST_STAGE_SETUP) {
|
||||
//Send the response in setup stage (it will write the data to vendor_line_coding in the DATA stage)
|
||||
result = Vendor.sendResponse(rhport, request, (void*) &vendor_line_coding, sizeof(request_line_coding_t));
|
||||
} else if (requestStage == REQUEST_STAGE_ACK) {
|
||||
//In the ACK stage the response is complete
|
||||
HWSerial.printf("Vendor Line Coding: bit_rate: %u, data_bits: %u, stop_bits: %u, parity: %u\n", vendor_line_coding.bit_rate, vendor_line_coding.data_bits, vendor_line_coding.stop_bits, vendor_line_coding.parity);
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
|
||||
case REQUEST_GET_LINE_CODING: //0x21
|
||||
// Accept only direction IN with data size 7
|
||||
if (request->wLength != sizeof(request_line_coding_t) || request->bmRequestDirection != REQUEST_DIRECTION_IN) {
|
||||
break;
|
||||
}
|
||||
if (requestStage == REQUEST_STAGE_SETUP) {
|
||||
//Send the response in setup stage (it will write the data to vendor_line_coding in the DATA stage)
|
||||
result = Vendor.sendResponse(rhport, request, (void*) &vendor_line_coding, sizeof(request_line_coding_t));
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
|
||||
case REQUEST_SET_CONTROL_LINE_STATE: //0x22
|
||||
// Accept only direction OUT with data size 0
|
||||
if (request->wLength != 0 || request->bmRequestDirection != REQUEST_DIRECTION_OUT) {
|
||||
break;
|
||||
}
|
||||
if (requestStage == REQUEST_STAGE_SETUP) {
|
||||
//Send the response in setup stage
|
||||
vendor_line_state = request->wValue;
|
||||
result = Vendor.sendResponse(rhport, request);
|
||||
} else if (requestStage == REQUEST_STAGE_ACK) {
|
||||
//In the ACK stage the response is complete
|
||||
bool dtr = (vendor_line_state & 1) != 0;
|
||||
bool rts = (vendor_line_state & 2) != 0;
|
||||
HWSerial.printf("Vendor Line State: dtr: %u, rts: %u\n", dtr, rts);
|
||||
}
|
||||
result = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
// stall unknown request
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
pinMode(buttonPin, INPUT_PULLUP);
|
||||
HWSerial.begin(115200);
|
||||
HWSerial.setDebugOutput(true);
|
||||
|
||||
Vendor.onEvent(usbEventCallback);
|
||||
Vendor.onRequest(vendorRequestCallback);
|
||||
Vendor.begin();
|
||||
|
||||
USB.onEvent(usbEventCallback);
|
||||
USB.webUSB(true);
|
||||
USB.webUSBURL("http://localhost/webusb");
|
||||
USB.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static int previousButtonState = HIGH;
|
||||
int buttonState = digitalRead(buttonPin);
|
||||
if (buttonState != previousButtonState) {
|
||||
previousButtonState = buttonState;
|
||||
if (buttonState == LOW) {
|
||||
HWSerial.println("Button Pressed");
|
||||
Vendor.println("Button Pressed");
|
||||
} else {
|
||||
Vendor.println("Button Released");
|
||||
HWSerial.println("Button Released");
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
|
||||
while (HWSerial.available()) {
|
||||
size_t l = HWSerial.available();
|
||||
uint8_t b[l];
|
||||
l = HWSerial.read(b, l);
|
||||
Vendor.write(b, l);
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
|
||||
USB KEYWORD1
|
||||
USBCDC KEYWORD1
|
||||
USBMSC KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
@ -18,6 +19,14 @@ end KEYWORD2
|
||||
onEvent KEYWORD2
|
||||
enableReset KEYWORD2
|
||||
|
||||
vendorID KEYWORD2
|
||||
productID KEYWORD2
|
||||
productRevision KEYWORD2
|
||||
mediaPresent KEYWORD2
|
||||
onStartStop KEYWORD2
|
||||
onRead KEYWORD2
|
||||
onWrite KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
365
libraries/USB/src/USBHID.cpp
Normal file
365
libraries/USB/src/USBHID.cpp
Normal file
@ -0,0 +1,365 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "USBHID.h"
|
||||
|
||||
#if CONFIG_TINYUSB_HID_ENABLED
|
||||
|
||||
#include "esp32-hal-tinyusb.h"
|
||||
#include "USB.h"
|
||||
#include "esp_hid_common.h"
|
||||
|
||||
#define USB_HID_DEVICES_MAX 10
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_EVENTS);
|
||||
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait);
|
||||
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg);
|
||||
|
||||
typedef struct {
|
||||
USBHIDDevice * device;
|
||||
uint8_t reports_num;
|
||||
uint8_t * report_ids;
|
||||
} tinyusb_hid_device_t;
|
||||
|
||||
static tinyusb_hid_device_t tinyusb_hid_devices[USB_HID_DEVICES_MAX];
|
||||
|
||||
static uint8_t tinyusb_hid_devices_num = 0;
|
||||
static bool tinyusb_hid_devices_is_initialized = false;
|
||||
static xSemaphoreHandle tinyusb_hid_device_input_sem = NULL;
|
||||
static xSemaphoreHandle tinyusb_hid_device_input_mutex = NULL;
|
||||
|
||||
static bool tinyusb_hid_is_initialized = false;
|
||||
static uint8_t tinyusb_loaded_hid_devices_num = 0;
|
||||
static uint16_t tinyusb_hid_device_descriptor_len = 0;
|
||||
static uint8_t * tinyusb_hid_device_descriptor = NULL;
|
||||
static const char * tinyusb_hid_device_report_types[4] = {"INVALID", "INPUT", "OUTPUT", "FEATURE"};
|
||||
|
||||
static bool tinyusb_enable_hid_device(uint16_t descriptor_len, USBHIDDevice * device){
|
||||
if(tinyusb_hid_is_initialized){
|
||||
log_e("TinyUSB HID has already started! Device not enabled");
|
||||
return false;
|
||||
}
|
||||
if(tinyusb_loaded_hid_devices_num >= USB_HID_DEVICES_MAX){
|
||||
log_e("Maximum devices already enabled! Device not enabled");
|
||||
return false;
|
||||
}
|
||||
tinyusb_hid_device_descriptor_len += descriptor_len;
|
||||
tinyusb_hid_devices[tinyusb_loaded_hid_devices_num++].device = device;
|
||||
|
||||
log_d("Device[%u] len: %u", tinyusb_loaded_hid_devices_num-1, descriptor_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
USBHIDDevice * tinyusb_get_device_by_report_id(uint8_t report_id){
|
||||
for(uint8_t i=0; i<tinyusb_loaded_hid_devices_num; i++){
|
||||
tinyusb_hid_device_t * device = &tinyusb_hid_devices[i];
|
||||
if(device->device && device->reports_num){
|
||||
for(uint8_t r=0; r<device->reports_num; r++){
|
||||
if(report_id == device->report_ids[r]){
|
||||
return device->device;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint16_t tinyusb_on_get_feature(uint8_t report_id, uint8_t* buffer, uint16_t reqlen){
|
||||
USBHIDDevice * device = tinyusb_get_device_by_report_id(report_id);
|
||||
if(device){
|
||||
return device->_onGetFeature(report_id, buffer, reqlen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool tinyusb_on_set_feature(uint8_t report_id, const uint8_t* buffer, uint16_t reqlen){
|
||||
USBHIDDevice * device = tinyusb_get_device_by_report_id(report_id);
|
||||
if(device){
|
||||
device->_onSetFeature(report_id, buffer, reqlen);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool tinyusb_on_set_output(uint8_t report_id, const uint8_t* buffer, uint16_t reqlen){
|
||||
USBHIDDevice * device = tinyusb_get_device_by_report_id(report_id);
|
||||
if(device){
|
||||
device->_onOutput(report_id, buffer, reqlen);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint16_t tinyusb_on_add_descriptor(uint8_t device_index, uint8_t * dst){
|
||||
uint16_t res = 0;
|
||||
uint8_t report_id = 0, reports_num = 0;
|
||||
tinyusb_hid_device_t * device = &tinyusb_hid_devices[device_index];
|
||||
if(device->device){
|
||||
res = device->device->_onGetDescriptor(dst);
|
||||
if(res){
|
||||
|
||||
esp_hid_report_map_t *hid_report_map = esp_hid_parse_report_map(dst, res);
|
||||
if(hid_report_map){
|
||||
if(device->report_ids){
|
||||
free(device->report_ids);
|
||||
}
|
||||
device->reports_num = hid_report_map->reports_len;
|
||||
device->report_ids = (uint8_t*)malloc(device->reports_num);
|
||||
memset(device->report_ids, 0, device->reports_num);
|
||||
reports_num = device->reports_num;
|
||||
|
||||
for(uint8_t i=0; i<device->reports_num; i++){
|
||||
if(hid_report_map->reports[i].protocol_mode == ESP_HID_PROTOCOL_MODE_REPORT){
|
||||
report_id = hid_report_map->reports[i].report_id;
|
||||
for(uint8_t r=0; r<device->reports_num; r++){
|
||||
if(!report_id){
|
||||
//todo: handle better when device has no report ID set
|
||||
break;
|
||||
} else if(report_id == device->report_ids[r]){
|
||||
//already added
|
||||
reports_num--;
|
||||
break;
|
||||
} else if(!device->report_ids[r]){
|
||||
//empty slot
|
||||
device->report_ids[r] = report_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
reports_num--;
|
||||
}
|
||||
}
|
||||
device->reports_num = reports_num;
|
||||
esp_hid_free_report_map(hid_report_map);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static bool tinyusb_load_enabled_hid_devices(){
|
||||
if(tinyusb_hid_device_descriptor != NULL){
|
||||
return true;
|
||||
}
|
||||
tinyusb_hid_device_descriptor = (uint8_t *)malloc(tinyusb_hid_device_descriptor_len);
|
||||
if (tinyusb_hid_device_descriptor == NULL) {
|
||||
log_e("HID Descriptor Malloc Failed");
|
||||
return false;
|
||||
}
|
||||
uint8_t * dst = tinyusb_hid_device_descriptor;
|
||||
|
||||
for(uint8_t i=0; i<tinyusb_loaded_hid_devices_num; i++){
|
||||
uint16_t len = tinyusb_on_add_descriptor(i, dst);
|
||||
if (!len) {
|
||||
break;
|
||||
} else {
|
||||
dst += len;
|
||||
}
|
||||
}
|
||||
|
||||
esp_hid_report_map_t *hid_report_map = esp_hid_parse_report_map(tinyusb_hid_device_descriptor, tinyusb_hid_device_descriptor_len);
|
||||
if(hid_report_map){
|
||||
log_d("Loaded HID Desriptor with the following reports:");
|
||||
for(uint8_t i=0; i<hid_report_map->reports_len; i++){
|
||||
if(hid_report_map->reports[i].protocol_mode == ESP_HID_PROTOCOL_MODE_REPORT){
|
||||
log_d(" ID: %3u, Type: %7s, Size: %2u, Usage: %8s",
|
||||
hid_report_map->reports[i].report_id,
|
||||
esp_hid_report_type_str(hid_report_map->reports[i].report_type),
|
||||
hid_report_map->reports[i].value_len,
|
||||
esp_hid_usage_str(hid_report_map->reports[i].usage)
|
||||
);
|
||||
}
|
||||
}
|
||||
esp_hid_free_report_map(hid_report_map);
|
||||
} else {
|
||||
log_e("Failed to parse the hid report descriptor!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" uint16_t tusb_hid_load_descriptor(uint8_t * dst, uint8_t * itf)
|
||||
{
|
||||
if(tinyusb_hid_is_initialized){
|
||||
return 0;
|
||||
}
|
||||
tinyusb_hid_is_initialized = true;
|
||||
|
||||
uint8_t str_index = tinyusb_add_string_descriptor("TinyUSB HID");
|
||||
uint8_t ep_in = tinyusb_get_free_in_endpoint();
|
||||
TU_VERIFY (ep_in != 0);
|
||||
uint8_t ep_out = tinyusb_get_free_out_endpoint();
|
||||
TU_VERIFY (ep_out != 0);
|
||||
uint8_t descriptor[TUD_HID_INOUT_DESC_LEN] = {
|
||||
// HID Input & Output descriptor
|
||||
// Interface number, string index, protocol, report descriptor len, EP OUT & IN address, size & polling interval
|
||||
TUD_HID_INOUT_DESCRIPTOR(*itf, str_index, HID_ITF_PROTOCOL_NONE, tinyusb_hid_device_descriptor_len, ep_out, (uint8_t)(0x80 | ep_in), 64, 1)
|
||||
};
|
||||
*itf+=1;
|
||||
memcpy(dst, descriptor, TUD_HID_INOUT_DESC_LEN);
|
||||
return TUD_HID_INOUT_DESC_LEN;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Invoked when received GET HID REPORT DESCRIPTOR request
|
||||
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
|
||||
uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance){
|
||||
log_v("instance: %u", instance);
|
||||
if(!tinyusb_load_enabled_hid_devices()){
|
||||
return NULL;
|
||||
}
|
||||
return tinyusb_hid_device_descriptor;
|
||||
}
|
||||
|
||||
// Invoked when received SET_PROTOCOL request
|
||||
// protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
|
||||
void tud_hid_set_protocol_cb(uint8_t instance, uint8_t protocol){
|
||||
log_v("instance: %u, protocol:%u", instance, protocol);
|
||||
arduino_usb_hid_event_data_t p = {0};
|
||||
p.instance = instance;
|
||||
p.set_protocol.protocol = protocol;
|
||||
arduino_usb_event_post(ARDUINO_USB_HID_EVENTS, ARDUINO_USB_HID_SET_PROTOCOL_EVENT, &p, sizeof(arduino_usb_hid_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
// Invoked when received SET_IDLE request. return false will stall the request
|
||||
// - Idle Rate = 0 : only send report if there is changes, i.e skip duplication
|
||||
// - Idle Rate > 0 : skip duplication, but send at least 1 report every idle rate (in unit of 4 ms).
|
||||
bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate){
|
||||
log_v("instance: %u, idle_rate:%u", instance, idle_rate);
|
||||
arduino_usb_hid_event_data_t p = {0};
|
||||
p.instance = instance;
|
||||
p.set_idle.idle_rate = idle_rate;
|
||||
arduino_usb_event_post(ARDUINO_USB_HID_EVENTS, ARDUINO_USB_HID_SET_IDLE_EVENT, &p, sizeof(arduino_usb_hid_event_data_t), portMAX_DELAY);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Invoked when received GET_REPORT control request
|
||||
// Application must fill buffer report's content and return its length.
|
||||
// Return zero will cause the stack to STALL request
|
||||
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen){
|
||||
uint16_t res = tinyusb_on_get_feature(report_id, buffer, reqlen);
|
||||
if(!res){
|
||||
log_d("instance: %u, report_id: %u, report_type: %s, reqlen: %u", instance, report_id, tinyusb_hid_device_report_types[report_type], reqlen);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Invoked when received SET_REPORT control request or
|
||||
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize){
|
||||
if(!report_id && !report_type){
|
||||
if(!tinyusb_on_set_output(0, buffer, bufsize) && !tinyusb_on_set_output(buffer[0], buffer+1, bufsize-1)){
|
||||
log_d("instance: %u, report_id: %u, report_type: %s, bufsize: %u", instance, buffer[0], tinyusb_hid_device_report_types[HID_REPORT_TYPE_OUTPUT], bufsize-1);
|
||||
}
|
||||
} else {
|
||||
if(!tinyusb_on_set_feature(report_id, buffer, bufsize)){
|
||||
log_d("instance: %u, report_id: %u, report_type: %s, bufsize: %u", instance, report_id, tinyusb_hid_device_report_types[report_type], bufsize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
USBHID::USBHID(){
|
||||
if(!tinyusb_hid_devices_is_initialized){
|
||||
tinyusb_hid_devices_is_initialized = true;
|
||||
for(uint8_t i=0; i<USB_HID_DEVICES_MAX; i++){
|
||||
memset(&tinyusb_hid_devices[i], 0, sizeof(tinyusb_hid_device_t));
|
||||
}
|
||||
tinyusb_hid_devices_num = 0;
|
||||
tinyusb_enable_interface(USB_INTERFACE_HID, TUD_HID_INOUT_DESC_LEN, tusb_hid_load_descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
void USBHID::begin(){
|
||||
if(tinyusb_hid_device_input_sem == NULL){
|
||||
tinyusb_hid_device_input_sem = xSemaphoreCreateBinary();
|
||||
}
|
||||
if(tinyusb_hid_device_input_mutex == NULL){
|
||||
tinyusb_hid_device_input_mutex = xSemaphoreCreateMutex();
|
||||
}
|
||||
}
|
||||
|
||||
void USBHID::end(){
|
||||
if (tinyusb_hid_device_input_sem != NULL) {
|
||||
vSemaphoreDelete(tinyusb_hid_device_input_sem);
|
||||
tinyusb_hid_device_input_sem = NULL;
|
||||
}
|
||||
if (tinyusb_hid_device_input_mutex != NULL) {
|
||||
vSemaphoreDelete(tinyusb_hid_device_input_mutex);
|
||||
tinyusb_hid_device_input_mutex = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool USBHID::ready(void){
|
||||
return tud_hid_n_ready(0);
|
||||
}
|
||||
|
||||
void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint8_t len){
|
||||
if (tinyusb_hid_device_input_sem) {
|
||||
xSemaphoreGive(tinyusb_hid_device_input_sem);
|
||||
}
|
||||
}
|
||||
|
||||
bool USBHID::SendReport(uint8_t id, const void* data, size_t len, uint32_t timeout_ms){
|
||||
if(!tinyusb_hid_device_input_sem || !tinyusb_hid_device_input_mutex){
|
||||
log_e("TX Semaphore is NULL. You must call USBHID::begin() before you can send reports");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(xSemaphoreTake(tinyusb_hid_device_input_mutex, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){
|
||||
log_e("report %u mutex failed", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool res = ready();
|
||||
if(!res){
|
||||
log_e("not ready");
|
||||
} else {
|
||||
res = tud_hid_n_report(0, id, data, len);
|
||||
if(!res){
|
||||
log_e("report %u failed", id);
|
||||
} else {
|
||||
xSemaphoreTake(tinyusb_hid_device_input_sem, 0);
|
||||
if(xSemaphoreTake(tinyusb_hid_device_input_sem, timeout_ms / portTICK_PERIOD_MS) != pdTRUE){
|
||||
log_e("report %u wait failed", id);
|
||||
res = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xSemaphoreGive(tinyusb_hid_device_input_mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool USBHID::addDevice(USBHIDDevice * device, uint16_t descriptor_len){
|
||||
if(device && tinyusb_loaded_hid_devices_num < USB_HID_DEVICES_MAX){
|
||||
if(!tinyusb_enable_hid_device(descriptor_len, device)){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void USBHID::onEvent(esp_event_handler_t callback){
|
||||
onEvent(ARDUINO_USB_HID_ANY_EVENT, callback);
|
||||
}
|
||||
void USBHID::onEvent(arduino_usb_hid_event_t event, esp_event_handler_t callback){
|
||||
arduino_usb_event_handler_register_with(ARDUINO_USB_HID_EVENTS, event, callback, this);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TINYUSB_HID_ENABLED */
|
79
libraries/USB/src/USBHID.h
Normal file
79
libraries/USB/src/USBHID.h
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_TINYUSB_HID_ENABLED
|
||||
#include "esp_event.h"
|
||||
#include "class/hid/hid.h"
|
||||
#include "class/hid/hid_device.h"
|
||||
|
||||
// Used by the included TinyUSB drivers
|
||||
enum {
|
||||
HID_REPORT_ID_NONE,
|
||||
HID_REPORT_ID_KEYBOARD,
|
||||
HID_REPORT_ID_MOUSE,
|
||||
HID_REPORT_ID_GAMEPAD,
|
||||
HID_REPORT_ID_CONSUMER_CONTROL,
|
||||
HID_REPORT_ID_SYSTEM_CONTROL,
|
||||
HID_REPORT_ID_VENDOR
|
||||
};
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_HID_EVENTS);
|
||||
|
||||
typedef enum {
|
||||
ARDUINO_USB_HID_ANY_EVENT = ESP_EVENT_ANY_ID,
|
||||
ARDUINO_USB_HID_SET_PROTOCOL_EVENT = 0,
|
||||
ARDUINO_USB_HID_SET_IDLE_EVENT,
|
||||
ARDUINO_USB_HID_MAX_EVENT,
|
||||
} arduino_usb_hid_event_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t instance;
|
||||
union {
|
||||
struct {
|
||||
uint8_t protocol;
|
||||
} set_protocol;
|
||||
struct {
|
||||
uint8_t idle_rate;
|
||||
} set_idle;
|
||||
};
|
||||
} arduino_usb_hid_event_data_t;
|
||||
|
||||
class USBHIDDevice
|
||||
{
|
||||
public:
|
||||
virtual uint16_t _onGetDescriptor(uint8_t* buffer){return 0;}
|
||||
virtual uint16_t _onGetFeature(uint8_t report_id, uint8_t* buffer, uint16_t len){return 0;}
|
||||
virtual void _onSetFeature(uint8_t report_id, const uint8_t* buffer, uint16_t len){}
|
||||
virtual void _onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t len){}
|
||||
};
|
||||
|
||||
class USBHID
|
||||
{
|
||||
public:
|
||||
USBHID(void);
|
||||
void begin(void);
|
||||
void end(void);
|
||||
bool ready(void);
|
||||
bool SendReport(uint8_t report_id, const void* data, size_t len, uint32_t timeout_ms = 100);
|
||||
void onEvent(esp_event_handler_t callback);
|
||||
void onEvent(arduino_usb_hid_event_t event, esp_event_handler_t callback);
|
||||
static bool addDevice(USBHIDDevice * device, uint16_t descriptor_len);
|
||||
};
|
||||
|
||||
#endif /* CONFIG_TINYUSB_HID_ENABLED */
|
57
libraries/USB/src/USBHIDConsumerControl.cpp
Normal file
57
libraries/USB/src/USBHIDConsumerControl.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "USBHID.h"
|
||||
|
||||
#if CONFIG_TINYUSB_HID_ENABLED
|
||||
|
||||
#include "USBHIDConsumerControl.h"
|
||||
|
||||
static const uint8_t report_descriptor[] = {
|
||||
TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(HID_REPORT_ID_CONSUMER_CONTROL))
|
||||
};
|
||||
|
||||
USBHIDConsumerControl::USBHIDConsumerControl(): hid(){
|
||||
static bool initialized = false;
|
||||
if(!initialized){
|
||||
initialized = true;
|
||||
hid.addDevice(this, sizeof(report_descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t USBHIDConsumerControl::_onGetDescriptor(uint8_t* dst){
|
||||
memcpy(dst, report_descriptor, sizeof(report_descriptor));
|
||||
return sizeof(report_descriptor);
|
||||
}
|
||||
|
||||
void USBHIDConsumerControl::begin(){
|
||||
hid.begin();
|
||||
}
|
||||
|
||||
void USBHIDConsumerControl::end(){
|
||||
}
|
||||
|
||||
bool USBHIDConsumerControl::send(uint16_t value){
|
||||
return hid.SendReport(HID_REPORT_ID_CONSUMER_CONTROL, &value, 2);
|
||||
}
|
||||
|
||||
size_t USBHIDConsumerControl::press(uint16_t k){
|
||||
return send(k);
|
||||
}
|
||||
|
||||
size_t USBHIDConsumerControl::release(){
|
||||
return send(0);
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_TINYUSB_HID_ENABLED */
|
85
libraries/USB/src/USBHIDConsumerControl.h
Normal file
85
libraries/USB/src/USBHIDConsumerControl.h
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include "USBHID.h"
|
||||
#if CONFIG_TINYUSB_HID_ENABLED
|
||||
|
||||
// Power Control
|
||||
#define CONSUMER_CONTROL_POWER 0x0030
|
||||
#define CONSUMER_CONTROL_RESET 0x0031
|
||||
#define CONSUMER_CONTROL_SLEEP 0x0032
|
||||
|
||||
// Screen Brightness
|
||||
#define CONSUMER_CONTROL_BRIGHTNESS_INCREMENT 0x006F
|
||||
#define CONSUMER_CONTROL_BRIGHTNESS_DECREMENT 0x0070
|
||||
|
||||
// These HID usages operate only on mobile systems (battery powered) and
|
||||
// require Windows 8 (build 8302 or greater).
|
||||
#define CONSUMER_CONTROL_WIRELESS_RADIO_CONTROLS 0x000C
|
||||
#define CONSUMER_CONTROL_WIRELESS_RADIO_BUTTONS 0x00C6
|
||||
#define CONSUMER_CONTROL_WIRELESS_RADIO_LED 0x00C7
|
||||
#define CONSUMER_CONTROL_WIRELESS_RADIO_SLIDER_SWITCH 0x00C8
|
||||
|
||||
// Media Control
|
||||
#define CONSUMER_CONTROL_PLAY_PAUSE 0x00CD
|
||||
#define CONSUMER_CONTROL_SCAN_NEXT 0x00B5
|
||||
#define CONSUMER_CONTROL_SCAN_PREVIOUS 0x00B6
|
||||
#define CONSUMER_CONTROL_STOP 0x00B7
|
||||
#define CONSUMER_CONTROL_VOLUME 0x00E0
|
||||
#define CONSUMER_CONTROL_MUTE 0x00E2
|
||||
#define CONSUMER_CONTROL_BASS 0x00E3
|
||||
#define CONSUMER_CONTROL_TREBLE 0x00E4
|
||||
#define CONSUMER_CONTROL_BASS_BOOST 0x00E5
|
||||
#define CONSUMER_CONTROL_VOLUME_INCREMENT 0x00E9
|
||||
#define CONSUMER_CONTROL_VOLUME_DECREMENT 0x00EA
|
||||
#define CONSUMER_CONTROL_BASS_INCREMENT 0x0152
|
||||
#define CONSUMER_CONTROL_BASS_DECREMENT 0x0153
|
||||
#define CONSUMER_CONTROL_TREBLE_INCREMENT 0x0154
|
||||
#define CONSUMER_CONTROL_TREBLE_DECREMENT 0x0155
|
||||
|
||||
// Application Launcher
|
||||
#define CONSUMER_CONTROL_CONFIGURATION 0x0183
|
||||
#define CONSUMER_CONTROL_EMAIL_READER 0x018A
|
||||
#define CONSUMER_CONTROL_CALCULATOR 0x0192
|
||||
#define CONSUMER_CONTROL_LOCAL_BROWSER 0x0194
|
||||
|
||||
// Browser/Explorer Specific
|
||||
#define CONSUMER_CONTROL_SEARCH 0x0221
|
||||
#define CONSUMER_CONTROL_HOME 0x0223
|
||||
#define CONSUMER_CONTROL_BACK 0x0224
|
||||
#define CONSUMER_CONTROL_FORWARD 0x0225
|
||||
#define CONSUMER_CONTROL_BR_STOP 0x0226
|
||||
#define CONSUMER_CONTROL_REFRESH 0x0227
|
||||
#define CONSUMER_CONTROL_BOOKMARKS 0x022A
|
||||
|
||||
// Mouse Horizontal scroll
|
||||
#define CONSUMER_CONTROL_PAN 0x0238
|
||||
|
||||
class USBHIDConsumerControl: public USBHIDDevice {
|
||||
private:
|
||||
USBHID hid;
|
||||
bool send(uint16_t value);
|
||||
public:
|
||||
USBHIDConsumerControl(void);
|
||||
void begin(void);
|
||||
void end(void);
|
||||
size_t press(uint16_t k);
|
||||
size_t release();
|
||||
|
||||
// internal use
|
||||
uint16_t _onGetDescriptor(uint8_t* buffer);
|
||||
};
|
||||
|
||||
#endif
|
121
libraries/USB/src/USBHIDGamepad.cpp
Normal file
121
libraries/USB/src/USBHIDGamepad.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "USBHID.h"
|
||||
|
||||
#if CONFIG_TINYUSB_HID_ENABLED
|
||||
|
||||
#include "USBHIDGamepad.h"
|
||||
|
||||
static const uint8_t report_descriptor[] = {
|
||||
TUD_HID_REPORT_DESC_GAMEPAD(HID_REPORT_ID(HID_REPORT_ID_GAMEPAD))
|
||||
};
|
||||
|
||||
USBHIDGamepad::USBHIDGamepad(): hid(), _x(0), _y(0), _z(0), _rz(0), _rx(0), _ry(0), _hat(0), _buttons(0){
|
||||
static bool initialized = false;
|
||||
if(!initialized){
|
||||
initialized = true;
|
||||
hid.addDevice(this, sizeof(report_descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t USBHIDGamepad::_onGetDescriptor(uint8_t* dst){
|
||||
memcpy(dst, report_descriptor, sizeof(report_descriptor));
|
||||
return sizeof(report_descriptor);
|
||||
}
|
||||
|
||||
void USBHIDGamepad::begin(){
|
||||
hid.begin();
|
||||
}
|
||||
|
||||
void USBHIDGamepad::end(){
|
||||
|
||||
}
|
||||
|
||||
bool USBHIDGamepad::write(){
|
||||
hid_gamepad_report_t report = {
|
||||
.x = _x,
|
||||
.y = _y,
|
||||
.z = _z,
|
||||
.rz = _rz,
|
||||
.rx = _rx,
|
||||
.ry = _ry,
|
||||
.hat = _hat,
|
||||
.buttons = _buttons
|
||||
};
|
||||
return hid.SendReport(HID_REPORT_ID_GAMEPAD, &report, sizeof(report));
|
||||
}
|
||||
|
||||
bool USBHIDGamepad::leftStick(int8_t x, int8_t y){
|
||||
_x = x;
|
||||
_y = y;
|
||||
return write();
|
||||
}
|
||||
|
||||
bool USBHIDGamepad::rightStick(int8_t z, int8_t rz){
|
||||
_z = z;
|
||||
_rz = rz;
|
||||
return write();
|
||||
}
|
||||
|
||||
bool USBHIDGamepad::leftTrigger(int8_t rx){
|
||||
_rx = rx;
|
||||
return write();
|
||||
}
|
||||
|
||||
bool USBHIDGamepad::rightTrigger(int8_t ry){
|
||||
_ry = ry;
|
||||
return write();
|
||||
}
|
||||
|
||||
bool USBHIDGamepad::hat(uint8_t hat){
|
||||
if(hat > 9){
|
||||
return false;
|
||||
}
|
||||
_hat = hat;
|
||||
return write();
|
||||
}
|
||||
|
||||
bool USBHIDGamepad::pressButton(uint8_t button){
|
||||
if(button > 31){
|
||||
return false;
|
||||
}
|
||||
_buttons |= (1 << button);
|
||||
return write();
|
||||
}
|
||||
|
||||
bool USBHIDGamepad::releaseButton(uint8_t button){
|
||||
if(button > 31){
|
||||
return false;
|
||||
}
|
||||
_buttons &= ~(1 << button);
|
||||
return write();
|
||||
}
|
||||
|
||||
bool USBHIDGamepad::send(int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons){
|
||||
if(hat > 9){
|
||||
return false;
|
||||
}
|
||||
_x = x;
|
||||
_y = y;
|
||||
_z = z;
|
||||
_rz = rz;
|
||||
_rx = rx;
|
||||
_ry = ry;
|
||||
_hat = hat;
|
||||
_buttons = buttons;
|
||||
return write();
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_TINYUSB_HID_ENABLED */
|
87
libraries/USB/src/USBHIDGamepad.h
Normal file
87
libraries/USB/src/USBHIDGamepad.h
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include "USBHID.h"
|
||||
#if CONFIG_TINYUSB_HID_ENABLED
|
||||
|
||||
/// Standard Gamepad Buttons Naming from Linux input event codes
|
||||
/// https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
|
||||
#define BUTTON_A 0
|
||||
#define BUTTON_B 1
|
||||
#define BUTTON_C 2
|
||||
#define BUTTON_X 3
|
||||
#define BUTTON_Y 4
|
||||
#define BUTTON_Z 5
|
||||
#define BUTTON_TL 6
|
||||
#define BUTTON_TR 7
|
||||
#define BUTTON_TL2 8
|
||||
#define BUTTON_TR2 9
|
||||
#define BUTTON_SELECT 10
|
||||
#define BUTTON_START 11
|
||||
#define BUTTON_MODE 12
|
||||
#define BUTTON_THUMBL 13
|
||||
#define BUTTON_THUMBR 14
|
||||
|
||||
#define BUTTON_SOUTH BUTTON_A
|
||||
#define BUTTON_EAST BUTTON_B
|
||||
#define BUTTON_NORTH BUTTON_X
|
||||
#define BUTTON_WEST BUTTON_Y
|
||||
|
||||
/// Standard Gamepad HAT/DPAD Buttons (from Linux input event codes)
|
||||
#define HAT_CENTER 0
|
||||
#define HAT_UP 1
|
||||
#define HAT_UP_RIGHT 2
|
||||
#define HAT_RIGHT 3
|
||||
#define HAT_DOWN_RIGHT 4
|
||||
#define HAT_DOWN 5
|
||||
#define HAT_DOWN_LEFT 6
|
||||
#define HAT_LEFT 7
|
||||
#define HAT_UP_LEFT 8
|
||||
|
||||
class USBHIDGamepad: public USBHIDDevice {
|
||||
private:
|
||||
USBHID hid;
|
||||
int8_t _x; ///< Delta x movement of left analog-stick
|
||||
int8_t _y; ///< Delta y movement of left analog-stick
|
||||
int8_t _z; ///< Delta z movement of right analog-joystick
|
||||
int8_t _rz; ///< Delta Rz movement of right analog-joystick
|
||||
int8_t _rx; ///< Delta Rx movement of analog left trigger
|
||||
int8_t _ry; ///< Delta Ry movement of analog right trigger
|
||||
uint8_t _hat; ///< Buttons mask for currently pressed buttons in the DPad/hat
|
||||
uint32_t _buttons; ///< Buttons mask for currently pressed buttons
|
||||
bool write();
|
||||
public:
|
||||
USBHIDGamepad(void);
|
||||
void begin(void);
|
||||
void end(void);
|
||||
|
||||
bool leftStick(int8_t x, int8_t y);
|
||||
bool rightStick(int8_t z, int8_t rz);
|
||||
|
||||
bool leftTrigger(int8_t rx);
|
||||
bool rightTrigger(int8_t ry);
|
||||
|
||||
bool hat(uint8_t hat);
|
||||
|
||||
bool pressButton(uint8_t button);
|
||||
bool releaseButton(uint8_t button);
|
||||
|
||||
bool send(int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons);
|
||||
|
||||
// internal use
|
||||
uint16_t _onGetDescriptor(uint8_t* buffer);
|
||||
};
|
||||
|
||||
#endif
|
354
libraries/USB/src/USBHIDKeyboard.cpp
Normal file
354
libraries/USB/src/USBHIDKeyboard.cpp
Normal file
@ -0,0 +1,354 @@
|
||||
/*
|
||||
Keyboard.cpp
|
||||
|
||||
Copyright (c) 2015, Arduino LLC
|
||||
Original code (pre-library): Copyright (c) 2011, Peter Barrett
|
||||
|
||||
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 2.1 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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "USBHID.h"
|
||||
|
||||
#if CONFIG_TINYUSB_HID_ENABLED
|
||||
|
||||
#include "USBHIDKeyboard.h"
|
||||
|
||||
ESP_EVENT_DEFINE_BASE(ARDUINO_USB_HID_KEYBOARD_EVENTS);
|
||||
esp_err_t arduino_usb_event_post(esp_event_base_t event_base, int32_t event_id, void *event_data, size_t event_data_size, TickType_t ticks_to_wait);
|
||||
esp_err_t arduino_usb_event_handler_register_with(esp_event_base_t event_base, int32_t event_id, esp_event_handler_t event_handler, void *event_handler_arg);
|
||||
|
||||
static const uint8_t report_descriptor[] = {
|
||||
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(HID_REPORT_ID_KEYBOARD))
|
||||
};
|
||||
|
||||
USBHIDKeyboard::USBHIDKeyboard(): hid(){
|
||||
static bool initialized = false;
|
||||
if(!initialized){
|
||||
initialized = true;
|
||||
hid.addDevice(this, sizeof(report_descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t USBHIDKeyboard::_onGetDescriptor(uint8_t* dst){
|
||||
memcpy(dst, report_descriptor, sizeof(report_descriptor));
|
||||
return sizeof(report_descriptor);
|
||||
}
|
||||
|
||||
void USBHIDKeyboard::begin(){
|
||||
hid.begin();
|
||||
}
|
||||
|
||||
void USBHIDKeyboard::end(){
|
||||
}
|
||||
|
||||
void USBHIDKeyboard::onEvent(esp_event_handler_t callback){
|
||||
onEvent(ARDUINO_USB_HID_KEYBOARD_ANY_EVENT, callback);
|
||||
}
|
||||
void USBHIDKeyboard::onEvent(arduino_usb_hid_keyboard_event_t event, esp_event_handler_t callback){
|
||||
arduino_usb_event_handler_register_with(ARDUINO_USB_HID_KEYBOARD_EVENTS, event, callback, this);
|
||||
}
|
||||
|
||||
void USBHIDKeyboard::_onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t len){
|
||||
if(report_id == HID_REPORT_ID_KEYBOARD){
|
||||
arduino_usb_hid_keyboard_event_data_t p = {0};
|
||||
p.leds = buffer[0];
|
||||
arduino_usb_event_post(ARDUINO_USB_HID_KEYBOARD_EVENTS, ARDUINO_USB_HID_KEYBOARD_LED_EVENT, &p, sizeof(arduino_usb_hid_keyboard_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void USBHIDKeyboard::sendReport(KeyReport* keys)
|
||||
{
|
||||
hid_keyboard_report_t report;
|
||||
report.reserved = 0;
|
||||
report.modifier = keys->modifiers;
|
||||
if (keys->keys) {
|
||||
memcpy(report.keycode, keys->keys, 6);
|
||||
} else {
|
||||
memset(report.keycode, 0, 6);
|
||||
}
|
||||
hid.SendReport(HID_REPORT_ID_KEYBOARD, &report, sizeof(report));
|
||||
}
|
||||
|
||||
#define SHIFT 0x80
|
||||
const uint8_t _asciimap[128] =
|
||||
{
|
||||
0x00, // NUL
|
||||
0x00, // SOH
|
||||
0x00, // STX
|
||||
0x00, // ETX
|
||||
0x00, // EOT
|
||||
0x00, // ENQ
|
||||
0x00, // ACK
|
||||
0x00, // BEL
|
||||
0x2a, // BS Backspace
|
||||
0x2b, // TAB Tab
|
||||
0x28, // LF Enter
|
||||
0x00, // VT
|
||||
0x00, // FF
|
||||
0x00, // CR
|
||||
0x00, // SO
|
||||
0x00, // SI
|
||||
0x00, // DEL
|
||||
0x00, // DC1
|
||||
0x00, // DC2
|
||||
0x00, // DC3
|
||||
0x00, // DC4
|
||||
0x00, // NAK
|
||||
0x00, // SYN
|
||||
0x00, // ETB
|
||||
0x00, // CAN
|
||||
0x00, // EM
|
||||
0x00, // SUB
|
||||
0x00, // ESC
|
||||
0x00, // FS
|
||||
0x00, // GS
|
||||
0x00, // RS
|
||||
0x00, // US
|
||||
|
||||
0x2c, // ' '
|
||||
0x1e|SHIFT, // !
|
||||
0x34|SHIFT, // "
|
||||
0x20|SHIFT, // #
|
||||
0x21|SHIFT, // $
|
||||
0x22|SHIFT, // %
|
||||
0x24|SHIFT, // &
|
||||
0x34, // '
|
||||
0x26|SHIFT, // (
|
||||
0x27|SHIFT, // )
|
||||
0x25|SHIFT, // *
|
||||
0x2e|SHIFT, // +
|
||||
0x36, // ,
|
||||
0x2d, // -
|
||||
0x37, // .
|
||||
0x38, // /
|
||||
0x27, // 0
|
||||
0x1e, // 1
|
||||
0x1f, // 2
|
||||
0x20, // 3
|
||||
0x21, // 4
|
||||
0x22, // 5
|
||||
0x23, // 6
|
||||
0x24, // 7
|
||||
0x25, // 8
|
||||
0x26, // 9
|
||||
0x33|SHIFT, // :
|
||||
0x33, // ;
|
||||
0x36|SHIFT, // <
|
||||
0x2e, // =
|
||||
0x37|SHIFT, // >
|
||||
0x38|SHIFT, // ?
|
||||
0x1f|SHIFT, // @
|
||||
0x04|SHIFT, // A
|
||||
0x05|SHIFT, // B
|
||||
0x06|SHIFT, // C
|
||||
0x07|SHIFT, // D
|
||||
0x08|SHIFT, // E
|
||||
0x09|SHIFT, // F
|
||||
0x0a|SHIFT, // G
|
||||
0x0b|SHIFT, // H
|
||||
0x0c|SHIFT, // I
|
||||
0x0d|SHIFT, // J
|
||||
0x0e|SHIFT, // K
|
||||
0x0f|SHIFT, // L
|
||||
0x10|SHIFT, // M
|
||||
0x11|SHIFT, // N
|
||||
0x12|SHIFT, // O
|
||||
0x13|SHIFT, // P
|
||||
0x14|SHIFT, // Q
|
||||
0x15|SHIFT, // R
|
||||
0x16|SHIFT, // S
|
||||
0x17|SHIFT, // T
|
||||
0x18|SHIFT, // U
|
||||
0x19|SHIFT, // V
|
||||
0x1a|SHIFT, // W
|
||||
0x1b|SHIFT, // X
|
||||
0x1c|SHIFT, // Y
|
||||
0x1d|SHIFT, // Z
|
||||
0x2f, // [
|
||||
0x31, // bslash
|
||||
0x30, // ]
|
||||
0x23|SHIFT, // ^
|
||||
0x2d|SHIFT, // _
|
||||
0x35, // `
|
||||
0x04, // a
|
||||
0x05, // b
|
||||
0x06, // c
|
||||
0x07, // d
|
||||
0x08, // e
|
||||
0x09, // f
|
||||
0x0a, // g
|
||||
0x0b, // h
|
||||
0x0c, // i
|
||||
0x0d, // j
|
||||
0x0e, // k
|
||||
0x0f, // l
|
||||
0x10, // m
|
||||
0x11, // n
|
||||
0x12, // o
|
||||
0x13, // p
|
||||
0x14, // q
|
||||
0x15, // r
|
||||
0x16, // s
|
||||
0x17, // t
|
||||
0x18, // u
|
||||
0x19, // v
|
||||
0x1a, // w
|
||||
0x1b, // x
|
||||
0x1c, // y
|
||||
0x1d, // z
|
||||
0x2f|SHIFT, // {
|
||||
0x31|SHIFT, // |
|
||||
0x30|SHIFT, // }
|
||||
0x35|SHIFT, // ~
|
||||
0 // DEL
|
||||
};
|
||||
|
||||
size_t USBHIDKeyboard::pressRaw(uint8_t k)
|
||||
{
|
||||
uint8_t i;
|
||||
if (k >= 0xE0 && k < 0xE8) {
|
||||
// it's a modifier key
|
||||
_keyReport.modifiers |= (1<<(k-0x80));
|
||||
} else if (k && k < 0xA5) {
|
||||
// Add k to the key report only if it's not already present
|
||||
// and if there is an empty slot.
|
||||
if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&
|
||||
_keyReport.keys[2] != k && _keyReport.keys[3] != k &&
|
||||
_keyReport.keys[4] != k && _keyReport.keys[5] != k) {
|
||||
|
||||
for (i=0; i<6; i++) {
|
||||
if (_keyReport.keys[i] == 0x00) {
|
||||
_keyReport.keys[i] = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 6) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//not a modifier and not a key
|
||||
return 0;
|
||||
}
|
||||
sendReport(&_keyReport);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t USBHIDKeyboard::releaseRaw(uint8_t k)
|
||||
{
|
||||
uint8_t i;
|
||||
if (k >= 0xE0 && k < 0xE8) {
|
||||
// it's a modifier key
|
||||
_keyReport.modifiers &= ~(1<<(k-0x80));
|
||||
} else if (k && k < 0xA5) {
|
||||
// Test the key report to see if k is present. Clear it if it exists.
|
||||
// Check all positions in case the key is present more than once (which it shouldn't be)
|
||||
for (i=0; i<6; i++) {
|
||||
if (0 != k && _keyReport.keys[i] == k) {
|
||||
_keyReport.keys[i] = 0x00;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//not a modifier and not a key
|
||||
return 0;
|
||||
}
|
||||
|
||||
sendReport(&_keyReport);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// press() adds the specified key (printing, non-printing, or modifier)
|
||||
// to the persistent key report and sends the report. Because of the way
|
||||
// USB HID works, the host acts like the key remains pressed until we
|
||||
// call release(), releaseAll(), or otherwise clear the report and resend.
|
||||
size_t USBHIDKeyboard::press(uint8_t k)
|
||||
{
|
||||
uint8_t i;
|
||||
if (k >= 0x88) { // it's a non-printing key (not a modifier)
|
||||
k = k - 0x88;
|
||||
} else if (k >= 0x80) { // it's a modifier key
|
||||
_keyReport.modifiers |= (1<<(k-0x80));
|
||||
k = 0;
|
||||
} else { // it's a printing key
|
||||
k = _asciimap[k];
|
||||
if (!k) {
|
||||
return 0;
|
||||
}
|
||||
if (k & 0x80) { // it's a capital letter or other character reached with shift
|
||||
_keyReport.modifiers |= 0x02; // the left shift modifier
|
||||
k &= 0x7F;
|
||||
}
|
||||
}
|
||||
return pressRaw(k);
|
||||
}
|
||||
|
||||
// release() takes the specified key out of the persistent key report and
|
||||
// sends the report. This tells the OS the key is no longer pressed and that
|
||||
// it shouldn't be repeated any more.
|
||||
size_t USBHIDKeyboard::release(uint8_t k)
|
||||
{
|
||||
uint8_t i;
|
||||
if (k >= 0x88) { // it's a non-printing key (not a modifier)
|
||||
k = k - 0x88;
|
||||
} else if (k >= 0x80) { // it's a modifier key
|
||||
_keyReport.modifiers &= ~(1<<(k-0x80));
|
||||
k = 0;
|
||||
} else { // it's a printing key
|
||||
k = _asciimap[k];
|
||||
if (!k) {
|
||||
return 0;
|
||||
}
|
||||
if (k & 0x80) { // it's a capital letter or other character reached with shift
|
||||
_keyReport.modifiers &= ~(0x02); // the left shift modifier
|
||||
k &= 0x7F;
|
||||
}
|
||||
}
|
||||
return releaseRaw(k);
|
||||
}
|
||||
|
||||
void USBHIDKeyboard::releaseAll(void)
|
||||
{
|
||||
_keyReport.keys[0] = 0;
|
||||
_keyReport.keys[1] = 0;
|
||||
_keyReport.keys[2] = 0;
|
||||
_keyReport.keys[3] = 0;
|
||||
_keyReport.keys[4] = 0;
|
||||
_keyReport.keys[5] = 0;
|
||||
_keyReport.modifiers = 0;
|
||||
sendReport(&_keyReport);
|
||||
}
|
||||
|
||||
size_t USBHIDKeyboard::write(uint8_t c)
|
||||
{
|
||||
uint8_t p = press(c); // Keydown
|
||||
release(c); // Keyup
|
||||
return p; // just return the result of press() since release() almost always returns 1
|
||||
}
|
||||
|
||||
size_t USBHIDKeyboard::write(const uint8_t *buffer, size_t size) {
|
||||
size_t n = 0;
|
||||
while (size--) {
|
||||
if (*buffer != '\r') {
|
||||
if (write(*buffer)) {
|
||||
n++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
buffer++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TINYUSB_HID_ENABLED */
|
140
libraries/USB/src/USBHIDKeyboard.h
Normal file
140
libraries/USB/src/USBHIDKeyboard.h
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
Keyboard.h
|
||||
|
||||
Copyright (c) 2015, Arduino LLC
|
||||
Original code (pre-library): Copyright (c) 2011, Peter Barrett
|
||||
|
||||
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 2.1 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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "Print.h"
|
||||
#include "USBHID.h"
|
||||
#if CONFIG_TINYUSB_HID_ENABLED
|
||||
|
||||
#include "esp_event.h"
|
||||
|
||||
ESP_EVENT_DECLARE_BASE(ARDUINO_USB_HID_KEYBOARD_EVENTS);
|
||||
|
||||
typedef enum {
|
||||
ARDUINO_USB_HID_KEYBOARD_ANY_EVENT = ESP_EVENT_ANY_ID,
|
||||
ARDUINO_USB_HID_KEYBOARD_LED_EVENT = 0,
|
||||
ARDUINO_USB_HID_KEYBOARD_MAX_EVENT,
|
||||
} arduino_usb_hid_keyboard_event_t;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t numlock:1;
|
||||
uint8_t capslock:1;
|
||||
uint8_t scrolllock:1;
|
||||
uint8_t compose:1;
|
||||
uint8_t kana:1;
|
||||
uint8_t reserved:3;
|
||||
};
|
||||
uint8_t leds;
|
||||
} arduino_usb_hid_keyboard_event_data_t;
|
||||
|
||||
#define KEY_LEFT_CTRL 0x80
|
||||
#define KEY_LEFT_SHIFT 0x81
|
||||
#define KEY_LEFT_ALT 0x82
|
||||
#define KEY_LEFT_GUI 0x83
|
||||
#define KEY_RIGHT_CTRL 0x84
|
||||
#define KEY_RIGHT_SHIFT 0x85
|
||||
#define KEY_RIGHT_ALT 0x86
|
||||
#define KEY_RIGHT_GUI 0x87
|
||||
|
||||
#define KEY_UP_ARROW 0xDA
|
||||
#define KEY_DOWN_ARROW 0xD9
|
||||
#define KEY_LEFT_ARROW 0xD8
|
||||
#define KEY_RIGHT_ARROW 0xD7
|
||||
#define KEY_BACKSPACE 0xB2
|
||||
#define KEY_TAB 0xB3
|
||||
#define KEY_RETURN 0xB0
|
||||
#define KEY_ESC 0xB1
|
||||
#define KEY_INSERT 0xD1
|
||||
#define KEY_DELETE 0xD4
|
||||
#define KEY_PAGE_UP 0xD3
|
||||
#define KEY_PAGE_DOWN 0xD6
|
||||
#define KEY_HOME 0xD2
|
||||
#define KEY_END 0xD5
|
||||
#define KEY_CAPS_LOCK 0xC1
|
||||
#define KEY_F1 0xC2
|
||||
#define KEY_F2 0xC3
|
||||
#define KEY_F3 0xC4
|
||||
#define KEY_F4 0xC5
|
||||
#define KEY_F5 0xC6
|
||||
#define KEY_F6 0xC7
|
||||
#define KEY_F7 0xC8
|
||||
#define KEY_F8 0xC9
|
||||
#define KEY_F9 0xCA
|
||||
#define KEY_F10 0xCB
|
||||
#define KEY_F11 0xCC
|
||||
#define KEY_F12 0xCD
|
||||
#define KEY_F13 0xF0
|
||||
#define KEY_F14 0xF1
|
||||
#define KEY_F15 0xF2
|
||||
#define KEY_F16 0xF3
|
||||
#define KEY_F17 0xF4
|
||||
#define KEY_F18 0xF5
|
||||
#define KEY_F19 0xF6
|
||||
#define KEY_F20 0xF7
|
||||
#define KEY_F21 0xF8
|
||||
#define KEY_F22 0xF9
|
||||
#define KEY_F23 0xFA
|
||||
#define KEY_F24 0xFB
|
||||
|
||||
#define LED_NUMLOCK 0x01
|
||||
#define LED_CAPSLOCK 0x02
|
||||
#define LED_SCROLLLOCK 0x04
|
||||
#define LED_COMPOSE 0x08
|
||||
#define LED_KANA 0x10
|
||||
|
||||
// Low level key report: up to 6 keys and shift, ctrl etc at once
|
||||
typedef struct
|
||||
{
|
||||
uint8_t modifiers;
|
||||
uint8_t reserved;
|
||||
uint8_t keys[6];
|
||||
} KeyReport;
|
||||
|
||||
class USBHIDKeyboard: public USBHIDDevice, public Print
|
||||
{
|
||||
private:
|
||||
USBHID hid;
|
||||
KeyReport _keyReport;
|
||||
void sendReport(KeyReport* keys);
|
||||
public:
|
||||
USBHIDKeyboard(void);
|
||||
void begin(void);
|
||||
void end(void);
|
||||
size_t write(uint8_t k);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
size_t press(uint8_t k);
|
||||
size_t release(uint8_t k);
|
||||
void releaseAll(void);
|
||||
|
||||
//raw functions work with TinyUSB's HID_KEY_* macros
|
||||
size_t pressRaw(uint8_t k);
|
||||
size_t releaseRaw(uint8_t k);
|
||||
|
||||
void onEvent(esp_event_handler_t callback);
|
||||
void onEvent(arduino_usb_hid_keyboard_event_t event, esp_event_handler_t callback);
|
||||
|
||||
// internal use
|
||||
uint16_t _onGetDescriptor(uint8_t* buffer);
|
||||
void _onOutput(uint8_t report_id, const uint8_t* buffer, uint16_t len);
|
||||
};
|
||||
|
||||
#endif
|
92
libraries/USB/src/USBHIDMouse.cpp
Normal file
92
libraries/USB/src/USBHIDMouse.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
Mouse.cpp
|
||||
|
||||
Copyright (c) 2015, Arduino LLC
|
||||
Original code (pre-library): Copyright (c) 2011, Peter Barrett
|
||||
|
||||
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 2.1 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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "USBHID.h"
|
||||
|
||||
#if CONFIG_TINYUSB_HID_ENABLED
|
||||
|
||||
#include "USBHIDMouse.h"
|
||||
|
||||
static const uint8_t report_descriptor[] = {
|
||||
TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(HID_REPORT_ID_MOUSE))
|
||||
};
|
||||
|
||||
USBHIDMouse::USBHIDMouse(): hid(), _buttons(0){
|
||||
static bool initialized = false;
|
||||
if(!initialized){
|
||||
initialized = true;
|
||||
hid.addDevice(this, sizeof(report_descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t USBHIDMouse::_onGetDescriptor(uint8_t* dst){
|
||||
memcpy(dst, report_descriptor, sizeof(report_descriptor));
|
||||
return sizeof(report_descriptor);
|
||||
}
|
||||
|
||||
void USBHIDMouse::begin(){
|
||||
hid.begin();
|
||||
}
|
||||
|
||||
void USBHIDMouse::end(){
|
||||
}
|
||||
|
||||
void USBHIDMouse::move(int8_t x, int8_t y, int8_t wheel, int8_t pan){
|
||||
hid_mouse_report_t report = {
|
||||
.buttons = _buttons,
|
||||
.x = x,
|
||||
.y = y,
|
||||
.wheel = wheel,
|
||||
.pan = pan
|
||||
};
|
||||
hid.SendReport(HID_REPORT_ID_MOUSE, &report, sizeof(report));
|
||||
}
|
||||
|
||||
void USBHIDMouse::click(uint8_t b){
|
||||
_buttons = b;
|
||||
move(0,0);
|
||||
_buttons = 0;
|
||||
move(0,0);
|
||||
}
|
||||
|
||||
void USBHIDMouse::buttons(uint8_t b){
|
||||
if (b != _buttons){
|
||||
_buttons = b;
|
||||
move(0,0);
|
||||
}
|
||||
}
|
||||
|
||||
void USBHIDMouse::press(uint8_t b){
|
||||
buttons(_buttons | b);
|
||||
}
|
||||
|
||||
void USBHIDMouse::release(uint8_t b){
|
||||
buttons(_buttons & ~b);
|
||||
}
|
||||
|
||||
bool USBHIDMouse::isPressed(uint8_t b){
|
||||
if ((b & _buttons) > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_TINYUSB_HID_ENABLED */
|
54
libraries/USB/src/USBHIDMouse.h
Normal file
54
libraries/USB/src/USBHIDMouse.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
Mouse.h
|
||||
|
||||
Copyright (c) 2015, Arduino LLC
|
||||
Original code (pre-library): Copyright (c) 2011, Peter Barrett
|
||||
|
||||
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 2.1 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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "USBHID.h"
|
||||
#if CONFIG_TINYUSB_HID_ENABLED
|
||||
|
||||
#define MOUSE_LEFT 0x01
|
||||
#define MOUSE_RIGHT 0x02
|
||||
#define MOUSE_MIDDLE 0x04
|
||||
#define MOUSE_BACKWARD 0x08
|
||||
#define MOUSE_FORWARD 0x10
|
||||
#define MOUSE_ALL 0x1F
|
||||
|
||||
class USBHIDMouse: public USBHIDDevice {
|
||||
private:
|
||||
USBHID hid;
|
||||
uint8_t _buttons;
|
||||
void buttons(uint8_t b);
|
||||
bool write(int8_t x, int8_t y, int8_t vertical, int8_t horizontal);
|
||||
public:
|
||||
USBHIDMouse(void);
|
||||
void begin(void);
|
||||
void end(void);
|
||||
|
||||
void click(uint8_t b = MOUSE_LEFT);
|
||||
void move(int8_t x, int8_t y, int8_t wheel = 0, int8_t pan = 0);
|
||||
void press(uint8_t b = MOUSE_LEFT); // press LEFT by default
|
||||
void release(uint8_t b = MOUSE_LEFT); // release LEFT by default
|
||||
bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default
|
||||
|
||||
// internal use
|
||||
uint16_t _onGetDescriptor(uint8_t* buffer);
|
||||
};
|
||||
|
||||
#endif
|
59
libraries/USB/src/USBHIDSystemControl.cpp
Normal file
59
libraries/USB/src/USBHIDSystemControl.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "USBHID.h"
|
||||
|
||||
#if CONFIG_TINYUSB_HID_ENABLED
|
||||
|
||||
#include "USBHIDSystemControl.h"
|
||||
|
||||
static const uint8_t report_descriptor[] = {
|
||||
TUD_HID_REPORT_DESC_SYSTEM_CONTROL(HID_REPORT_ID(HID_REPORT_ID_SYSTEM_CONTROL))
|
||||
};
|
||||
|
||||
USBHIDSystemControl::USBHIDSystemControl(): hid(){
|
||||
static bool initialized = false;
|
||||
if(!initialized){
|
||||
initialized = true;
|
||||
hid.addDevice(this, sizeof(report_descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t USBHIDSystemControl::_onGetDescriptor(uint8_t* dst){
|
||||
memcpy(dst, report_descriptor, sizeof(report_descriptor));
|
||||
return sizeof(report_descriptor);
|
||||
}
|
||||
|
||||
void USBHIDSystemControl::begin(){
|
||||
hid.begin();
|
||||
}
|
||||
|
||||
void USBHIDSystemControl::end(){
|
||||
}
|
||||
|
||||
bool USBHIDSystemControl::send(uint8_t value){
|
||||
return hid.SendReport(HID_REPORT_ID_SYSTEM_CONTROL, &value, 1);
|
||||
}
|
||||
|
||||
size_t USBHIDSystemControl::press(uint8_t k){
|
||||
if(k > 3){
|
||||
return 0;
|
||||
}
|
||||
return send(k);
|
||||
}
|
||||
|
||||
size_t USBHIDSystemControl::release(){
|
||||
return send(0);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TINYUSB_HID_ENABLED */
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user