mirror of
https://github.com/Architeuthis-Flux/Jumperless.git
synced 2024-11-12 01:30:50 +01:00
Merge pull request #28 from nilclass/adc-samples-via-hid
Continously sample ADCs and expose samples via a USB Interrupt endpoint
This commit is contained in:
commit
aa6590a1fe
@ -65,14 +65,18 @@ extern "C" {
|
||||
// Device Configuration
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#define CFG_TUD_ENDOINT0_SIZE 64
|
||||
#define CFG_TUD_ENDOINT0_SIZE 256
|
||||
|
||||
#define CFG_TUD_CDC 2
|
||||
|
||||
#define CFG_TUD_MSC 1
|
||||
#define CFG_TUD_HID 1
|
||||
#define CFG_TUD_MIDI 1
|
||||
#define CFG_TUD_VENDOR 1
|
||||
#define CFG_TUD_MSC 0
|
||||
#define CFG_TUD_HID 0
|
||||
#define CFG_TUD_MIDI 0
|
||||
#define CFG_TUD_VENDOR 0
|
||||
#define CFG_TUD_JUMPERLESS 1
|
||||
|
||||
// max is 64
|
||||
#define CFG_TUD_JUMPERLESS_EP_BUFSIZE 8
|
||||
|
||||
// CDC FIFO size of TX and RX
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE 256
|
||||
|
@ -0,0 +1,6 @@
|
||||
synopsys
|
||||
sie
|
||||
inout
|
||||
busses
|
||||
thre
|
||||
|
10
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/.codespellrc
Normal file
10
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/.codespellrc
Normal file
@ -0,0 +1,10 @@
|
||||
# See: https://github.com/codespell-project/codespell#using-a-config-file
|
||||
[codespell]
|
||||
# In the event of a false positive, add the problematic word, in all lowercase, to 'ignore-words.txt' (one word per line).
|
||||
# Or copy & paste the whole problematic line to 'exclude-file.txt'
|
||||
ignore-words = .codespell/ignore-words.txt
|
||||
exclude-file = .codespell/exclude-file.txt
|
||||
check-filenames =
|
||||
check-hidden =
|
||||
count =
|
||||
skip = .git
|
102
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
102
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
name: Bug Report
|
||||
description: Report a problem with TinyUSB Library
|
||||
labels: 'Bug'
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report!
|
||||
It's okay to leave some blank if it doesn't apply to your problem.
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Operating System
|
||||
options:
|
||||
- Linux
|
||||
- MacOS
|
||||
- RaspberryPi OS
|
||||
- Windows 7
|
||||
- Windows 10
|
||||
- Windows 11
|
||||
- Others
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Arduino IDE version
|
||||
placeholder: e.g Arduino 1.8.15
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: Board
|
||||
placeholder: e.g Feather nRF52840 Express
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: ArduinoCore version
|
||||
description: Can be found under "Board Manager" menu
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
attributes:
|
||||
label: TinyUSB Library version
|
||||
placeholder: "Release version or github latest"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Sketch as ATTACHED TXT
|
||||
placeholder: |
|
||||
e.g examples/MassStorage/msc_ramdisk.
|
||||
If it is custom sketch, please provide it as **ATTACHED** files or link to it.
|
||||
Pasting raw long code that hurts readability can get your issue **closed**
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Compiled Log as ATTACHED TXT
|
||||
placeholder: |
|
||||
Compiled log from Arduino IDE as **ATTACHED** txt.
|
||||
Pasting raw long log that hurts readability can get your issue **closed**
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: What happened ?
|
||||
placeholder: A clear and concise description of what the bug is.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: How to reproduce ?
|
||||
placeholder: |
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. See error
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Debug Log
|
||||
placeholder: |
|
||||
TinyUSB debug log where the issue occurred as attached txt file, best with comments to explain the actual events.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If applicable, add screenshots to help explain your problem.
|
||||
validations:
|
||||
required: false
|
8
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Adafruit Support Forum
|
||||
url: https://forums.adafruit.com
|
||||
about: If you have other questions or need help, post it here.
|
||||
- name: TinyUSB Arduino Discussion
|
||||
url: https://github.com/adafruit/Adafruit_TinyUSB_Arduino/discussions
|
||||
about: If you have other questions or need help, post it here.
|
20
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: 'Feature'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
85
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/.github/workflows/githubci.yml
vendored
Normal file
85
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/.github/workflows/githubci.yml
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
name: Build
|
||||
|
||||
on: [pull_request, push, repository_dispatch]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Run pre-commit
|
||||
uses: pre-commit/action@v3.0.0
|
||||
|
||||
- name: Checkout adafruit/ci-arduino
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: adafruit/ci-arduino
|
||||
path: ci
|
||||
|
||||
- name: pre-install
|
||||
run: bash ci/actions_install.sh
|
||||
|
||||
# - name: clang
|
||||
# run: python3 ci/run-clang-format.py -r src/arduino
|
||||
|
||||
- name: doxygen
|
||||
env:
|
||||
GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }}
|
||||
PRETTYNAME : "Adafruit TinyUSB Library"
|
||||
run: bash ci/doxy_gen_and_deploy.sh
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre-commit
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arduino-platform:
|
||||
# ESP32S3
|
||||
- 'feather_esp32s3'
|
||||
# ESP32S2
|
||||
- 'feather_esp32s2'
|
||||
# nRF52
|
||||
- 'cpb'
|
||||
- 'nrf52840'
|
||||
# RP2040
|
||||
- 'feather_rp2040_tinyusb'
|
||||
# SAMD
|
||||
- 'feather_m4_can_tinyusb'
|
||||
- 'metro_m0_tinyusb'
|
||||
- 'metro_m4_tinyusb'
|
||||
|
||||
steps:
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.x'
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Checkout adafruit/ci-arduino
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: adafruit/ci-arduino
|
||||
path: ci
|
||||
|
||||
- name: pre-install
|
||||
run: bash ci/actions_install.sh
|
||||
|
||||
- name: Install Libraries for building examples
|
||||
run: arduino-cli lib install "Adafruit SPIFlash" "MIDI Library" "Adafruit seesaw Library" "Adafruit NeoPixel" "SdFat - Adafruit Fork" "SD" "Adafruit Circuit Playground" "Adafruit InternalFlash" "Pico PIO USB"
|
||||
|
||||
- name: test platforms
|
||||
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }}
|
4
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/.gitignore
vendored
Normal file
4
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/examples/**/build/
|
||||
/.development
|
||||
.idea
|
||||
platformio.ini
|
@ -0,0 +1,29 @@
|
||||
# SPDX-FileCopyrightText: 2020 Diego Elio Pettenò
|
||||
#
|
||||
# SPDX-License-Identifier: Unlicense
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v15.0.7
|
||||
hooks:
|
||||
- id: clang-format
|
||||
exclude: |
|
||||
(?x)^(
|
||||
examples/|
|
||||
src/class|
|
||||
src/common|
|
||||
src/device|
|
||||
src/host|
|
||||
src/osal|
|
||||
src/portable|
|
||||
src/tusb_option.h|
|
||||
src/tusb.c|
|
||||
src/tusb.h
|
||||
)
|
||||
types_or: [c++, c, header]
|
||||
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.2.4
|
||||
hooks:
|
||||
- id: codespell
|
||||
args: [-w]
|
@ -0,0 +1,76 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at . All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
21
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/LICENSE
Normal file
21
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
82
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/README.md
Normal file
82
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/README.md
Normal file
@ -0,0 +1,82 @@
|
||||
# Adafruit TinyUSB Library for Arduino
|
||||
|
||||
[![Build Status](https://github.com/adafruit/Adafruit_TinyUSB_Arduino/workflows/Build/badge.svg)](https://github.com/adafruit/Adafruit_TinyUSB_Arduino/actions) [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)
|
||||
|
||||
This library is a Arduino-friendly version of [TinyUSB](https://github.com/hathach/tinyusb) stack.
|
||||
It is designed with structure and APIs that are easily integrated to an Arduino Core.
|
||||
|
||||
## Features
|
||||
|
||||
### Device Stack
|
||||
|
||||
Supported device class drivers are:
|
||||
|
||||
- Communication (CDC): which is used to implement `Serial` monitor
|
||||
- Human Interface Device (HID): Generic (In & Out), Keyboard, Mouse, Gamepad etc ...
|
||||
- Mass Storage Class (MSC): with multiple LUNs
|
||||
- Musical Instrument Digital Interface (MIDI)
|
||||
- WebUSB with vendor specific class
|
||||
|
||||
### Host Stack
|
||||
|
||||
Host support is still work-in-progress but currently available with rp2040 core thanks to [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB). Supported class driver are:
|
||||
|
||||
- Communication (CDC)
|
||||
- MassStorage class
|
||||
|
||||
## Supported Cores
|
||||
|
||||
There are 2 type of supported cores: with and without built-in support for TinyUSB. Built-in support provide seamless integration but requires extra code added to core's source code. Unfortunately it is not always easy or possible to make those modification.
|
||||
|
||||
### Cores with built-in support
|
||||
|
||||
Following core has TinyUSB as either the primary usb stack or selectable via menu `Tools->USB Stack`. You only need to include `<Adafruit_TinyUSB.h>` in your sketch to use.
|
||||
|
||||
- [adafruit/Adafruit_nRF52_Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino)
|
||||
- [adafruit/ArduinoCore-samd](https://github.com/adafruit/ArduinoCore-samd)
|
||||
- [earlephilhower/arduino-pico](https://github.com/earlephilhower/arduino-pico)
|
||||
- [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32)
|
||||
|
||||
ESP32 port relies on Espressif's [esp32-hal-tinyusb.c](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-tinyusb.c) for building usb descriptors which requires all descriptors must be specified in usb objects declaration i.e constructors. Therefore all descriptor-related fields must be part of object declaration and descriptor-related API have no effect afterwards for this port.
|
||||
|
||||
### Cores without built-in support
|
||||
|
||||
Following is cores without built-in support
|
||||
|
||||
- **mbed_rp2040**
|
||||
|
||||
It is still possible to use TinyUSB but with some limits such as:
|
||||
|
||||
- `TinyUSB_Device_Init()` need to be manually called in setup()
|
||||
- `TinyUSB_Device_Task()` and/or `TinyUSB_Device_FlushCDC()` may (or not) need to be manually called in loop()
|
||||
- Use `SerialTinyUSB` name instead of Serial for serial monitor
|
||||
- And there could be more other issues, using on these cores should be considered as experimental
|
||||
|
||||
## Class Driver API
|
||||
|
||||
More document to write ...
|
||||
|
||||
## Porting Guide
|
||||
|
||||
To integrate TinyUSB library to a Arduino core, you will need to make changes to the core for built-in support and library for porting the mcu/platform.
|
||||
|
||||
### Arduino Core Changes
|
||||
|
||||
If possible, making changes to core will allow it to have built-in which make it almost transparent to user sketch
|
||||
|
||||
1. Add this repo as submodule (or have local copy) at your ArduioCore/libraries/Adafruit_TinyUSB_Arduino (much like SPI).
|
||||
2. Since Serial as CDC is considered as part of the core, we need to have `#include "Adafruit_USBD_CDC.h"` within your `Arduino.h`. For this to work, your `platform.txt` include path need to have `"-I{runtime.platform.path}/libraries/Adafruit_TinyUSB_Arduino/src/arduino"`.
|
||||
3. In your `main.cpp` before setup() invoke the `TinyUSB_Device_Init(rhport)`. This will initialize usb device hardware and tinyusb stack and also include Serial as an instance of CDC class.
|
||||
4. `TinyUSB_Device_Task()` must be called whenever there is new USB event. Depending on your core and MCU with or without RTOS. There are many ways to run the task. For example:
|
||||
- Use USB IRQn to set flag then invoke function later on after exiting IRQ.
|
||||
- Just invoke function after the loop(), within yield(), and delay()
|
||||
5. `TinyUSB_Device_FlushCDC()` should also be called often to send out Serial data as well.
|
||||
6. Note: For low power platform that make use of WFI()/WFE(), extra care is required before mcu go into low power mode. Check out my PR to circuipython for reference https://github.com/adafruit/circuitpython/pull/2956
|
||||
|
||||
### Library Changes
|
||||
|
||||
In addition to core changes, library need to be ported to your platform. Don't worry, tinyusb stack has already done most of heavy-lifting. You only need to write a few APIs
|
||||
|
||||
1. `TinyUSB_Port_InitDevice()` hardware specific (clock, phy) to enable usb hardware then call tud_init(). This API is called as part of TinyUSB_Device_Init() invocation.
|
||||
2. `TinyUSB_Port_EnterDFU()` which is called when device need to enter DFU mode, usually by touch1200 feature
|
||||
3. `TinyUSB_Port_GetSerialNumber()` which is called to get unique MCU Serial ID to used as Serial string descriptor.
|
158
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/changelog.md
Normal file
158
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/changelog.md
Normal file
@ -0,0 +1,158 @@
|
||||
# Adafruit TinyUSB Arduino Library Changelog
|
||||
|
||||
## 1.6.0
|
||||
|
||||
- Update TinyUSB to post 0.12.0 at commit https://github.com/hathach/tinyusb/commit/b4a0f0b273eee32ead7acbd44ca9554c58a2adfa
|
||||
- Fix build with ESP32S2 v2.0.1rc
|
||||
- Fix MIDI Control Change message sending is corrupted
|
||||
|
||||
## 1.5.0 - 2021.09.29
|
||||
|
||||
- Add support for ESP32-S2 core version 2.0.0
|
||||
- ESP32 port relies on Espressif's [esp32-hal-tinyusb.c](https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-tinyusb.c) for building usb descriptors which requires all descriptors must be specified in usb objects declaration i.e constructors. Therefore all descriptor-related fields must be part of object declaration and descriptor-related API have no effect afterwards for this port.
|
||||
|
||||
- Add new constructor for Adafruit_USBD_HID(desc_report, len, protocol, interval_ms, has_out_endpoint)
|
||||
|
||||
## 1.4.4 - 2021.08.18
|
||||
|
||||
- Update tinyusb stack
|
||||
- Fully support nRF5x suspend, resume & remote wakeup
|
||||
- Update hid_keyboard/mouse example to hid boot keyboard/mouse
|
||||
|
||||
## 1.4.3 - 2021.08.11
|
||||
|
||||
- Fix HID generic inout example python/js script cause missing 1st byte in report
|
||||
- Use correct HID code for newline 0x28
|
||||
|
||||
## 1.4.2 - 2021.08.03
|
||||
|
||||
- Update tinyusb to match upstream
|
||||
|
||||
## 1.4.1 - 2021.07.27
|
||||
|
||||
- Fix nRF race condition when initialize usb stack
|
||||
|
||||
## 1.4.0 - 2021.07.22
|
||||
|
||||
- Support rp2040 mbed core as non built-in support
|
||||
|
||||
## 1.3.2 - 2021.07.07
|
||||
|
||||
- revert CFG_TUSB_DEBUG = 0 on SAMD port
|
||||
|
||||
## 1.3.1 - 2021.07.06
|
||||
|
||||
- Fix warning with ci build for rp2040 core
|
||||
- Fix example build for esp32s2
|
||||
- Use ARDUINO_NRF52_ADAFRUIT instead of ARDUINO_ARCH_NRF52
|
||||
|
||||
## 1.3.0 - 2021.06.29
|
||||
|
||||
- Move tusb_config for each ports into library to make it more portable
|
||||
- Adding support for ESP32S2 (still need PR to be merged from esp32-arduino)
|
||||
- Update CDC to have instance and getInstanceCount()
|
||||
- Allow USB_VID/PID to be declared in variant pins_arduino.h
|
||||
- Use bug report form template
|
||||
|
||||
## 1.1.0 - 2021.06.21
|
||||
|
||||
- Add support for multiple CDC ports (need to modify tusb_config.h)
|
||||
- fix #86 when calling midi API when device is not fully enumerated
|
||||
- fix Serial connection issue with nrf52 on windows
|
||||
- Update device driver of rp2040 to match tinyusb upstream
|
||||
- Added feather rp2040 to ci build (skipped the external flash example for now due to SdFat compilation error)
|
||||
- Add optional debug log for stack with Serial1 on samd core (will expand later to other core).
|
||||
- lost more bug fixes to the stack
|
||||
|
||||
## 1.0.3 - 2021.05.26
|
||||
|
||||
- Update tinyusb stack to latest
|
||||
- Added HID Gamepad example with Dhat support
|
||||
- Fix warnings with -Wall -Wextra
|
||||
- Fix warnings with cast function type for nrf
|
||||
|
||||
## 1.0.1 - 2021.05.21
|
||||
|
||||
Warn user to select TinyUSB via menu on ports where it is optional e.g SAMD and RP2040
|
||||
|
||||
## 1.0.0 - 2021.05.19
|
||||
|
||||
Rework to work as independent libraries, sources from https://github.com/adafruit/Adafruit_TinyUSB_ArduinoCore is now integrated as part of this libraries. Require
|
||||
- Adafruit SAMD core with version at least 1.7.0
|
||||
- Adafruit nRF52 core with version at least 0.22.0
|
||||
- Support [earlephilhower/arduino-pico](https://github.com/earlephilhower/arduino-pico) version released after https://github.com/earlephilhower/arduino-pico/pull/127
|
||||
|
||||
## 0.9.0 - 2020.04.23
|
||||
|
||||
- Fixed mouseButtonRelease() error
|
||||
- Supported multiple cables for USB MIDI (requires BSP nRF52 0.20.0 and SAMD 1.5.12 )
|
||||
- Added consumer control support to HID/hid_composite example
|
||||
- Added Adafruit_USBD_HID send report helper: sendReport8(), sendReport16(), sendReport32()
|
||||
|
||||
**Minor Breaking Changes**
|
||||
- Removed trailing comma in hid report descriptor, this is required to use with BSP nRF52 0.20.0 and SAMD 1.5.12 e.g
|
||||
|
||||
from
|
||||
|
||||
```
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD), ),
|
||||
TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(RID_MOUSE ), ),
|
||||
};
|
||||
```
|
||||
to
|
||||
|
||||
```
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD) /*, no more trailing comma */ ),
|
||||
TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(RID_MOUSE ) /*, no more trailing comma */ ),
|
||||
};
|
||||
```
|
||||
|
||||
## 0.8.2 - 2020.04.06
|
||||
|
||||
- Removed package-lock.json in hid generic inout example due to security warning from github
|
||||
|
||||
## 0.8.1 - 2020.01.08
|
||||
|
||||
- More CI migrating work, no function changes
|
||||
|
||||
## 0.8.0 - 2019.12.30
|
||||
|
||||
- Correct USB BCD version to 2.1 for webUSB
|
||||
- Migrate CI from travis to github actions
|
||||
|
||||
## 0.7.1 - 2019.10.12
|
||||
|
||||
- Fixed MIDI build failed since it is under development
|
||||
|
||||
## 0.7.0 - 2019.10.09
|
||||
|
||||
- Added MIDI virtual wires/plugs
|
||||
|
||||
## 0.6.0 - 2019.08.05
|
||||
|
||||
- Added webUSB support with 2 example: webusb-serial, webusb-rgb
|
||||
- Aligned mouse examples, added newer hid in/out example from main repo, added new composite example for ramdisk and hid in/out. PR #19 thanks to @PTS93
|
||||
|
||||
## 0.5.0 - 2019.07.17
|
||||
|
||||
- Added travis build
|
||||
- Fixed msc setID
|
||||
- Added itfnum to internal API getDescriptor()
|
||||
- Added MIDI support
|
||||
- Added midi_test example
|
||||
- Added pizza box dj example for cplayground express
|
||||
- Mass Storage
|
||||
- Added msc_sdfat, msc dual lun (external flash + sd card) example
|
||||
- Updated msc example to use new SPIFlash 3.x API
|
||||
- Update msc example to print root contents
|
||||
- HID
|
||||
- Added hid_mouse, hid_keyboard
|
||||
- Added hid_composite_joy_featherwing
|
||||
- Added Composite: mouse_ramdisk, mouse_external_flash example
|
||||
|
||||
## 0.0.1 Initial Release
|
||||
|
@ -0,0 +1,75 @@
|
||||
.main-content {
|
||||
width: 1440px;
|
||||
margin: auto;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.connect-container {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.button::before {
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-box-shadow: #959595 0 2px 5px;
|
||||
-moz-box-shadow: #959595 0 2px 5px;
|
||||
border-radius: 3px;
|
||||
box-shadow: #959595 0 2px 5px;
|
||||
content: "";
|
||||
display: block;
|
||||
left: 0;
|
||||
padding: 2px 0 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.button:active::before { padding: 1px 0 0; }
|
||||
|
||||
.button.black {
|
||||
background: #656565;
|
||||
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#656565), to(#444));
|
||||
background: -moz-linear-gradient(#656565, #444);
|
||||
background: linear-gradient(#656565, #444);
|
||||
border: solid 1px #535353;
|
||||
border-bottom: solid 3px #414141;
|
||||
box-shadow: inset 0 0 0 1px #939393;
|
||||
color: #fff;
|
||||
text-shadow: 0 1px 0 #2f2f2f;
|
||||
padding: 8px 16px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.button.black:hover {
|
||||
background: #4c4c4c;
|
||||
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#4c4c4c), to(#565656));
|
||||
background: -moz-linear-gradient(#4c4c4c, #565656);
|
||||
background: linear-gradient(#4c4c4c, #565656);
|
||||
border: solid 1px #464646;
|
||||
border-bottom: solid 3px #414141;
|
||||
box-shadow: inset 0 0 0 1px #818181;
|
||||
}
|
||||
|
||||
.button.black:active {
|
||||
background: #474747;
|
||||
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#474747), to(#444));
|
||||
background: -moz-linear-gradient(#474747, #444);
|
||||
background: linear-gradient(#474747, #444);
|
||||
border: solid 1px #2f2f2f;
|
||||
box-shadow: inset 0 10px 15px 0 #3e3e3e;
|
||||
}
|
||||
|
||||
.color-picker-container {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 50px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.color-picker {
|
||||
padding: 0;
|
||||
border: none;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
outline: none;
|
||||
transform: translate(-25%, -25%)
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', event => {
|
||||
let connectButton = document.querySelector("#connect");
|
||||
let statusDisplay = document.querySelector('#status');
|
||||
let port;
|
||||
|
||||
function connect() {
|
||||
port.connect().then(() => {
|
||||
statusDisplay.textContent = '';
|
||||
connectButton.textContent = 'Disconnect';
|
||||
|
||||
port.onReceiveError = error => {
|
||||
console.error(error);
|
||||
};
|
||||
}, error => {
|
||||
statusDisplay.textContent = error;
|
||||
});
|
||||
}
|
||||
|
||||
connectButton.addEventListener('click', function() {
|
||||
if (port) {
|
||||
port.disconnect();
|
||||
connectButton.textContent = 'Connect';
|
||||
statusDisplay.textContent = '';
|
||||
port = null;
|
||||
} else {
|
||||
serial.requestPort().then(selectedPort => {
|
||||
port = selectedPort;
|
||||
connect();
|
||||
}).catch(error => {
|
||||
statusDisplay.textContent = error;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
serial.getPorts().then(ports => {
|
||||
if (ports.length === 0) {
|
||||
statusDisplay.textContent = 'No device found.';
|
||||
} else {
|
||||
statusDisplay.textContent = 'Connecting...';
|
||||
port = ports[0];
|
||||
connect();
|
||||
}
|
||||
});
|
||||
|
||||
let colorPicker = document.getElementById("color_picker");
|
||||
|
||||
colorPicker.addEventListener("change", function(event) {
|
||||
port.send(new TextEncoder("utf-8").encode(colorPicker.value));
|
||||
});
|
||||
});
|
||||
})();
|
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>TinyUSB</title>
|
||||
<script src="serial.js"></script>
|
||||
<script src="application.js"></script>
|
||||
<link rel="stylesheet" href="application.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-content">
|
||||
<h1>TinyUSB - WebUSB RGB Example</h1>
|
||||
<div class="connect-container">
|
||||
<button id="connect" class="button black">Connect</button>
|
||||
<span id="status"></span>
|
||||
</div>
|
||||
<div class="color-picker-container">
|
||||
<input type="color" id="color_picker" value="#00ff00" class="color-picker">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,92 @@
|
||||
var serial = {};
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
serial.getPorts = function() {
|
||||
return navigator.usb.getDevices().then(devices => {
|
||||
return devices.map(device => new serial.Port(device));
|
||||
});
|
||||
};
|
||||
|
||||
serial.requestPort = function() {
|
||||
const filters = [
|
||||
{ 'vendorId': 0xcafe }, // TinyUSB
|
||||
{ 'vendorId': 0x239a }, // Adafruit
|
||||
{ 'vendorId': 0x2e8a }, // Raspberry Pi
|
||||
{ 'vendorId': 0x303a }, // Espressif
|
||||
{ 'vendorId': 0x2341 }, // Arduino
|
||||
];
|
||||
return navigator.usb.requestDevice({ 'filters': filters }).then(
|
||||
device => new serial.Port(device)
|
||||
);
|
||||
}
|
||||
|
||||
serial.Port = function(device) {
|
||||
this.device_ = device;
|
||||
this.interfaceNumber = 0;
|
||||
this.endpointIn = 0;
|
||||
this.endpointOut = 0;
|
||||
};
|
||||
|
||||
serial.Port.prototype.connect = function() {
|
||||
let readLoop = () => {
|
||||
this.device_.transferIn(this.endpointIn, 64).then(result => {
|
||||
this.onReceive(result.data);
|
||||
readLoop();
|
||||
}, error => {
|
||||
this.onReceiveError(error);
|
||||
});
|
||||
};
|
||||
|
||||
return this.device_.open()
|
||||
.then(() => {
|
||||
if (this.device_.configuration === null) {
|
||||
return this.device_.selectConfiguration(1);
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
var interfaces = this.device_.configuration.interfaces;
|
||||
interfaces.forEach(element => {
|
||||
element.alternates.forEach(elementalt => {
|
||||
if (elementalt.interfaceClass==0xFF) {
|
||||
this.interfaceNumber = element.interfaceNumber;
|
||||
elementalt.endpoints.forEach(elementendpoint => {
|
||||
if (elementendpoint.direction == "out") {
|
||||
this.endpointOut = elementendpoint.endpointNumber;
|
||||
}
|
||||
if (elementendpoint.direction=="in") {
|
||||
this.endpointIn =elementendpoint.endpointNumber;
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
.then(() => this.device_.claimInterface(this.interfaceNumber))
|
||||
.then(() => this.device_.selectAlternateInterface(this.interfaceNumber, 0))
|
||||
.then(() => this.device_.controlTransferOut({
|
||||
'requestType': 'class',
|
||||
'recipient': 'interface',
|
||||
'request': 0x22,
|
||||
'value': 0x01,
|
||||
'index': this.interfaceNumber}))
|
||||
.then(() => {
|
||||
readLoop();
|
||||
});
|
||||
};
|
||||
|
||||
serial.Port.prototype.disconnect = function() {
|
||||
return this.device_.controlTransferOut({
|
||||
'requestType': 'class',
|
||||
'recipient': 'interface',
|
||||
'request': 0x22,
|
||||
'value': 0x00,
|
||||
'index': this.interfaceNumber})
|
||||
.then(() => this.device_.close());
|
||||
};
|
||||
|
||||
serial.Port.prototype.send = function(data) {
|
||||
return this.device_.transferOut(this.endpointOut, data);
|
||||
};
|
||||
})();
|
@ -0,0 +1,107 @@
|
||||
.main-content {
|
||||
width: 1440px;
|
||||
margin: auto;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.connect-container {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.sender, .receiver {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sender {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.receiver {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.lines-header {
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background-color: #444;
|
||||
line-height: 30px;
|
||||
color: white;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.lines-body {
|
||||
width: 100%;
|
||||
background-color: #222;
|
||||
min-height: 300px;
|
||||
padding: 10px 0 20px 0;
|
||||
}
|
||||
|
||||
.line, .command-line {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
color: #f1f1f1;
|
||||
background-color: #222;
|
||||
outline: none;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.line:hover {
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
.button::before {
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-box-shadow: #959595 0 2px 5px;
|
||||
-moz-box-shadow: #959595 0 2px 5px;
|
||||
border-radius: 3px;
|
||||
box-shadow: #959595 0 2px 5px;
|
||||
content: "";
|
||||
display: block;
|
||||
left: 0;
|
||||
padding: 2px 0 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.button:active::before { padding: 1px 0 0; }
|
||||
|
||||
.button.black {
|
||||
background: #656565;
|
||||
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#656565), to(#444));
|
||||
background: -moz-linear-gradient(#656565, #444);
|
||||
background: linear-gradient(#656565, #444);
|
||||
border: solid 1px #535353;
|
||||
border-bottom: solid 3px #414141;
|
||||
box-shadow: inset 0 0 0 1px #939393;
|
||||
color: #fff;
|
||||
text-shadow: 0 1px 0 #2f2f2f;
|
||||
padding: 8px 16px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.button.black:hover {
|
||||
background: #4c4c4c;
|
||||
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#4c4c4c), to(#565656));
|
||||
background: -moz-linear-gradient(#4c4c4c, #565656);
|
||||
background: linear-gradient(#4c4c4c, #565656);
|
||||
border: solid 1px #464646;
|
||||
border-bottom: solid 3px #414141;
|
||||
box-shadow: inset 0 0 0 1px #818181;
|
||||
}
|
||||
|
||||
.button.black:active {
|
||||
background: #474747;
|
||||
background: -webkit-gradient(linear, 0 0, 0 bottom, from(#474747), to(#444));
|
||||
background: -moz-linear-gradient(#474747, #444);
|
||||
background: linear-gradient(#474747, #444);
|
||||
border: solid 1px #2f2f2f;
|
||||
box-shadow: inset 0 10px 15px 0 #3e3e3e;
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', event => {
|
||||
let connectButton = document.querySelector("#connect");
|
||||
let statusDisplay = document.querySelector('#status');
|
||||
let port;
|
||||
|
||||
function addLine(linesId, text) {
|
||||
var senderLine = document.createElement("div");
|
||||
senderLine.className = 'line';
|
||||
var textnode = document.createTextNode(text);
|
||||
senderLine.appendChild(textnode);
|
||||
document.getElementById(linesId).appendChild(senderLine);
|
||||
return senderLine;
|
||||
}
|
||||
|
||||
let currentReceiverLine;
|
||||
|
||||
function appendLines(linesId, text) {
|
||||
const lines = text.split('\r');
|
||||
if (currentReceiverLine) {
|
||||
currentReceiverLine.innerHTML = currentReceiverLine.innerHTML + lines[0];
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
currentReceiverLine = addLine(linesId, lines[i]);
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
currentReceiverLine = addLine(linesId, lines[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function connect() {
|
||||
port.connect().then(() => {
|
||||
statusDisplay.textContent = '';
|
||||
connectButton.textContent = 'Disconnect';
|
||||
|
||||
port.onReceive = data => {
|
||||
let textDecoder = new TextDecoder();
|
||||
console.log(textDecoder.decode(data));
|
||||
if (data.getInt8() === 13) {
|
||||
currentReceiverLine = null;
|
||||
} else {
|
||||
appendLines('receiver_lines', textDecoder.decode(data));
|
||||
}
|
||||
};
|
||||
port.onReceiveError = error => {
|
||||
console.error(error);
|
||||
};
|
||||
}, error => {
|
||||
statusDisplay.textContent = error;
|
||||
});
|
||||
}
|
||||
|
||||
connectButton.addEventListener('click', function() {
|
||||
if (port) {
|
||||
port.disconnect();
|
||||
connectButton.textContent = 'Connect';
|
||||
statusDisplay.textContent = '';
|
||||
port = null;
|
||||
} else {
|
||||
serial.requestPort().then(selectedPort => {
|
||||
port = selectedPort;
|
||||
connect();
|
||||
}).catch(error => {
|
||||
statusDisplay.textContent = error;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
serial.getPorts().then(ports => {
|
||||
if (ports.length === 0) {
|
||||
statusDisplay.textContent = 'No device found.';
|
||||
} else {
|
||||
statusDisplay.textContent = 'Connecting...';
|
||||
port = ports[0];
|
||||
connect();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let commandLine = document.getElementById("command_line");
|
||||
|
||||
commandLine.addEventListener("keypress", function(event) {
|
||||
if (event.keyCode === 13) {
|
||||
if (commandLine.value.length > 0) {
|
||||
addLine('sender_lines', commandLine.value);
|
||||
commandLine.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
port.send(new TextEncoder('utf-8').encode(String.fromCharCode(event.which || event.keyCode)));
|
||||
});
|
||||
});
|
||||
})();
|
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>TinyUSB</title>
|
||||
<script src="serial.js"></script>
|
||||
<script src="application.js"></script>
|
||||
<link rel="stylesheet" href="application.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-content">
|
||||
<h1>TinyUSB - WebUSB Serial Example</h1>
|
||||
<div class="connect-container">
|
||||
<button id="connect" class="button black">Connect</button>
|
||||
<span id="status"></span>
|
||||
</div>
|
||||
<div class="container">
|
||||
<div class="sender">
|
||||
<div class="lines-header">Sender</div>
|
||||
<div class="lines-body">
|
||||
<div id="sender_lines" class="lines"></div>
|
||||
<input id="command_line" class="command-line" placeholder="Start typing ...." />
|
||||
</div>
|
||||
</div>
|
||||
<div class="receiver">
|
||||
<div class="lines-header">Receiver</div>
|
||||
<div class="lines-body">
|
||||
<div id="receiver_lines" class="lines"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,92 @@
|
||||
var serial = {};
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
serial.getPorts = function() {
|
||||
return navigator.usb.getDevices().then(devices => {
|
||||
return devices.map(device => new serial.Port(device));
|
||||
});
|
||||
};
|
||||
|
||||
serial.requestPort = function() {
|
||||
const filters = [
|
||||
{ 'vendorId': 0xcafe }, // TinyUSB
|
||||
{ 'vendorId': 0x239a }, // Adafruit
|
||||
{ 'vendorId': 0x2e8a }, // Raspberry Pi
|
||||
{ 'vendorId': 0x303a }, // Espressif
|
||||
{ 'vendorId': 0x2341 }, // Arduino
|
||||
];
|
||||
return navigator.usb.requestDevice({ 'filters': filters }).then(
|
||||
device => new serial.Port(device)
|
||||
);
|
||||
}
|
||||
|
||||
serial.Port = function(device) {
|
||||
this.device_ = device;
|
||||
this.interfaceNumber = 0;
|
||||
this.endpointIn = 0;
|
||||
this.endpointOut = 0;
|
||||
};
|
||||
|
||||
serial.Port.prototype.connect = function() {
|
||||
let readLoop = () => {
|
||||
this.device_.transferIn(this.endpointIn, 64).then(result => {
|
||||
this.onReceive(result.data);
|
||||
readLoop();
|
||||
}, error => {
|
||||
this.onReceiveError(error);
|
||||
});
|
||||
};
|
||||
|
||||
return this.device_.open()
|
||||
.then(() => {
|
||||
if (this.device_.configuration === null) {
|
||||
return this.device_.selectConfiguration(1);
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
var interfaces = this.device_.configuration.interfaces;
|
||||
interfaces.forEach(element => {
|
||||
element.alternates.forEach(elementalt => {
|
||||
if (elementalt.interfaceClass==0xFF) {
|
||||
this.interfaceNumber = element.interfaceNumber;
|
||||
elementalt.endpoints.forEach(elementendpoint => {
|
||||
if (elementendpoint.direction == "out") {
|
||||
this.endpointOut = elementendpoint.endpointNumber;
|
||||
}
|
||||
if (elementendpoint.direction=="in") {
|
||||
this.endpointIn =elementendpoint.endpointNumber;
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
.then(() => this.device_.claimInterface(this.interfaceNumber))
|
||||
.then(() => this.device_.selectAlternateInterface(this.interfaceNumber, 0))
|
||||
.then(() => this.device_.controlTransferOut({
|
||||
'requestType': 'class',
|
||||
'recipient': 'interface',
|
||||
'request': 0x22,
|
||||
'value': 0x01,
|
||||
'index': this.interfaceNumber}))
|
||||
.then(() => {
|
||||
readLoop();
|
||||
});
|
||||
};
|
||||
|
||||
serial.Port.prototype.disconnect = function() {
|
||||
return this.device_.controlTransferOut({
|
||||
'requestType': 'class',
|
||||
'recipient': 'interface',
|
||||
'request': 0x22,
|
||||
'value': 0x00,
|
||||
'index': this.interfaceNumber})
|
||||
.then(() => this.device_.close());
|
||||
};
|
||||
|
||||
serial.Port.prototype.send = function(data) {
|
||||
return this.device_.transferOut(this.endpointOut, data);
|
||||
};
|
||||
})();
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
This example demonstrates the use of multiple USB CDC/ACM "Virtual
|
||||
Serial" ports
|
||||
|
||||
Written by Bill Westfield (aka WestfW), June 2021.
|
||||
Copyright 2021 by Bill Westfield
|
||||
MIT license, check LICENSE for more information
|
||||
*/
|
||||
|
||||
|
||||
/* The example creates two virtual serial ports. Text entered on
|
||||
* any of the ports will be echoed to the all ports with
|
||||
* - all lower case in port0 (Serial)
|
||||
* - all upper case in port1
|
||||
*
|
||||
* Requirement:
|
||||
* The max number of CDC ports (CFG_TUD_CDC) has to be changed to at least 2.
|
||||
* Config file is located in Adafruit_TinyUSB_Arduino/src/arduino/ports/{platform}/tusb_config_{platform}.h
|
||||
* where platform is one of: nrf, rp2040, samd
|
||||
*
|
||||
* NOTE: Currnetly multiple CDCs on ESP32-Sx is not yet supported.
|
||||
* An PR to update core/esp32/USBCDC and/or pre-built libusb are needed.
|
||||
* We would implement this later when we could.
|
||||
*/
|
||||
|
||||
#include <Adafruit_TinyUSB.h>
|
||||
|
||||
#define LED LED_BUILTIN
|
||||
|
||||
// Create 2nd instance of CDC Ports.
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#error "Currnetly multiple CDCs on ESP32-Sx is not yet supported. An PR to update core/esp32/USBCDC and/or pre-built libusb are needed."
|
||||
// for ESP32, we need to specify instance number when declaring object
|
||||
Adafruit_USBD_CDC USBSer1(1);
|
||||
#else
|
||||
Adafruit_USBD_CDC USBSer1;
|
||||
#endif
|
||||
|
||||
void setup() {
|
||||
pinMode(LED, OUTPUT);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// check to see if multiple CDCs are enabled
|
||||
if ( CFG_TUD_CDC < 2 ) {
|
||||
digitalWrite(LED, HIGH); // LED on for error indicator
|
||||
|
||||
while(1) {
|
||||
Serial.printf("CFG_TUD_CDC must be at least 2, current value is %u\n", CFG_TUD_CDC);
|
||||
Serial.println(" Config file is located in Adafruit_TinyUSB_Arduino/src/arduino/ports/{platform}/tusb_config_{platform}.h");
|
||||
Serial.println(" where platform is one of: nrf, rp2040, samd");
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
// initialize 2nd CDC interface
|
||||
USBSer1.begin(115200);
|
||||
|
||||
while (!Serial || !USBSer1) {
|
||||
if (Serial) {
|
||||
Serial.println("Waiting for other USB ports");
|
||||
}
|
||||
|
||||
if (USBSer1) {
|
||||
USBSer1.println("Waiting for other USB ports");
|
||||
}
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
Serial.print("You are port 0\n\r\n0> ");
|
||||
USBSer1.print("You are port 1\n\r\n1> ");
|
||||
}
|
||||
|
||||
int LEDstate = 0;
|
||||
|
||||
void loop() {
|
||||
int ch;
|
||||
|
||||
ch = Serial.read();
|
||||
if (ch > 0) {
|
||||
printAll(ch);
|
||||
}
|
||||
|
||||
ch = USBSer1.read();
|
||||
if (ch > 0) {
|
||||
printAll(ch);
|
||||
}
|
||||
|
||||
if (delay_without_delaying(500)) {
|
||||
LEDstate = !LEDstate;
|
||||
digitalWrite(LED, LEDstate);
|
||||
}
|
||||
}
|
||||
|
||||
// print to all CDC ports
|
||||
void printAll(int ch) {
|
||||
// always lower case
|
||||
Serial.write(tolower(ch));
|
||||
|
||||
// always upper case
|
||||
USBSer1.write(toupper(ch));
|
||||
}
|
||||
|
||||
// Helper: non-blocking "delay" alternative.
|
||||
boolean delay_without_delaying(unsigned long time) {
|
||||
// return false if we're still "delaying", true if time ms has passed.
|
||||
// this should look a lot like "blink without delay"
|
||||
static unsigned long previousmillis = 0;
|
||||
unsigned long currentmillis = millis();
|
||||
if (currentmillis - previousmillis >= time) {
|
||||
previousmillis = currentmillis;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
/* This sketch demonstrates USB CDC Serial can be dropped by simply
|
||||
* call Serial.end() within setup(). This must be called before any
|
||||
* other USB interfaces (MSC / HID) begin to have a clean configuration
|
||||
*
|
||||
* Note: this will cause device to loose the touch1200 and require
|
||||
* user manual interaction to put device into bootloader/DFU mode.
|
||||
*/
|
||||
|
||||
int led = LED_BUILTIN;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.end();
|
||||
pinMode(led, OUTPUT);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
digitalWrite(led, HIGH);
|
||||
delay(1000);
|
||||
digitalWrite(led, LOW);
|
||||
delay(1000);
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
/* This sketch demonstrates USB Mass Storage and HID mouse (and CDC)
|
||||
* - Enumerated as disk using on-board external flash
|
||||
* - Press button pin will move mouse toward bottom right of monitor
|
||||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat.h"
|
||||
#include "Adafruit_SPIFlash.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MSC External Flash Config
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Un-comment to run example with custom SPI SPI and SS e.g with FRAM breakout
|
||||
// #define CUSTOM_CS A5
|
||||
// #define CUSTOM_SPI SPI
|
||||
|
||||
#if defined(CUSTOM_CS) && defined(CUSTOM_SPI)
|
||||
Adafruit_FlashTransport_SPI flashTransport(CUSTOM_CS, CUSTOM_SPI);
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
// ESP32 use same flash device that store code.
|
||||
// Therefore there is no need to specify the SPI and SS
|
||||
Adafruit_FlashTransport_ESP32 flashTransport;
|
||||
|
||||
#elif defined(ARDUINO_ARCH_RP2040)
|
||||
// RP2040 use same flash device that store code.
|
||||
// Therefore there is no need to specify the SPI and SS
|
||||
// Use default (no-args) constructor to be compatible with CircuitPython partition scheme
|
||||
Adafruit_FlashTransport_RP2040 flashTransport;
|
||||
|
||||
// For generic usage:
|
||||
// Adafruit_FlashTransport_RP2040 flashTransport(start_address, size)
|
||||
// If start_address and size are both 0, value that match filesystem setting in
|
||||
// 'Tools->Flash Size' menu selection will be used
|
||||
|
||||
#else
|
||||
// On-board external flash (QSPI or SPI) macros should already
|
||||
// defined in your board variant if supported
|
||||
// - EXTERNAL_FLASH_USE_QSPI
|
||||
// - EXTERNAL_FLASH_USE_CS/EXTERNAL_FLASH_USE_SPI
|
||||
#if defined(EXTERNAL_FLASH_USE_QSPI)
|
||||
Adafruit_FlashTransport_QSPI flashTransport;
|
||||
|
||||
#elif defined(EXTERNAL_FLASH_USE_SPI)
|
||||
Adafruit_FlashTransport_SPI flashTransport(EXTERNAL_FLASH_USE_CS, EXTERNAL_FLASH_USE_SPI);
|
||||
|
||||
#else
|
||||
#error No QSPI/SPI flash are defined on your board variant.h !
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Adafruit_SPIFlash flash(&flashTransport);
|
||||
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HID Config
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Single Report (no ID) descriptor
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_MOUSE()
|
||||
};
|
||||
|
||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||
// desc report, desc len, protocol, interval, use out endpoint
|
||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
|
||||
|
||||
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
||||
const int pin = 4; // Left Button
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||
const int pin = BUTTON_DOWN;
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined PIN_BUTTON1
|
||||
const int pin = PIN_BUTTON1;
|
||||
bool activeState = false;
|
||||
|
||||
#else
|
||||
const int pin = 12;
|
||||
bool activeState = false;
|
||||
#endif
|
||||
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
flash.begin();
|
||||
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
usb_msc.setID("Adafruit", "External Flash", "1.0");
|
||||
|
||||
// Set callback
|
||||
usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
|
||||
|
||||
// Set disk size, block size should be 512 regardless of spi flash page size
|
||||
usb_msc.setCapacity(flash.size()/512, 512);
|
||||
|
||||
// MSC is ready for read/write
|
||||
usb_msc.setUnitReady(true);
|
||||
|
||||
usb_msc.begin();
|
||||
|
||||
// Set up button
|
||||
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
|
||||
usb_hid.begin();
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("Adafruit TinyUSB Mouse + Mass Storage (external flash) example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// poll gpio once each 10 ms
|
||||
delay(10);
|
||||
|
||||
// button is active low
|
||||
uint32_t const btn = (digitalRead(pin) == activeState);
|
||||
|
||||
// Remote wakeup
|
||||
if ( TinyUSBDevice.suspended() && btn )
|
||||
{
|
||||
// Wake up host if we are in suspend mode
|
||||
// and REMOTE_WAKEUP feature is enabled by host
|
||||
tud_remote_wakeup();
|
||||
}
|
||||
|
||||
/*------------- Mouse -------------*/
|
||||
if ( usb_hid.ready() )
|
||||
{
|
||||
if ( btn )
|
||||
{
|
||||
int8_t const delta = 5;
|
||||
usb_hid.mouseMove(0, delta, delta); // no ID: right + down
|
||||
|
||||
// delay a bit before attempt to send keyboard report
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
||||
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
||||
return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void msc_flush_cb (void)
|
||||
{
|
||||
flash.syncBlocks();
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
/* This sketch demonstrates USB Mass Storage and HID mouse (and CDC)
|
||||
* - Enumerated as 8KB flash disk
|
||||
* - Press button pin will move mouse toward bottom right of monitor
|
||||
*/
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MSC RAM Disk Config
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// 8KB is the smallest size that windows allow to mount
|
||||
#define DISK_BLOCK_NUM 16
|
||||
#define DISK_BLOCK_SIZE 512
|
||||
#include "ramdisk.h"
|
||||
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HID Config
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Single Report (no ID) descriptor
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_MOUSE()
|
||||
};
|
||||
|
||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||
// desc report, desc len, protocol, interval, use out endpoint
|
||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
|
||||
|
||||
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
||||
const int pin = 4; // Left Button
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||
const int pin = BUTTON_DOWN;
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined PIN_BUTTON1
|
||||
const int pin = PIN_BUTTON1;
|
||||
bool activeState = false;
|
||||
|
||||
#else
|
||||
const int pin = 12;
|
||||
bool activeState = false;
|
||||
#endif
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
||||
TinyUSB_Device_Init(0);
|
||||
#endif
|
||||
|
||||
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
usb_msc.setID("Adafruit", "Mass Storage", "1.0");
|
||||
|
||||
// Set disk size
|
||||
usb_msc.setCapacity(DISK_BLOCK_NUM, DISK_BLOCK_SIZE);
|
||||
|
||||
// Set callback
|
||||
usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
|
||||
|
||||
// Set Lun ready (RAM disk is always ready)
|
||||
usb_msc.setUnitReady(true);
|
||||
|
||||
usb_msc.begin();
|
||||
|
||||
// Set up button
|
||||
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
|
||||
usb_hid.begin();
|
||||
|
||||
Serial.begin(115200);
|
||||
while( !TinyUSBDevice.mounted() ) delay(1); // wait for native usb
|
||||
|
||||
Serial.println("Adafruit TinyUSB Mouse + Mass Storage (ramdisk) example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// poll gpio once each 10 ms
|
||||
delay(10);
|
||||
|
||||
// button is active low
|
||||
uint32_t const btn = (digitalRead(pin) == activeState);
|
||||
|
||||
// Remote wakeup
|
||||
if ( TinyUSBDevice.suspended() && btn )
|
||||
{
|
||||
// Wake up host if we are in suspend mode
|
||||
// and REMOTE_WAKEUP feature is enabled by host
|
||||
tud_remote_wakeup();
|
||||
}
|
||||
|
||||
/*------------- Mouse -------------*/
|
||||
if ( usb_hid.ready() )
|
||||
{
|
||||
if ( btn )
|
||||
{
|
||||
int8_t const delta = 5;
|
||||
usb_hid.mouseMove(0, delta, delta); // no ID: right + down
|
||||
|
||||
// delay a bit before attempt to send keyboard report
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t const* addr = msc_disk[lba];
|
||||
memcpy(buffer, addr, bufsize);
|
||||
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t* addr = msc_disk[lba];
|
||||
memcpy(addr, buffer, bufsize);
|
||||
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void msc_flush_cb (void)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef RAMDISK_H_
|
||||
#define RAMDISK_H_
|
||||
|
||||
#define README_CONTENTS \
|
||||
"This is TinyUSB MassStorage device demo for Arduino on RAM disk."
|
||||
|
||||
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
|
||||
//------------- Block0: Boot Sector -------------//
|
||||
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 =
|
||||
// DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num =
|
||||
// 1; fat12_root_entry_num = 16; sector_per_fat = 1; sector_per_track =
|
||||
// 1; head_num = 1; hidden_sectors = 0; drive_number = 0x80;
|
||||
// media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type =
|
||||
// "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
|
||||
// FAT magic code at offset 510-511
|
||||
{0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00,
|
||||
0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00,
|
||||
0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S',
|
||||
'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20,
|
||||
0x00, 0x00,
|
||||
|
||||
// Zero up to 2 last bytes of FAT magic code
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x55, 0xAA},
|
||||
|
||||
//------------- Block1: FAT12 Table -------------//
|
||||
{
|
||||
0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third
|
||||
// entry is cluster end of readme file
|
||||
},
|
||||
|
||||
//------------- Block2: Root Directory -------------//
|
||||
{
|
||||
// first entry is volume label
|
||||
'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// second entry is readme file
|
||||
'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6,
|
||||
0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43,
|
||||
0x02, 0x00, sizeof(README_CONTENTS) - 1, 0x00, 0x00,
|
||||
0x00 // readme's files size (4 Bytes)
|
||||
},
|
||||
|
||||
//------------- Block3: Readme Content -------------//
|
||||
README_CONTENTS};
|
||||
|
||||
#endif /* RAMDISK_H_ */
|
@ -0,0 +1,159 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
/* This example demonstrates use of Host Serial (CDC). SerialHost (declared below) is
|
||||
* an object to manage an CDC peripheral connected to our USB Host connector. This example
|
||||
* will forward all characters from Serial to SerialHost and vice versa.
|
||||
*
|
||||
* Note:
|
||||
* - Device run on native usb controller (controller0)
|
||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
||||
|
||||
* Requirements:
|
||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||
* - Provide VBus (5v) and GND for peripheral
|
||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||
*/
|
||||
|
||||
// pio-usb is required for rp2040 host
|
||||
#include "pio_usb.h"
|
||||
|
||||
// TinyUSB lib
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// Pin D+ for host, D- = D+ + 1
|
||||
#ifndef PIN_USB_HOST_DP
|
||||
#define PIN_USB_HOST_DP 16
|
||||
#endif
|
||||
|
||||
// Pin for enabling Host VBUS. comment out if not used
|
||||
#ifndef PIN_5V_EN
|
||||
#define PIN_5V_EN 18
|
||||
#endif
|
||||
|
||||
#ifndef PIN_5V_EN_STATE
|
||||
#define PIN_5V_EN_STATE 1
|
||||
#endif
|
||||
|
||||
// USB Host object
|
||||
Adafruit_USBH_Host USBHost;
|
||||
|
||||
// CDC Host object
|
||||
Adafruit_USBH_CDC SerialHost;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
// while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("TinyUSB Host Serial Echo Example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint8_t buf[64];
|
||||
|
||||
// Serial -> SerialHost
|
||||
if (Serial.available()) {
|
||||
size_t count = Serial.read(buf, sizeof(buf));
|
||||
if ( SerialHost && SerialHost.connected() ) {
|
||||
SerialHost.write(buf, count);
|
||||
SerialHost.flush();
|
||||
}
|
||||
}
|
||||
|
||||
// SerialHost -> Serial
|
||||
if ( SerialHost.connected() && SerialHost.available() ) {
|
||||
size_t count = SerialHost.read(buf, sizeof(buf));
|
||||
Serial.write(buf, count);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core1
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup1() {
|
||||
// while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||
|
||||
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
|
||||
uint32_t cpu_hz = clock_get_hz(clk_sys);
|
||||
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
|
||||
while ( !Serial ) {
|
||||
delay(10); // wait for native usb
|
||||
}
|
||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
||||
while(1) {
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PIN_5V_EN
|
||||
pinMode(PIN_5V_EN, OUTPUT);
|
||||
|
||||
// power off first
|
||||
digitalWrite(PIN_5V_EN, 1-PIN_5V_EN_STATE);
|
||||
delay(1);
|
||||
|
||||
// power on
|
||||
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||
delay(10);
|
||||
#endif
|
||||
|
||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||
|
||||
// run host stack on controller (rhport) 1
|
||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||
// host bit-banging processing works done in core1 to free up core0 for other works
|
||||
USBHost.begin(1);
|
||||
|
||||
SerialHost.begin(115200);
|
||||
}
|
||||
|
||||
void loop1()
|
||||
{
|
||||
USBHost.task();
|
||||
|
||||
// periodically flush SerialHost if connected
|
||||
if ( SerialHost && SerialHost.connected() ) {
|
||||
SerialHost.flush();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TinyUSB Host callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
extern "C" {
|
||||
|
||||
// Invoked when a device with CDC interface is mounted
|
||||
// idx is index of cdc interface in the internal pool.
|
||||
void tuh_cdc_mount_cb(uint8_t idx) {
|
||||
// bind SerialHost object to this interface index
|
||||
SerialHost.mount(idx);
|
||||
Serial.println("SerialHost is connected to a new CDC device");
|
||||
}
|
||||
|
||||
// Invoked when a device with CDC interface is unmounted
|
||||
void tuh_cdc_umount_cb(uint8_t idx) {
|
||||
SerialHost.umount(idx);
|
||||
Serial.println("SerialHost is disconnected");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
/* This example demonstrates use of both device and host, where
|
||||
* - Device run on native usb controller (controller0)
|
||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
||||
*
|
||||
* Requirements:
|
||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||
* - Provide VBus (5v) and GND for peripheral
|
||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||
*/
|
||||
|
||||
// pio-usb is required for rp2040 host
|
||||
#include "pio_usb.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// Pin D+ for host, D- = D+ + 1
|
||||
#ifndef PIN_USB_HOST_DP
|
||||
#define PIN_USB_HOST_DP 16
|
||||
#endif
|
||||
|
||||
// Pin for enabling Host VBUS. comment out if not used
|
||||
#ifndef PIN_5V_EN
|
||||
#define PIN_5V_EN 18
|
||||
#endif
|
||||
|
||||
#ifndef PIN_5V_EN_STATE
|
||||
#define PIN_5V_EN_STATE 1
|
||||
#endif
|
||||
|
||||
// Language ID: English
|
||||
#define LANGUAGE_ID 0x0409
|
||||
|
||||
// USB Host object
|
||||
Adafruit_USBH_Host USBHost;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("TinyUSB Dual Device Info Example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core1
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup1() {
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||
|
||||
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
|
||||
uint32_t cpu_hz = clock_get_hz(clk_sys);
|
||||
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
|
||||
while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
||||
while(1) delay(1);
|
||||
}
|
||||
|
||||
#ifdef PIN_5V_EN
|
||||
pinMode(PIN_5V_EN, OUTPUT);
|
||||
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||
#endif
|
||||
|
||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||
|
||||
// run host stack on controller (rhport) 1
|
||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||
// host bit-banging processing works done in core1 to free up core0 for other works
|
||||
USBHost.begin(1);
|
||||
}
|
||||
|
||||
void loop1()
|
||||
{
|
||||
USBHost.task();
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Invoked when device with hid interface is mounted
|
||||
// Report descriptor is also available for use.
|
||||
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
|
||||
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
|
||||
// it will be skipped therefore report_desc = NULL, desc_len = 0
|
||||
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
|
||||
(void) desc_report;
|
||||
(void) desc_len;
|
||||
uint16_t vid, pid;
|
||||
tuh_vid_pid_get(dev_addr, &vid, &pid);
|
||||
|
||||
Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
|
||||
Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);
|
||||
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||
Serial.printf("Error: cannot request to receive report\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when device with hid interface is un-mounted
|
||||
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
|
||||
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
|
||||
}
|
||||
|
||||
// Invoked when received report from device via interrupt endpoint
|
||||
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
|
||||
Serial.printf("HIDreport : ");
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
Serial.printf("0x%02X ", report[i]);
|
||||
}
|
||||
Serial.println();
|
||||
// continue to request to receive report
|
||||
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||
Serial.printf("Error: cannot request to receive report\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
} // extern C
|
@ -0,0 +1,213 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2023 Bill Binko for Adafruit Industries
|
||||
Based on tremor_filter example by Thach Ha
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
/* This example demonstrates use of both device and host, where
|
||||
* - Device run on native usb controller (controller0)
|
||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
||||
*
|
||||
* Example sketch receive mouse report from host interface (from e.g consumer mouse)
|
||||
* and reduce large motions due to tremors by applying the natural log function.
|
||||
* It handles negative values and a dead zone where small values will not be adjusted.
|
||||
* Adjusted mouse movement are send via device interface (to PC).
|
||||
*
|
||||
* Requirements:
|
||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||
* - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
|
||||
* - Provide VBus (5v) and GND for peripheral
|
||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||
*/
|
||||
|
||||
// pio-usb is required for rp2040 host
|
||||
#include "pio_usb.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
#include <math.h>
|
||||
|
||||
// Pin D+ for host, D- = D+ + 1
|
||||
#ifndef PIN_USB_HOST_DP
|
||||
#define PIN_USB_HOST_DP 16
|
||||
#endif
|
||||
|
||||
// Pin for enabling Host VBUS. comment out if not used
|
||||
#ifndef PIN_5V_EN
|
||||
#define PIN_5V_EN 18
|
||||
#endif
|
||||
|
||||
#ifndef PIN_5V_EN_STATE
|
||||
#define PIN_5V_EN_STATE 1
|
||||
#endif
|
||||
|
||||
// Language ID: English
|
||||
#define LANGUAGE_ID 0x0409
|
||||
|
||||
// USB Host object
|
||||
Adafruit_USBH_Host USBHost;
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Single Report (no ID) descriptor
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_MOUSE()
|
||||
};
|
||||
|
||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||
// desc report, desc len, protocol, interval, use out endpoint
|
||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_MOUSE, 2, false);
|
||||
|
||||
/* Adjustable parameters for the log_filter() method. Adjust for each user (would be ideal to have this
|
||||
* adjustable w/o recompiling
|
||||
*/
|
||||
#define PRESCALE 8.0 // Must be > 0, Higher numbers increase rate of attenuation
|
||||
#define POSTSCALE 1.5 // Must be > 0, Higher numbers compensate for PRESCALE attenuation
|
||||
#define DEADZONE 1.0 // Must be > 1, Movements < this magnitude will not be filtered
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
usb_hid.begin();
|
||||
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.println("ATMakers Logarithm Tremor Filter Example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core1
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup1() {
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||
|
||||
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
|
||||
uint32_t cpu_hz = clock_get_hz(clk_sys);
|
||||
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
|
||||
while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
||||
while(1) delay(1);
|
||||
}
|
||||
|
||||
#ifdef PIN_5V_EN
|
||||
pinMode(PIN_5V_EN, OUTPUT);
|
||||
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||
#endif
|
||||
|
||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||
|
||||
// run host stack on controller (rhport) 1
|
||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||
// host bit-banging processing works done in core1 to free up core0 for other works
|
||||
USBHost.begin(1);
|
||||
}
|
||||
|
||||
void loop1()
|
||||
{
|
||||
USBHost.task();
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Invoked when device with hid interface is mounted
|
||||
// Report descriptor is also available for use.
|
||||
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
|
||||
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
|
||||
// it will be skipped therefore report_desc = NULL, desc_len = 0
|
||||
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
|
||||
(void) desc_report;
|
||||
(void) desc_len;
|
||||
uint16_t vid, pid;
|
||||
tuh_vid_pid_get(dev_addr, &vid, &pid);
|
||||
|
||||
Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
|
||||
Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);
|
||||
|
||||
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
|
||||
if (itf_protocol == HID_ITF_PROTOCOL_MOUSE) {
|
||||
Serial.printf("HID Mouse\r\n");
|
||||
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||
Serial.printf("Error: cannot request to receive report\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when device with hid interface is un-mounted
|
||||
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
|
||||
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
|
||||
}
|
||||
|
||||
|
||||
// Invoked when received report from device via interrupt endpoint
|
||||
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
|
||||
filter_report((hid_mouse_report_t const *) report);
|
||||
|
||||
// continue to request to receive report
|
||||
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||
Serial.printf("Error: cannot request to receive report\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
} // extern C
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Low pass filter Functions
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/*
|
||||
* log_filter: Reduce large motions due to tremors by applying the natural log function
|
||||
* Handles negative values and a dead zone where small values will not be adjusted
|
||||
*/
|
||||
int8_t log_filter(int8_t val)
|
||||
{
|
||||
if (val < -1*DEADZONE)
|
||||
{
|
||||
return (int8_t) (-1.0 * POSTSCALE * logf(-1.0 * PRESCALE * (float)val));
|
||||
}
|
||||
else if (val > DEADZONE)
|
||||
{
|
||||
return (int8_t) (POSTSCALE * logf(PRESCALE * (float)val));
|
||||
}
|
||||
else
|
||||
{
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust HID report by applying log_filter
|
||||
*/
|
||||
void filter_report(hid_mouse_report_t const* report) {
|
||||
|
||||
int8_t old_x = report->x;
|
||||
int8_t old_y = report->y;
|
||||
|
||||
hid_mouse_report_t filtered_report = *report;
|
||||
filtered_report.x = log_filter(old_x);
|
||||
filtered_report.y = log_filter(old_y);
|
||||
|
||||
//Serial.printf("%d,%d,%d,%d\n", old_x, filtered_report.x, old_y, filtered_report.y);
|
||||
usb_hid.sendReport(0, &filtered_report, sizeof(filtered_report));
|
||||
|
||||
}
|
@ -0,0 +1,224 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
/* This example demonstrates use of both device and host, where
|
||||
* - Device run on native usb controller (controller0)
|
||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
||||
*
|
||||
* Example sketch receive mouse report from host interface (from e.g consumer mouse)
|
||||
* and apply a butterworth low pass filter with a specific CUTOFF_FREQUENCY on hid mouse movement report.
|
||||
* Filtered report are send via device interface (to PC) acting as a "Mouse Tremor Filter".
|
||||
*
|
||||
* Requirements:
|
||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||
* - 2 consecutive GPIOs: D+ is defined by PIN_PIO_USB_HOST_DP, D- = D+ +1
|
||||
* - Provide VBus (5v) and GND for peripheral
|
||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||
*/
|
||||
|
||||
// pio-usb is required for rp2040 host
|
||||
#include "pio_usb.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// Pin D+ for host, D- = D+ + 1
|
||||
#ifndef PIN_USB_HOST_DP
|
||||
#define PIN_USB_HOST_DP 16
|
||||
#endif
|
||||
|
||||
// Pin for enabling Host VBUS. comment out if not used
|
||||
#ifndef PIN_5V_EN
|
||||
#define PIN_5V_EN 18
|
||||
#endif
|
||||
|
||||
#ifndef PIN_5V_EN_STATE
|
||||
#define PIN_5V_EN_STATE 1
|
||||
#endif
|
||||
|
||||
// Language ID: English
|
||||
#define LANGUAGE_ID 0x0409
|
||||
|
||||
// USB Host object
|
||||
Adafruit_USBH_Host USBHost;
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Single Report (no ID) descriptor
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_MOUSE()
|
||||
};
|
||||
|
||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||
// desc report, desc len, protocol, interval, use out endpoint
|
||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_MOUSE, 2, false);
|
||||
|
||||
//------------- Low pass filter with Butterworth -------------//
|
||||
// Butterworth low-pass filter coefficients
|
||||
typedef struct {
|
||||
float b0, b1, b2, a1, a2;
|
||||
} butterworth_coeffs_t;
|
||||
|
||||
#define SAMPLING_FREQUENCY 100.0 // Hz
|
||||
#define CUTOFF_FREQUENCY 10.0 // Hz
|
||||
|
||||
// x, y
|
||||
butterworth_coeffs_t coeffs[2];
|
||||
|
||||
butterworth_coeffs_t butterworth_lowpass(float cutoff_frequency, float sampling_frequency);
|
||||
void filter_report(hid_mouse_report_t const* report);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
usb_hid.begin();
|
||||
|
||||
coeffs[0] = butterworth_lowpass(CUTOFF_FREQUENCY, SAMPLING_FREQUENCY);
|
||||
coeffs[1] = butterworth_lowpass(CUTOFF_FREQUENCY, SAMPLING_FREQUENCY);
|
||||
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.println("TinyUSB Mouse Tremor Filter Example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core1
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup1() {
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||
|
||||
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
|
||||
uint32_t cpu_hz = clock_get_hz(clk_sys);
|
||||
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
|
||||
while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
||||
while(1) delay(1);
|
||||
}
|
||||
|
||||
#ifdef PIN_5V_EN
|
||||
pinMode(PIN_5V_EN, OUTPUT);
|
||||
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||
#endif
|
||||
|
||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||
|
||||
// run host stack on controller (rhport) 1
|
||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||
// host bit-banging processing works done in core1 to free up core0 for other works
|
||||
USBHost.begin(1);
|
||||
}
|
||||
|
||||
void loop1()
|
||||
{
|
||||
USBHost.task();
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Invoked when device with hid interface is mounted
|
||||
// Report descriptor is also available for use.
|
||||
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
|
||||
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
|
||||
// it will be skipped therefore report_desc = NULL, desc_len = 0
|
||||
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
|
||||
(void) desc_report;
|
||||
(void) desc_len;
|
||||
uint16_t vid, pid;
|
||||
tuh_vid_pid_get(dev_addr, &vid, &pid);
|
||||
|
||||
Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
|
||||
Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);
|
||||
|
||||
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
|
||||
if (itf_protocol == HID_ITF_PROTOCOL_MOUSE) {
|
||||
Serial.printf("HID Mouse\r\n");
|
||||
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||
Serial.printf("Error: cannot request to receive report\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when device with hid interface is un-mounted
|
||||
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
|
||||
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
|
||||
}
|
||||
|
||||
|
||||
// Invoked when received report from device via interrupt endpoint
|
||||
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
|
||||
filter_report((hid_mouse_report_t const *) report);
|
||||
|
||||
// continue to request to receive report
|
||||
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||
Serial.printf("Error: cannot request to receive report\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
} // extern C
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Low pass filter Functions
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
butterworth_coeffs_t butterworth_lowpass(float cutoff_frequency, float sampling_frequency) {
|
||||
butterworth_coeffs_t coe;
|
||||
|
||||
float omega = 2.0 * PI * cutoff_frequency / sampling_frequency;
|
||||
float c = cos(omega);
|
||||
float s = sin(omega);
|
||||
float t = tan(omega / 2.0);
|
||||
float alpha = s / (2.0 * t);
|
||||
|
||||
coe.b0 = 1.0 / (1.0 + 2.0 * alpha + 2.0 * alpha * alpha);
|
||||
coe.b1 = 2.0 * coe.b0;
|
||||
coe.b2 = coe.b0;
|
||||
coe.a1 = 2.0 * (alpha * alpha - 1.0) * coe.b0;
|
||||
coe.a2 = (1.0 - 2.0 * alpha + 2.0 * alpha * alpha) * coe.b0;
|
||||
|
||||
return coe;
|
||||
}
|
||||
|
||||
float butterworth_filter(float data, butterworth_coeffs_t *coeffs, float *filtered, float *prev1, float *prev2) {
|
||||
float output = coeffs->b0 * data + coeffs->b1 * (*prev1) + coeffs->b2 * (*prev2) - coeffs->a1 * (*filtered) - coeffs->a2 * (*prev1);
|
||||
*prev2 = *prev1;
|
||||
*prev1 = data;
|
||||
*filtered = output;
|
||||
return output;
|
||||
}
|
||||
|
||||
void filter_report(hid_mouse_report_t const* report) {
|
||||
static float filtered[2] = { 0.0, 0.0 };
|
||||
static float prev1[2] = { 0.0, 0.0 };
|
||||
static float prev2[2] = { 0.0, 0.0 };
|
||||
|
||||
butterworth_filter(report->x, &coeffs[0], &filtered[0], &prev1[0], &prev2[0]);
|
||||
butterworth_filter(report->y, &coeffs[1], &filtered[1], &prev1[1], &prev2[1]);
|
||||
|
||||
hid_mouse_report_t filtered_report = *report;
|
||||
filtered_report.x = (int8_t) filtered[0];
|
||||
filtered_report.y = (int8_t) filtered[1];
|
||||
|
||||
usb_hid.sendReport(0, &filtered_report, sizeof(filtered_report));
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
/* This example demonstrates use of both device and host, where
|
||||
* - Device run on native usb controller (controller0)
|
||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
||||
*
|
||||
* Example sketch receive keyboard report from host interface (from e.g consumer keyboard)
|
||||
* and remap it to another key and send it via device interface (to PC). For simplicity,
|
||||
* this example only toggle shift key to the report, effectively remap:
|
||||
* - all character key <-> upper case
|
||||
* - number <-> its symbol (with shift)
|
||||
*
|
||||
* Requirements:
|
||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||
* - Provide VBus (5v) and GND for peripheral
|
||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||
*/
|
||||
|
||||
// pio-usb is required for rp2040 host
|
||||
#include "pio_usb.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// Pin D+ for host, D- = D+ + 1
|
||||
#ifndef PIN_USB_HOST_DP
|
||||
#define PIN_USB_HOST_DP 16
|
||||
#endif
|
||||
|
||||
// Pin for enabling Host VBUS. comment out if not used
|
||||
#ifndef PIN_5V_EN
|
||||
#define PIN_5V_EN 18
|
||||
#endif
|
||||
|
||||
#ifndef PIN_5V_EN_STATE
|
||||
#define PIN_5V_EN_STATE 1
|
||||
#endif
|
||||
|
||||
// Language ID: English
|
||||
#define LANGUAGE_ID 0x0409
|
||||
|
||||
// USB Host object
|
||||
Adafruit_USBH_Host USBHost;
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Single Report (no ID) descriptor
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_KEYBOARD()
|
||||
};
|
||||
|
||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||
// desc report, desc len, protocol, interval, use out endpoint
|
||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
usb_hid.begin();
|
||||
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("TinyUSB Host HID Remap Example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core1
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup1() {
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||
|
||||
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
|
||||
uint32_t cpu_hz = clock_get_hz(clk_sys);
|
||||
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
|
||||
while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
||||
while(1) delay(1);
|
||||
}
|
||||
|
||||
#ifdef PIN_5V_EN
|
||||
pinMode(PIN_5V_EN, OUTPUT);
|
||||
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||
#endif
|
||||
|
||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||
|
||||
// run host stack on controller (rhport) 1
|
||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||
// host bit-banging processing works done in core1 to free up core0 for other works
|
||||
USBHost.begin(1);
|
||||
}
|
||||
|
||||
void loop1()
|
||||
{
|
||||
USBHost.task();
|
||||
}
|
||||
|
||||
// Invoked when device with hid interface is mounted
|
||||
// Report descriptor is also available for use.
|
||||
// tuh_hid_parse_report_descriptor() can be used to parse common/simple enough
|
||||
// descriptor. Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE,
|
||||
// it will be skipped therefore report_desc = NULL, desc_len = 0
|
||||
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *desc_report, uint16_t desc_len) {
|
||||
(void)desc_report;
|
||||
(void)desc_len;
|
||||
uint16_t vid, pid;
|
||||
tuh_vid_pid_get(dev_addr, &vid, &pid);
|
||||
|
||||
Serial.printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
|
||||
Serial.printf("VID = %04x, PID = %04x\r\n", vid, pid);
|
||||
|
||||
uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance);
|
||||
if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) {
|
||||
Serial.printf("HID Keyboard\r\n");
|
||||
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||
Serial.printf("Error: cannot request to receive report\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when device with hid interface is un-mounted
|
||||
void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t instance) {
|
||||
Serial.printf("HID device address = %d, instance = %d is unmounted\r\n", dev_addr, instance);
|
||||
}
|
||||
|
||||
void remap_key(hid_keyboard_report_t const* original_report, hid_keyboard_report_t* remapped_report)
|
||||
{
|
||||
memcpy(remapped_report, original_report, sizeof(hid_keyboard_report_t));
|
||||
|
||||
// only remap if not empty report i.e key released
|
||||
for(uint8_t i=0; i<6; i++) {
|
||||
if (remapped_report->keycode[i] != 0) {
|
||||
// Note: we ignore right shift here
|
||||
remapped_report->modifier ^= KEYBOARD_MODIFIER_LEFTSHIFT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when received report from device via interrupt endpoint
|
||||
void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) {
|
||||
if ( len != 8 ) {
|
||||
Serial.printf("report len = %u NOT 8, probably something wrong !!\r\n", len);
|
||||
}else {
|
||||
hid_keyboard_report_t remapped_report;
|
||||
remap_key((hid_keyboard_report_t const*) report, &remapped_report);
|
||||
|
||||
// send remapped report to PC
|
||||
// NOTE: for better performance you should save/queue remapped report instead of
|
||||
// blocking wait for usb_hid ready here
|
||||
while ( !usb_hid.ready() ) {
|
||||
yield();
|
||||
}
|
||||
|
||||
usb_hid.sendReport(0, &remapped_report, sizeof(hid_keyboard_report_t));
|
||||
}
|
||||
|
||||
// continue to request to receive report
|
||||
if (!tuh_hid_receive_report(dev_addr, instance)) {
|
||||
Serial.printf("Error: cannot request to receive report\r\n");
|
||||
}
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
/* This example demonstrates use of both device and host, where
|
||||
* - Device run on native usb controller (controller0)
|
||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
||||
*
|
||||
* Example will log CPU temperature periodically (ms,value) to USB thumbdrive
|
||||
*
|
||||
* Requirements:
|
||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||
* - Provide VBus (5v) and GND for peripheral
|
||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||
*/
|
||||
|
||||
// pio-usb is required for rp2040 host
|
||||
#include "pio_usb.h"
|
||||
|
||||
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
|
||||
#include "SdFat.h"
|
||||
|
||||
// TinyUSB lib
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// Pin D+ for host, D- = D+ + 1
|
||||
#ifndef PIN_USB_HOST_DP
|
||||
#define PIN_USB_HOST_DP 16
|
||||
#endif
|
||||
|
||||
// Pin for enabling Host VBUS. comment out if not used
|
||||
#ifndef PIN_5V_EN
|
||||
#define PIN_5V_EN 18
|
||||
#endif
|
||||
|
||||
#ifndef PIN_5V_EN_STATE
|
||||
#define PIN_5V_EN_STATE 1
|
||||
#endif
|
||||
|
||||
|
||||
#define LOG_FILE "cpu_temp.csv"
|
||||
#define LOG_INTERVAL 5000
|
||||
|
||||
// USB Host object
|
||||
Adafruit_USBH_Host USBHost;
|
||||
|
||||
// USB Host MSC Block Device object which implemented API for use with SdFat
|
||||
Adafruit_USBH_MSC_BlockDevice msc_block_dev;
|
||||
|
||||
// file system object from SdFat
|
||||
FatVolume fatfs;
|
||||
File32 f_log;
|
||||
|
||||
// if file system is successfully mounted on usb block device
|
||||
volatile bool is_mounted = false;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("TinyUSB Host MassStorage Data Logger Example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (!is_mounted) {
|
||||
// nothing to do
|
||||
delay(1000);
|
||||
return;
|
||||
}
|
||||
|
||||
// Turn on LED when start writing
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
|
||||
f_log = fatfs.open(LOG_FILE, O_WRITE | O_APPEND | O_CREAT);
|
||||
|
||||
if (!f_log) {
|
||||
Serial.println("Cannot create file: " LOG_FILE);
|
||||
}else {
|
||||
float cpu_temp = analogReadTemp();
|
||||
uint32_t ms = millis();
|
||||
|
||||
Serial.printf("%u,%.02f\r\n", millis(), cpu_temp);
|
||||
f_log.printf("%u,%.02f\r\n", millis(), cpu_temp);
|
||||
|
||||
f_log.close();
|
||||
}
|
||||
|
||||
delay(LOG_INTERVAL);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core1
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup1() {
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||
|
||||
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
|
||||
uint32_t cpu_hz = clock_get_hz(clk_sys);
|
||||
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
|
||||
while ( !Serial ) {
|
||||
delay(10); // wait for native usb
|
||||
}
|
||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
||||
while(1) {
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PIN_5V_EN
|
||||
pinMode(PIN_5V_EN, OUTPUT);
|
||||
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||
#endif
|
||||
|
||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||
|
||||
// run host stack on controller (rhport) 1
|
||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||
// host bit-banging processing works done in core1 to free up core0 for other works
|
||||
USBHost.begin(1);
|
||||
}
|
||||
|
||||
void loop1()
|
||||
{
|
||||
USBHost.task();
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TinyUSB Host callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when device is mounted (configured)
|
||||
void tuh_mount_cb (uint8_t daddr)
|
||||
{
|
||||
(void) daddr;
|
||||
}
|
||||
|
||||
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||
void tuh_umount_cb(uint8_t daddr)
|
||||
{
|
||||
(void) daddr;
|
||||
}
|
||||
|
||||
// Invoked when a device with MassStorage interface is mounted
|
||||
void tuh_msc_mount_cb(uint8_t dev_addr)
|
||||
{
|
||||
// Initialize block device with MSC device address
|
||||
msc_block_dev.begin(dev_addr);
|
||||
|
||||
// For simplicity this example only support LUN 0
|
||||
msc_block_dev.setActiveLUN(0);
|
||||
|
||||
msc_block_dev.setWriteCompleteCallback(write_complete_callback);
|
||||
|
||||
is_mounted = fatfs.begin(&msc_block_dev);
|
||||
|
||||
if (is_mounted) {
|
||||
fatfs.ls(&Serial, LS_SIZE);
|
||||
}else {
|
||||
Serial.println("Failed to mount mass storage device. Make sure it is formatted as FAT");
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when a device with MassStorage interface is unmounted
|
||||
void tuh_msc_umount_cb(uint8_t dev_addr)
|
||||
{
|
||||
(void) dev_addr;
|
||||
|
||||
// unmount file system
|
||||
is_mounted = false;
|
||||
fatfs.end();
|
||||
|
||||
// end block device
|
||||
msc_block_dev.end();
|
||||
}
|
||||
|
||||
|
||||
bool write_complete_callback(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data)
|
||||
{
|
||||
(void) dev_addr;
|
||||
(void) cb_data;
|
||||
|
||||
// turn off LED after write is complete
|
||||
// Note this only marks the usb transfer is complete, device can take longer to actual
|
||||
// write data to physical flash
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -0,0 +1,160 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
/* This example demonstrates use of both device and host, where
|
||||
* - Device run on native usb controller (controller0)
|
||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
||||
*
|
||||
* Requirements:
|
||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||
* - Provide VBus (5v) and GND for peripheral
|
||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||
*/
|
||||
|
||||
// pio-usb is required for rp2040 host
|
||||
#include "pio_usb.h"
|
||||
|
||||
// SdFat is required for using Adafruit_USBH_MSC_SdFatDevice
|
||||
#include "SdFat.h"
|
||||
|
||||
// TinyUSB lib
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// Pin D+ for host, D- = D+ + 1
|
||||
#ifndef PIN_USB_HOST_DP
|
||||
#define PIN_USB_HOST_DP 16
|
||||
#endif
|
||||
|
||||
// Pin for enabling Host VBUS. comment out if not used
|
||||
#ifndef PIN_5V_EN
|
||||
#define PIN_5V_EN 18
|
||||
#endif
|
||||
|
||||
#ifndef PIN_5V_EN_STATE
|
||||
#define PIN_5V_EN_STATE 1
|
||||
#endif
|
||||
|
||||
// USB Host object
|
||||
Adafruit_USBH_Host USBHost;
|
||||
|
||||
// USB Host MSC Block Device object which implemented API for use with SdFat
|
||||
Adafruit_USBH_MSC_BlockDevice msc_block_dev;
|
||||
|
||||
// file system object from SdFat
|
||||
FatVolume fatfs;
|
||||
|
||||
// if file system is successfully mounted on usb block device
|
||||
bool is_mounted = false;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("TinyUSB Host Mass Storage File Explorer Example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core1
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup1() {
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||
|
||||
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
|
||||
uint32_t cpu_hz = clock_get_hz(clk_sys);
|
||||
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
|
||||
while ( !Serial ) {
|
||||
delay(10); // wait for native usb
|
||||
}
|
||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
||||
while(1) {
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PIN_5V_EN
|
||||
pinMode(PIN_5V_EN, OUTPUT);
|
||||
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||
#endif
|
||||
|
||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||
|
||||
// run host stack on controller (rhport) 1
|
||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||
// host bit-banging processing works done in core1 to free up core0 for other works
|
||||
USBHost.begin(1);
|
||||
}
|
||||
|
||||
void loop1()
|
||||
{
|
||||
USBHost.task();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TinyUSB Host callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when device is mounted (configured)
|
||||
void tuh_mount_cb (uint8_t daddr)
|
||||
{
|
||||
(void) daddr;
|
||||
}
|
||||
|
||||
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||
void tuh_umount_cb(uint8_t daddr)
|
||||
{
|
||||
(void) daddr;
|
||||
}
|
||||
|
||||
// Invoked when a device with MassStorage interface is mounted
|
||||
void tuh_msc_mount_cb(uint8_t dev_addr)
|
||||
{
|
||||
// Initialize block device with MSC device address
|
||||
msc_block_dev.begin(dev_addr);
|
||||
|
||||
// For simplicity this example only support LUN 0
|
||||
msc_block_dev.setActiveLUN(0);
|
||||
|
||||
is_mounted = fatfs.begin(&msc_block_dev);
|
||||
|
||||
if (is_mounted) {
|
||||
fatfs.ls(&Serial, LS_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
// Invoked when a device with MassStorage interface is unmounted
|
||||
void tuh_msc_umount_cb(uint8_t dev_addr)
|
||||
{
|
||||
(void) dev_addr;
|
||||
|
||||
// unmount file system
|
||||
is_mounted = false;
|
||||
fatfs.end();
|
||||
|
||||
// end block device
|
||||
msc_block_dev.end();
|
||||
}
|
||||
|
@ -0,0 +1,252 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
/* This example demonstrates use of both device and host, where
|
||||
* - Device run on native usb controller (controller0)
|
||||
* - Host run on bit-banging 2 GPIOs with the help of Pico-PIO-USB library (controller1)
|
||||
*
|
||||
* Requirements:
|
||||
* - [Pico-PIO-USB](https://github.com/sekigon-gonnoc/Pico-PIO-USB) library
|
||||
* - 2 consecutive GPIOs: D+ is defined by PIN_USB_HOST_DP, D- = D+ +1
|
||||
* - Provide VBus (5v) and GND for peripheral
|
||||
* - CPU Speed must be either 120 or 240 Mhz. Selected via "Menu -> CPU Speed"
|
||||
*
|
||||
* RP2040 host stack will get device descriptors of attached devices and print it out via
|
||||
* device cdc (Serial) as follows:
|
||||
* Device 1: ID 046d:c52f
|
||||
Device Descriptor:
|
||||
bLength 18
|
||||
bDescriptorType 1
|
||||
bcdUSB 0200
|
||||
bDeviceClass 0
|
||||
bDeviceSubClass 0
|
||||
bDeviceProtocol 0
|
||||
bMaxPacketSize0 8
|
||||
idVendor 0x046d
|
||||
idProduct 0xc52f
|
||||
bcdDevice 2200
|
||||
iManufacturer 1 Logitech
|
||||
iProduct 2 USB Receiver
|
||||
iSerialNumber 0
|
||||
bNumConfigurations 1
|
||||
*
|
||||
*/
|
||||
|
||||
// pio-usb is required for rp2040 host
|
||||
#include "pio_usb.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// Pin D+ for host, D- = D+ + 1
|
||||
#ifndef PIN_USB_HOST_DP
|
||||
#define PIN_USB_HOST_DP 16
|
||||
#endif
|
||||
|
||||
// Pin for enabling Host VBUS. comment out if not used
|
||||
#ifndef PIN_5V_EN
|
||||
#define PIN_5V_EN 18
|
||||
#endif
|
||||
|
||||
#ifndef PIN_5V_EN_STATE
|
||||
#define PIN_5V_EN_STATE 1
|
||||
#endif
|
||||
|
||||
// Language ID: English
|
||||
#define LANGUAGE_ID 0x0409
|
||||
|
||||
// USB Host object
|
||||
Adafruit_USBH_Host USBHost;
|
||||
|
||||
// holding device descriptor
|
||||
tusb_desc_device_t desc_device;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core0
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
Serial1.begin(115200);
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("TinyUSB Dual Device Info Example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup and Loop on Core1
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setup1() {
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.println("Core1 setup to run TinyUSB host with pio-usb");
|
||||
|
||||
// Check for CPU frequency, must be multiple of 120Mhz for bit-banging USB
|
||||
uint32_t cpu_hz = clock_get_hz(clk_sys);
|
||||
if ( cpu_hz != 120000000UL && cpu_hz != 240000000UL ) {
|
||||
while ( !Serial ) {
|
||||
delay(10); // wait for native usb
|
||||
}
|
||||
Serial.printf("Error: CPU Clock = %lu, PIO USB require CPU clock must be multiple of 120 Mhz\r\n", cpu_hz);
|
||||
Serial.printf("Change your CPU Clock to either 120 or 240 Mhz in Menu->CPU Speed \r\n");
|
||||
while(1) {
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PIN_5V_EN
|
||||
pinMode(PIN_5V_EN, OUTPUT);
|
||||
digitalWrite(PIN_5V_EN, PIN_5V_EN_STATE);
|
||||
#endif
|
||||
|
||||
pio_usb_configuration_t pio_cfg = PIO_USB_DEFAULT_CONFIG;
|
||||
pio_cfg.pin_dp = PIN_USB_HOST_DP;
|
||||
USBHost.configure_pio_usb(1, &pio_cfg);
|
||||
|
||||
// run host stack on controller (rhport) 1
|
||||
// Note: For rp2040 pico-pio-usb, calling USBHost.begin() on core1 will have most of the
|
||||
// host bit-banging processing works done in core1 to free up core0 for other works
|
||||
USBHost.begin(1);
|
||||
}
|
||||
|
||||
void loop1()
|
||||
{
|
||||
USBHost.task();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TinyUSB Host callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when device is mounted (configured)
|
||||
void tuh_mount_cb (uint8_t daddr)
|
||||
{
|
||||
Serial.printf("Device attached, address = %d\r\n", daddr);
|
||||
|
||||
// Get Device Descriptor
|
||||
tuh_descriptor_get_device(daddr, &desc_device, 18, print_device_descriptor, 0);
|
||||
}
|
||||
|
||||
/// Invoked when device is unmounted (bus reset/unplugged)
|
||||
void tuh_umount_cb(uint8_t daddr)
|
||||
{
|
||||
Serial.printf("Device removed, address = %d\r\n", daddr);
|
||||
}
|
||||
|
||||
void print_device_descriptor(tuh_xfer_t* xfer)
|
||||
{
|
||||
if ( XFER_RESULT_SUCCESS != xfer->result )
|
||||
{
|
||||
Serial.printf("Failed to get device descriptor\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
|
||||
Serial.printf("Device %u: ID %04x:%04x\r\n", daddr, desc_device.idVendor, desc_device.idProduct);
|
||||
Serial.printf("Device Descriptor:\r\n");
|
||||
Serial.printf(" bLength %u\r\n" , desc_device.bLength);
|
||||
Serial.printf(" bDescriptorType %u\r\n" , desc_device.bDescriptorType);
|
||||
Serial.printf(" bcdUSB %04x\r\n" , desc_device.bcdUSB);
|
||||
Serial.printf(" bDeviceClass %u\r\n" , desc_device.bDeviceClass);
|
||||
Serial.printf(" bDeviceSubClass %u\r\n" , desc_device.bDeviceSubClass);
|
||||
Serial.printf(" bDeviceProtocol %u\r\n" , desc_device.bDeviceProtocol);
|
||||
Serial.printf(" bMaxPacketSize0 %u\r\n" , desc_device.bMaxPacketSize0);
|
||||
Serial.printf(" idVendor 0x%04x\r\n" , desc_device.idVendor);
|
||||
Serial.printf(" idProduct 0x%04x\r\n" , desc_device.idProduct);
|
||||
Serial.printf(" bcdDevice %04x\r\n" , desc_device.bcdDevice);
|
||||
|
||||
// Get String descriptor using Sync API
|
||||
uint16_t temp_buf[128];
|
||||
|
||||
Serial.printf(" iManufacturer %u " , desc_device.iManufacturer);
|
||||
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_manufacturer_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)) )
|
||||
{
|
||||
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
|
||||
}
|
||||
Serial.printf("\r\n");
|
||||
|
||||
Serial.printf(" iProduct %u " , desc_device.iProduct);
|
||||
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_product_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
|
||||
{
|
||||
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
|
||||
}
|
||||
Serial.printf("\r\n");
|
||||
|
||||
Serial.printf(" iSerialNumber %u " , desc_device.iSerialNumber);
|
||||
if (XFER_RESULT_SUCCESS == tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, temp_buf, sizeof(temp_buf)))
|
||||
{
|
||||
print_utf16(temp_buf, TU_ARRAY_SIZE(temp_buf));
|
||||
}
|
||||
Serial.printf("\r\n");
|
||||
|
||||
Serial.printf(" bNumConfigurations %u\r\n" , desc_device.bNumConfigurations);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// String Descriptor Helper
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static void _convert_utf16le_to_utf8(const uint16_t *utf16, size_t utf16_len, uint8_t *utf8, size_t utf8_len) {
|
||||
// TODO: Check for runover.
|
||||
(void)utf8_len;
|
||||
// Get the UTF-16 length out of the data itself.
|
||||
|
||||
for (size_t i = 0; i < utf16_len; i++) {
|
||||
uint16_t chr = utf16[i];
|
||||
if (chr < 0x80) {
|
||||
*utf8++ = chr & 0xff;
|
||||
} else if (chr < 0x800) {
|
||||
*utf8++ = (uint8_t)(0xC0 | (chr >> 6 & 0x1F));
|
||||
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
|
||||
} else {
|
||||
// TODO: Verify surrogate.
|
||||
*utf8++ = (uint8_t)(0xE0 | (chr >> 12 & 0x0F));
|
||||
*utf8++ = (uint8_t)(0x80 | (chr >> 6 & 0x3F));
|
||||
*utf8++ = (uint8_t)(0x80 | (chr >> 0 & 0x3F));
|
||||
}
|
||||
// TODO: Handle UTF-16 code points that take two entries.
|
||||
}
|
||||
}
|
||||
|
||||
// Count how many bytes a utf-16-le encoded string will take in utf-8.
|
||||
static int _count_utf8_bytes(const uint16_t *buf, size_t len) {
|
||||
size_t total_bytes = 0;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint16_t chr = buf[i];
|
||||
if (chr < 0x80) {
|
||||
total_bytes += 1;
|
||||
} else if (chr < 0x800) {
|
||||
total_bytes += 2;
|
||||
} else {
|
||||
total_bytes += 3;
|
||||
}
|
||||
// TODO: Handle UTF-16 code points that take two entries.
|
||||
}
|
||||
return total_bytes;
|
||||
}
|
||||
|
||||
static void print_utf16(uint16_t *temp_buf, size_t buf_len) {
|
||||
size_t utf16_len = ((temp_buf[0] & 0xff) - 2) / sizeof(uint16_t);
|
||||
size_t utf8_len = _count_utf8_bytes(temp_buf + 1, utf16_len);
|
||||
|
||||
_convert_utf16le_to_utf8(temp_buf + 1, utf16_len, (uint8_t *) temp_buf, sizeof(uint16_t) * buf_len);
|
||||
((uint8_t*) temp_buf)[utf8_len] = '\0';
|
||||
|
||||
Serial.printf((char*)temp_buf);
|
||||
}
|
||||
|
@ -0,0 +1,205 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
|
||||
/* This sketch demonstrates USB HID keyboard.
|
||||
* - PIN A0-A5 is used to send digit '0' to '5' respectively
|
||||
* (On the RP2040, pins D0-D5 used)
|
||||
* - LED and/or Neopixels will be used as Capslock indicator
|
||||
*/
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Single Report (no ID) descriptor
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_KEYBOARD()
|
||||
};
|
||||
|
||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||
// desc report, desc len, protocol, interval, use out endpoint
|
||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false);
|
||||
|
||||
//------------- Input Pins -------------//
|
||||
// Array of pins and its keycode.
|
||||
// Notes: these pins can be replaced by PIN_BUTTONn if defined in setup()
|
||||
#ifdef ARDUINO_ARCH_RP2040
|
||||
uint8_t pins[] = { D0, D1, D2, D3 };
|
||||
#else
|
||||
uint8_t pins[] = { A0, A1, A2, A3 };
|
||||
#endif
|
||||
|
||||
// number of pins
|
||||
uint8_t pincount = sizeof(pins)/sizeof(pins[0]);
|
||||
|
||||
// For keycode definition check out https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h
|
||||
uint8_t hidcode[] = { HID_KEY_ARROW_RIGHT, HID_KEY_ARROW_LEFT, HID_KEY_ARROW_DOWN, HID_KEY_ARROW_UP };
|
||||
|
||||
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY) || defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||
bool activeState = true;
|
||||
#else
|
||||
bool activeState = false;
|
||||
#endif
|
||||
|
||||
//------------- Neopixel -------------//
|
||||
// #define PIN_NEOPIXEL 8
|
||||
#ifdef PIN_NEOPIXEL
|
||||
|
||||
// How many NeoPixels are attached to the Arduino?
|
||||
// use on-board defined NEOPIXEL_NUM if existed
|
||||
#ifndef NEOPIXEL_NUM
|
||||
#define NEOPIXEL_NUM 10
|
||||
#endif
|
||||
|
||||
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NEOPIXEL_NUM, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
||||
TinyUSB_Device_Init(0);
|
||||
#endif
|
||||
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// usb_hid.setBootProtocol(HID_ITF_PROTOCOL_KEYBOARD);
|
||||
// usb_hid.setPollInterval(2);
|
||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
// usb_hid.setStringDescriptor("TinyUSB Keyboard");
|
||||
|
||||
// Set up output report (on control endpoint) for Capslock indicator
|
||||
usb_hid.setReportCallback(NULL, hid_report_callback);
|
||||
|
||||
usb_hid.begin();
|
||||
|
||||
// led pin
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
// neopixel if existed
|
||||
#ifdef PIN_NEOPIXEL
|
||||
pixels.begin();
|
||||
pixels.setBrightness(50);
|
||||
|
||||
#ifdef NEOPIXEL_POWER
|
||||
pinMode(NEOPIXEL_POWER, OUTPUT);
|
||||
digitalWrite(NEOPIXEL_POWER, NEOPIXEL_POWER_ON);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// overwrite input pin with PIN_BUTTONx
|
||||
#ifdef PIN_BUTTON1
|
||||
pins[0] = PIN_BUTTON1;
|
||||
#endif
|
||||
|
||||
#ifdef PIN_BUTTON2
|
||||
pins[1] = PIN_BUTTON2;
|
||||
#endif
|
||||
|
||||
#ifdef PIN_BUTTON3
|
||||
pins[2] = PIN_BUTTON3;
|
||||
#endif
|
||||
|
||||
#ifdef PIN_BUTTON4
|
||||
pins[3] = PIN_BUTTON4;
|
||||
#endif
|
||||
|
||||
// Set up pin as input
|
||||
for (uint8_t i=0; i<pincount; i++)
|
||||
{
|
||||
pinMode(pins[i], activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||
}
|
||||
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
// poll gpio once each 2 ms
|
||||
delay(2);
|
||||
|
||||
// used to avoid send multiple consecutive zero report for keyboard
|
||||
static bool keyPressedPreviously = false;
|
||||
|
||||
uint8_t count=0;
|
||||
uint8_t keycode[6] = { 0 };
|
||||
|
||||
// scan normal key and send report
|
||||
for(uint8_t i=0; i < pincount; i++)
|
||||
{
|
||||
if ( activeState == digitalRead(pins[i]) )
|
||||
{
|
||||
// if pin is active (low), add its hid code to key report
|
||||
keycode[count++] = hidcode[i];
|
||||
|
||||
// 6 is max keycode per report
|
||||
if (count == 6) break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( TinyUSBDevice.suspended() && count )
|
||||
{
|
||||
// Wake up host if we are in suspend mode
|
||||
// and REMOTE_WAKEUP feature is enabled by host
|
||||
TinyUSBDevice.remoteWakeup();
|
||||
}
|
||||
|
||||
// skip if hid is not ready e.g still transferring previous report
|
||||
if ( !usb_hid.ready() ) return;
|
||||
|
||||
if ( count )
|
||||
{
|
||||
// Send report if there is key pressed
|
||||
uint8_t const report_id = 0;
|
||||
uint8_t const modifier = 0;
|
||||
|
||||
keyPressedPreviously = true;
|
||||
usb_hid.keyboardReport(report_id, modifier, keycode);
|
||||
}else
|
||||
{
|
||||
// Send All-zero report to indicate there is no keys pressed
|
||||
// Most of the time, it is, though we don't need to send zero report
|
||||
// every loop(), only a key is pressed in previous loop()
|
||||
if ( keyPressedPreviously )
|
||||
{
|
||||
keyPressedPreviously = false;
|
||||
usb_hid.keyboardRelease(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Output report callback for LED indicator such as Caplocks
|
||||
void hid_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
|
||||
{
|
||||
(void) report_id;
|
||||
(void) bufsize;
|
||||
|
||||
// LED indicator is output report with only 1 byte length
|
||||
if ( report_type != HID_REPORT_TYPE_OUTPUT ) return;
|
||||
|
||||
// The LED bit map is as follows: (also defined by KEYBOARD_LED_* )
|
||||
// Kana (4) | Compose (3) | ScrollLock (2) | CapsLock (1) | Numlock (0)
|
||||
uint8_t ledIndicator = buffer[0];
|
||||
|
||||
// turn on LED if capslock is set
|
||||
digitalWrite(LED_BUILTIN, ledIndicator & KEYBOARD_LED_CAPSLOCK);
|
||||
|
||||
#ifdef PIN_NEOPIXEL
|
||||
pixels.fill(ledIndicator & KEYBOARD_LED_CAPSLOCK ? 0xff0000 : 0x000000);
|
||||
pixels.show();
|
||||
#endif
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
/* This sketch demonstrates USB HID mouse
|
||||
* Press button pin will move
|
||||
* - mouse toward bottom right of monitor
|
||||
*
|
||||
* Depending on the board, the button pin
|
||||
* and its active state (when pressed) are different
|
||||
*/
|
||||
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
||||
const int pin = 4; // Left Button
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||
const int pin = BUTTON_DOWN;
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined PIN_BUTTON1
|
||||
const int pin = PIN_BUTTON1;
|
||||
bool activeState = false;
|
||||
|
||||
#else
|
||||
const int pin = 12;
|
||||
bool activeState = false;
|
||||
#endif
|
||||
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Single Report (no ID) descriptor
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_MOUSE()
|
||||
};
|
||||
|
||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||
// desc report, desc len, protocol, interval, use out endpoint
|
||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_MOUSE, 2, false);
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
||||
TinyUSB_Device_Init(0);
|
||||
#endif
|
||||
|
||||
// Set up button, pullup opposite to active state
|
||||
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// usb_hid.setBootProtocol(HID_ITF_PROTOCOL_MOUSE);
|
||||
// usb_hid.setPollInterval(2);
|
||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
// usb_hid.setStringDescriptor("TinyUSB Mouse");
|
||||
|
||||
usb_hid.begin();
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
|
||||
Serial.println("Adafruit TinyUSB HID Mouse example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// poll gpio once each 10 ms
|
||||
delay(10);
|
||||
|
||||
// Whether button is pressed
|
||||
bool btn_pressed = (digitalRead(pin) == activeState);
|
||||
|
||||
// nothing to do if button is not pressed
|
||||
if (!btn_pressed) return;
|
||||
|
||||
// Remote wakeup
|
||||
if ( TinyUSBDevice.suspended() )
|
||||
{
|
||||
// Wake up host if we are in suspend mode
|
||||
// and REMOTE_WAKEUP feature is enabled by host
|
||||
TinyUSBDevice.remoteWakeup();
|
||||
}
|
||||
|
||||
if ( usb_hid.ready() )
|
||||
{
|
||||
uint8_t const report_id = 0; // no ID
|
||||
int8_t const delta = 5;
|
||||
usb_hid.mouseMove(report_id, delta, delta); // right + down
|
||||
}
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
/* This sketch demonstrates multiple report USB HID.
|
||||
* Press button pin will move
|
||||
* - mouse toward bottom right of monitor
|
||||
* - send 'a' key
|
||||
*
|
||||
* Depending on the board, the button pin
|
||||
* and its active state (when pressed) are different
|
||||
*/
|
||||
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
||||
const int pin = 4; // Left Button
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||
const int pin = BUTTON_DOWN;
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined PIN_BUTTON1
|
||||
const int pin = PIN_BUTTON1;
|
||||
bool activeState = false;
|
||||
|
||||
#else
|
||||
const int pin = 12;
|
||||
bool activeState = false;
|
||||
#endif
|
||||
|
||||
|
||||
// Report ID
|
||||
enum
|
||||
{
|
||||
RID_KEYBOARD = 1,
|
||||
RID_MOUSE,
|
||||
RID_CONSUMER_CONTROL, // Media, volume etc ..
|
||||
};
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD) ),
|
||||
TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(RID_MOUSE) ),
|
||||
TUD_HID_REPORT_DESC_CONSUMER( HID_REPORT_ID(RID_CONSUMER_CONTROL) )
|
||||
};
|
||||
|
||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||
// desc report, desc len, protocol, interval, use out endpoint
|
||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// usb_hid.setPollInterval(2);
|
||||
// usb_hid.setReportDescriptor();
|
||||
// usb_hid.setStringDescriptor("TinyUSB HID Composite");
|
||||
|
||||
usb_hid.begin();
|
||||
|
||||
// Set up button, pullup opposite to active state
|
||||
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
|
||||
Serial.println("Adafruit TinyUSB HID Composite example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// poll gpio once each 10 ms
|
||||
delay(10);
|
||||
|
||||
// Whether button is pressed
|
||||
bool btn_pressed = (digitalRead(pin) == activeState);
|
||||
|
||||
// Remote wakeup
|
||||
if ( TinyUSBDevice.suspended() && btn_pressed )
|
||||
{
|
||||
// Wake up host if we are in suspend mode
|
||||
// and REMOTE_WAKEUP feature is enabled by host
|
||||
TinyUSBDevice.remoteWakeup();
|
||||
}
|
||||
|
||||
/*------------- Mouse -------------*/
|
||||
if ( usb_hid.ready() && btn_pressed )
|
||||
{
|
||||
int8_t const delta = 5;
|
||||
usb_hid.mouseMove(RID_MOUSE, delta, delta); // right + down
|
||||
|
||||
// delay a bit before attempt to send keyboard report
|
||||
delay(10);
|
||||
}
|
||||
|
||||
/*------------- Keyboard -------------*/
|
||||
if ( usb_hid.ready() )
|
||||
{
|
||||
// use to send key release report
|
||||
static bool has_key = false;
|
||||
|
||||
if ( btn_pressed )
|
||||
{
|
||||
uint8_t keycode[6] = { 0 };
|
||||
keycode[0] = HID_KEY_A;
|
||||
|
||||
usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
|
||||
|
||||
has_key = true;
|
||||
}else
|
||||
{
|
||||
// send empty key report if previously has key pressed
|
||||
if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD);
|
||||
has_key = false;
|
||||
}
|
||||
|
||||
// delay a bit before attempt to send consumer report
|
||||
delay(10);
|
||||
}
|
||||
|
||||
/*------------- Consumer Control -------------*/
|
||||
if ( usb_hid.ready() )
|
||||
{
|
||||
// Consumer Control is used to control Media playback, Volume, Brightness etc ...
|
||||
// Consumer report is 2-byte containing the control code of the key
|
||||
// For list of control check out https://github.com/hathach/tinyusb/blob/master/src/class/hid/hid.h
|
||||
|
||||
// use to send consumer release report
|
||||
static bool has_consumer_key = false;
|
||||
|
||||
if ( btn_pressed )
|
||||
{
|
||||
// send volume down (0x00EA)
|
||||
usb_hid.sendReport16(RID_CONSUMER_CONTROL, HID_USAGE_CONSUMER_VOLUME_DECREMENT);
|
||||
has_consumer_key = true;
|
||||
}else
|
||||
{
|
||||
// release the consume key by sending zero (0x0000)
|
||||
if (has_consumer_key) usb_hid.sendReport16(RID_CONSUMER_CONTROL, 0);
|
||||
has_consumer_key = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
/* This sketch demonstrates USB HID Mouse and Keyboard with Joy Feather Wing.
|
||||
* - The analog stick move mouse cursor
|
||||
* - Button A, B, X, Y will send character a, b, x, y
|
||||
* - Any actions will wake up PC host if it is in suspended (standby) mode.
|
||||
*
|
||||
* Joy Feather Wing: https://www.adafruit.com/product/3632
|
||||
*
|
||||
* Following library is required
|
||||
* - Adafruit_seesaw
|
||||
*/
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
#include "Adafruit_seesaw.h"
|
||||
|
||||
#define BUTTON_A 6
|
||||
#define BUTTON_B 7
|
||||
#define BUTTON_Y 9
|
||||
#define BUTTON_X 10
|
||||
uint32_t button_mask = (1 << BUTTON_A) | (1 << BUTTON_B) |
|
||||
(1 << BUTTON_Y) | (1 << BUTTON_X);
|
||||
|
||||
Adafruit_seesaw ss;
|
||||
|
||||
// Report ID
|
||||
enum
|
||||
{
|
||||
RID_KEYBOARD = 1,
|
||||
RID_MOUSE
|
||||
};
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_KEYBOARD( HID_REPORT_ID(RID_KEYBOARD) ),
|
||||
TUD_HID_REPORT_DESC_MOUSE ( HID_REPORT_ID(RID_MOUSE) )
|
||||
};
|
||||
|
||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||
// desc report, desc len, protocol, interval, use out endpoint
|
||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
|
||||
|
||||
int last_x, last_y;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// usb_hid.setPollInterval(2);
|
||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
|
||||
usb_hid.begin();
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.println("Adafruit TinyUSB HID Mouse with Joy FeatherWing example");
|
||||
|
||||
if(!ss.begin(0x49)){
|
||||
Serial.println("ERROR! seesaw not found");
|
||||
while(1);
|
||||
} else {
|
||||
Serial.println("seesaw started");
|
||||
Serial.print("version: ");
|
||||
Serial.println(ss.getVersion(), HEX);
|
||||
}
|
||||
ss.pinModeBulk(button_mask, INPUT_PULLUP);
|
||||
ss.setGPIOInterrupts(button_mask, 1);
|
||||
|
||||
last_y = ss.analogRead(2);
|
||||
last_x = ss.analogRead(3);
|
||||
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// poll gpio once each 10 ms
|
||||
delay(10);
|
||||
|
||||
// If either analog stick or any buttons is pressed
|
||||
bool has_action = false;
|
||||
|
||||
/*------------- Mouse -------------*/
|
||||
int y = ss.analogRead(2);
|
||||
int x = ss.analogRead(3);
|
||||
|
||||
// reduce the delta by half to slow down the cursor move
|
||||
int dx = (x - last_x) / 2;
|
||||
int dy = (y - last_y) / 2;
|
||||
|
||||
if ( (abs(dx) > 3) || (abs(dy) > 3) )
|
||||
{
|
||||
has_action = true;
|
||||
|
||||
if ( usb_hid.ready() )
|
||||
{
|
||||
usb_hid.mouseMove(RID_MOUSE, dx, dy); // no ID: right + down
|
||||
|
||||
last_x = x;
|
||||
last_y = y;
|
||||
|
||||
// delay a bit before attempt to send keyboard report
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*------------- Keyboard -------------*/
|
||||
// button is active low, invert read value for convenience
|
||||
uint32_t buttons = ~ss.digitalReadBulk(button_mask);
|
||||
|
||||
if ( usb_hid.ready() )
|
||||
{
|
||||
// use to prevent sending multiple consecutive zero report
|
||||
static bool has_key = false;
|
||||
|
||||
if ( buttons & button_mask )
|
||||
{
|
||||
has_action = true;
|
||||
has_key = true;
|
||||
|
||||
uint8_t keycode[6] = { 0 };
|
||||
|
||||
if ( buttons & (1 << BUTTON_A) ) keycode[0] = HID_KEY_A;
|
||||
if ( buttons & (1 << BUTTON_B) ) keycode[0] = HID_KEY_B;
|
||||
if ( buttons & (1 << BUTTON_X) ) keycode[0] = HID_KEY_X;
|
||||
if ( buttons & (1 << BUTTON_Y) ) keycode[0] = HID_KEY_Y;
|
||||
|
||||
usb_hid.keyboardReport(RID_KEYBOARD, 0, keycode);
|
||||
}else
|
||||
{
|
||||
// send empty key report if previously has key pressed
|
||||
if (has_key) usb_hid.keyboardRelease(RID_KEYBOARD);
|
||||
has_key = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*------------- Remote Wakeup -------------*/
|
||||
// Remote wakeup if PC is suspended and we has user interaction with joy feather wing
|
||||
if ( has_action && TinyUSBDevice.suspended() )
|
||||
{
|
||||
// Wake up only works if REMOTE_WAKEUP feature is enable by host
|
||||
// Usually this is the case with Mouse/Keyboard device
|
||||
TinyUSBDevice.remoteWakeup();
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
/* This sketch demonstrates multiple USB HID interfaces. Pressing the button will
|
||||
* - mouse toward bottom right of monitor
|
||||
* - send 'a' key
|
||||
*
|
||||
* Depending on the board, the button pin
|
||||
* and its active state (when pressed) are different
|
||||
*/
|
||||
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
||||
const int pin = 4; // Left Button
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||
const int pin = BUTTON_DOWN;
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined PIN_BUTTON1
|
||||
const int pin = PIN_BUTTON1;
|
||||
bool activeState = false;
|
||||
|
||||
#elif defined PIN_BUTTON
|
||||
const int pin = PIN_BUTTON;
|
||||
bool activeState = false;
|
||||
|
||||
#else
|
||||
const int pin = 12;
|
||||
bool activeState = false;
|
||||
#endif
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
uint8_t const desc_keyboard_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_KEYBOARD()
|
||||
};
|
||||
|
||||
uint8_t const desc_mouse_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_MOUSE()
|
||||
};
|
||||
|
||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||
// desc report, desc len, protocol, interval, use out endpoint
|
||||
Adafruit_USBD_HID usb_keyboard(desc_keyboard_report, sizeof(desc_keyboard_report), HID_ITF_PROTOCOL_KEYBOARD, 2, false);
|
||||
Adafruit_USBD_HID usb_mouse(desc_mouse_report, sizeof(desc_mouse_report), HID_ITF_PROTOCOL_MOUSE, 2, false);
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// usb_keyboard.setPollInterval(2);
|
||||
// usb_keyboard.setReportDescriptor();
|
||||
// usb_keyboard.setStringDescriptor("TinyUSB HID Composite");
|
||||
|
||||
usb_keyboard.begin();
|
||||
usb_mouse.begin();
|
||||
|
||||
// Set up button, pullup opposite to active state
|
||||
pinMode(pin, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// wait until device mounted
|
||||
//while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
Serial.println("Adafruit TinyUSB HID Composite example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// poll gpio once each 10 ms
|
||||
delay(10);
|
||||
|
||||
// Whether button is pressed
|
||||
bool btn_pressed = (digitalRead(pin) == activeState);
|
||||
|
||||
// Remote wakeup
|
||||
if ( TinyUSBDevice.suspended() && btn_pressed )
|
||||
{
|
||||
// Wake up host if we are in suspend mode
|
||||
// and REMOTE_WAKEUP feature is enabled by host
|
||||
TinyUSBDevice.remoteWakeup();
|
||||
}
|
||||
|
||||
/*------------- Mouse -------------*/
|
||||
if (usb_mouse.ready() && btn_pressed )
|
||||
{
|
||||
int8_t const delta = 5;
|
||||
usb_mouse.mouseMove(0, delta, delta); // right + down
|
||||
}
|
||||
|
||||
/*------------- Keyboard -------------*/
|
||||
if ( usb_keyboard.ready() )
|
||||
{
|
||||
// use to send key release report
|
||||
static bool has_key = false;
|
||||
|
||||
if ( btn_pressed )
|
||||
{
|
||||
uint8_t keycode[6] = { 0 };
|
||||
keycode[0] = HID_KEY_A;
|
||||
|
||||
usb_keyboard.keyboardReport(0, 0, keycode);
|
||||
|
||||
has_key = true;
|
||||
}else
|
||||
{
|
||||
// send empty key report if previously has key pressed
|
||||
if (has_key) usb_keyboard.keyboardRelease(0);
|
||||
has_key = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,275 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2021 NeKuNeKo for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
/* This sketch demonstrates USB HID gamepad use.
|
||||
* This sketch is only valid on boards which have native USB support
|
||||
* and compatibility with Adafruit TinyUSB library.
|
||||
* For example SAMD21, SAMD51, nRF52840.
|
||||
*
|
||||
* Make sure you select the TinyUSB USB stack if you have a SAMD board.
|
||||
* You can test the gamepad on a Windows system by pressing WIN+R, writing Joy.cpl and pressing Enter.
|
||||
*/
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Single Report (no ID) descriptor
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_GAMEPAD()
|
||||
};
|
||||
|
||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||
// desc report, desc len, protocol, interval, use out endpoint
|
||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, false);
|
||||
|
||||
// Report payload defined in src/class/hid/hid.h
|
||||
// - For Gamepad Button Bit Mask see hid_gamepad_button_bm_t
|
||||
// - For Gamepad Hat Bit Mask see hid_gamepad_hat_t
|
||||
hid_gamepad_report_t gp;
|
||||
|
||||
void setup()
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
||||
TinyUSB_Device_Init(0);
|
||||
#endif
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// usb_hid.setPollInterval(2);
|
||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
|
||||
usb_hid.begin();
|
||||
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
|
||||
Serial.println("Adafruit TinyUSB HID Gamepad example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// // Remote wakeup
|
||||
// if ( TinyUSBDevice.suspended() && btn )
|
||||
// {
|
||||
// // Wake up host if we are in suspend mode
|
||||
// // and REMOTE_WAKEUP feature is enabled by host
|
||||
// TinyUSBDevice.remoteWakeup();
|
||||
// }
|
||||
|
||||
if ( !usb_hid.ready() ) return;
|
||||
|
||||
// Reset buttons
|
||||
Serial.println("No pressing buttons");
|
||||
gp.x = 0;
|
||||
gp.y = 0;
|
||||
gp.z = 0;
|
||||
gp.rz = 0;
|
||||
gp.rx = 0;
|
||||
gp.ry = 0;
|
||||
gp.hat = 0;
|
||||
gp.buttons = 0;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
|
||||
// Hat/DPAD UP
|
||||
Serial.println("Hat/DPAD UP");
|
||||
gp.hat = 1; // GAMEPAD_HAT_UP;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Hat/DPAD UP RIGHT
|
||||
Serial.println("Hat/DPAD UP RIGHT");
|
||||
gp.hat = 2; // GAMEPAD_HAT_UP_RIGHT;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Hat/DPAD RIGHT
|
||||
Serial.println("Hat/DPAD RIGHT");
|
||||
gp.hat = 3; // GAMEPAD_HAT_RIGHT;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Hat/DPAD DOWN RIGHT
|
||||
Serial.println("Hat/DPAD DOWN RIGHT");
|
||||
gp.hat = 4; // GAMEPAD_HAT_DOWN_RIGHT;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Hat/DPAD DOWN
|
||||
Serial.println("Hat/DPAD DOWN");
|
||||
gp.hat = 5; // GAMEPAD_HAT_DOWN;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Hat/DPAD DOWN LEFT
|
||||
Serial.println("Hat/DPAD DOWN LEFT");
|
||||
gp.hat = 6; // GAMEPAD_HAT_DOWN_LEFT;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Hat/DPAD LEFT
|
||||
Serial.println("Hat/DPAD LEFT");
|
||||
gp.hat = 7; // GAMEPAD_HAT_LEFT;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Hat/DPAD UP LEFT
|
||||
Serial.println("Hat/DPAD UP LEFT");
|
||||
gp.hat = 8; // GAMEPAD_HAT_UP_LEFT;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Hat/DPAD CENTER
|
||||
Serial.println("Hat/DPAD CENTER");
|
||||
gp.hat = 0; // GAMEPAD_HAT_CENTERED;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
|
||||
// Joystick 1 UP
|
||||
Serial.println("Joystick 1 UP");
|
||||
gp.x = 0;
|
||||
gp.y = -127;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Joystick 1 DOWN
|
||||
Serial.println("Joystick 1 DOWN");
|
||||
gp.x = 0;
|
||||
gp.y = 127;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Joystick 1 RIGHT
|
||||
Serial.println("Joystick 1 RIGHT");
|
||||
gp.x = 127;
|
||||
gp.y = 0;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Joystick 1 LEFT
|
||||
Serial.println("Joystick 1 LEFT");
|
||||
gp.x = -127;
|
||||
gp.y = 0;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Joystick 1 CENTER
|
||||
Serial.println("Joystick 1 CENTER");
|
||||
gp.x = 0;
|
||||
gp.y = 0;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
|
||||
// Joystick 2 UP
|
||||
Serial.println("Joystick 2 UP");
|
||||
gp.z = 0;
|
||||
gp.rz = 127;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Joystick 2 DOWN
|
||||
Serial.println("Joystick 2 DOWN");
|
||||
gp.z = 0;
|
||||
gp.rz = -127;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Joystick 2 RIGHT
|
||||
Serial.println("Joystick 2 RIGHT");
|
||||
gp.z = 127;
|
||||
gp.rz = 0;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Joystick 2 LEFT
|
||||
Serial.println("Joystick 2 LEFT");
|
||||
gp.z = -127;
|
||||
gp.rz = 0;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Joystick 2 CENTER
|
||||
Serial.println("Joystick 2 CENTER");
|
||||
gp.z = 0;
|
||||
gp.rz = 0;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
|
||||
// Analog Trigger 1 UP
|
||||
Serial.println("Analog Trigger 1 UP");
|
||||
gp.rx = 127;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Analog Trigger 1 DOWN
|
||||
Serial.println("Analog Trigger 1 DOWN");
|
||||
gp.rx = -127;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Analog Trigger 1 CENTER
|
||||
Serial.println("Analog Trigger 1 CENTER");
|
||||
gp.rx = 0;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
|
||||
// Analog Trigger 2 UP
|
||||
Serial.println("Analog Trigger 2 UP");
|
||||
gp.ry = 127;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Analog Trigger 2 DOWN
|
||||
Serial.println("Analog Trigger 2 DOWN");
|
||||
gp.ry = -127;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// Analog Trigger 2 CENTER
|
||||
Serial.println("Analog Trigger 2 CENTER");
|
||||
gp.ry = 0;
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
|
||||
// Test buttons (up to 32 buttons)
|
||||
for (int i=0; i<32; ++i)
|
||||
{
|
||||
Serial.print("Pressing button "); Serial.println(i);
|
||||
gp.buttons = (1U << i);
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
// Random touch
|
||||
Serial.println("Random touch");
|
||||
gp.x = random(-127, 128);
|
||||
gp.y = random(-127, 128);
|
||||
gp.z = random(-127, 128);
|
||||
gp.rz = random(-127, 128);
|
||||
gp.rx = random(-127, 128);
|
||||
gp.ry = random(-127, 128);
|
||||
gp.hat = random(0, 9);
|
||||
gp.buttons = random(0, 0xffff);
|
||||
usb_hid.sendReport(0, &gp, sizeof(gp));
|
||||
delay(2000);
|
||||
|
||||
// */
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
Instructions for node.js based example
|
||||
|
||||
===Setup===
|
||||
|
||||
1. Upload example code to your board
|
||||
2. Install node.js if you haven't already
|
||||
3. Run `npm install` to install the dependencies
|
||||
4. If this should fail on windows try installing the build tools via `npm i -g windows-build-tools`
|
||||
5. While the board is connected run `node hid_test.js`
|
||||
6. If this should fail make sure the VID and PID of your board is listed in boards.js
|
@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
"Adafruit Boards":[0x239A,0xFFFF],
|
||||
"TinyUSB example":[0xCAFE,0xFFFF]
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
/* This example demonstrate HID Generic raw Input & Output.
|
||||
* It will receive data from Host (In endpoint) and echo back (Out endpoint).
|
||||
* HID Report descriptor use vendor for usage page (using template TUD_HID_REPORT_DESC_GENERIC_INOUT)
|
||||
*
|
||||
* There are 2 ways to test the sketch
|
||||
* 1. Using nodejs
|
||||
* - Install nodejs and npm to your PC
|
||||
*
|
||||
* - Install excellent node-hid (https://github.com/node-hid/node-hid) by
|
||||
* $ npm install node-hid
|
||||
*
|
||||
* - Run provided hid test script
|
||||
* $ node hid_test.js
|
||||
*
|
||||
* 2. Using python
|
||||
* - Install `hid` package (https://pypi.org/project/hid/) by
|
||||
* $ pip install hid
|
||||
*
|
||||
* - hid package replies on hidapi (https://github.com/libusb/hidapi) for backend,
|
||||
* which already available in Linux. However on windows, you may need to download its dlls from their release page and
|
||||
* copy it over to folder where python is installed.
|
||||
*
|
||||
* - Run provided hid test script to send and receive data to this device.
|
||||
* $ python3 hid_test.py
|
||||
*/
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// HID report descriptor using TinyUSB's template
|
||||
// Generic In Out with 64 bytes report (max)
|
||||
uint8_t const desc_hid_report[] =
|
||||
{
|
||||
TUD_HID_REPORT_DESC_GENERIC_INOUT(64)
|
||||
};
|
||||
|
||||
// USB HID object. For ESP32 these values cannot be changed after this declaration
|
||||
// desc report, desc len, protocol, interval, use out endpoint
|
||||
Adafruit_USBD_HID usb_hid(desc_hid_report, sizeof(desc_hid_report), HID_ITF_PROTOCOL_NONE, 2, true);
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
||||
TinyUSB_Device_Init(0);
|
||||
#endif
|
||||
|
||||
// Notes: following commented-out functions has no affect on ESP32
|
||||
// usb_hid.enableOutEndpoint(true);
|
||||
// usb_hid.setPollInterval(2);
|
||||
// usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
|
||||
// usb_hid.setStringDescriptor("TinyUSB HID Generic");
|
||||
|
||||
usb_hid.setReportCallback(get_report_callback, set_report_callback);
|
||||
usb_hid.begin();
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
|
||||
Serial.println("Adafruit TinyUSB HID Generic In Out example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
// 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 get_report_callback (uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
|
||||
{
|
||||
// not used in this example
|
||||
(void) report_id;
|
||||
(void) report_type;
|
||||
(void) buffer;
|
||||
(void) reqlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Invoked when received SET_REPORT control request or
|
||||
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||
void set_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
|
||||
{
|
||||
// This example doesn't use multiple report and report ID
|
||||
(void) report_id;
|
||||
(void) report_type;
|
||||
|
||||
// echo back anything we received from host
|
||||
usb_hid.sendReport(0, buffer, bufsize);
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
// IMPORTANT: install the dependency via 'npm i node-hid' in the same location as the script
|
||||
// If the install fails on windows you may need to run 'npm i -g windows-build-tools' first to be able to compile native code needed for this library
|
||||
|
||||
var HID = require('node-hid');
|
||||
var os = require('os')
|
||||
// list of supported devices
|
||||
var boards = require('./boards.js')
|
||||
var devices = HID.devices();
|
||||
|
||||
// this will choose any device found in the boards.js file
|
||||
var deviceInfo = devices.find(anySupportedBoard);
|
||||
var reportLen = 64;
|
||||
|
||||
var message = "Hello World!"
|
||||
|
||||
// Turn our string into an array of integers e.g. 'ascii codes', though charCodeAt spits out UTF-16
|
||||
// This means if you have characters in your string that are not Latin-1 you will have to add additional logic for character codes above 255
|
||||
var messageBuffer = Array.from(message, function(c){return c.charCodeAt(0)});
|
||||
|
||||
// HIDAPI requires us to prepend a 0 for single hid report as dummy reportID
|
||||
messageBuffer.unshift(0)
|
||||
|
||||
// Some OSes expect that you always send a buffer that equals your report length
|
||||
// So lets fill up the rest of the buffer with zeros
|
||||
var paddingBuf = Array(reportLen-messageBuffer.length);
|
||||
paddingBuf.fill(0)
|
||||
messageBuffer = messageBuffer.concat(paddingBuf)
|
||||
|
||||
// check if we actually found a device and if so send our messageBuffer to it
|
||||
if( deviceInfo ) {
|
||||
console.log(deviceInfo)
|
||||
var device = new HID.HID( deviceInfo.path );
|
||||
|
||||
// register an event listener for data coming from the device
|
||||
device.on("data", function(data) {
|
||||
// Print what we get from the device
|
||||
console.log(data.toString('ascii'));
|
||||
});
|
||||
|
||||
// the same for any error that occur
|
||||
device.on("error", function(err) {console.log(err)});
|
||||
|
||||
// send our message to the device every 500ms
|
||||
setInterval(function () {
|
||||
device.write(messageBuffer);
|
||||
},500)
|
||||
}
|
||||
|
||||
|
||||
function anySupportedBoard(d) {
|
||||
|
||||
for (var key in boards) {
|
||||
if (boards.hasOwnProperty(key)) {
|
||||
if (isDevice(boards[key],d)) {
|
||||
console.log("Found " + d.product);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function isDevice(board,d){
|
||||
// product id 0xff is matches all
|
||||
return d.vendorId==board[0] && (d.productId==board[1] || board[1] == 0xFFFF);
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
# Install python3 HID package https://pypi.org/project/hid/
|
||||
import hid
|
||||
|
||||
# default is TinyUSB (0xcafe), Adafruit (0x239a), RaspberryPi (0x2e8a), Espressif (0x303a) VID
|
||||
USB_VID = (0xcafe, 0x239a, 0x2e8a, 0x303a)
|
||||
|
||||
print("VID list: " + ", ".join('%02x' % v for v in USB_VID))
|
||||
|
||||
for vid in USB_VID:
|
||||
for dict in hid.enumerate(vid):
|
||||
print(dict)
|
||||
dev = hid.Device(dict['vendor_id'], dict['product_id'])
|
||||
if dev:
|
||||
while True:
|
||||
# Get input from console and encode to UTF8 for array of chars.
|
||||
# hid generic inout is single report therefore by HIDAPI requirement
|
||||
# it must be preceded with 0x00 as dummy reportID
|
||||
str_out = b'\x00'
|
||||
str_out += input("Send text to HID Device : ").encode('utf-8')
|
||||
dev.write(str_out)
|
||||
str_in = dev.read(64)
|
||||
print("Received from HID Device:", str_in, '\n')
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "hid_example",
|
||||
"version": "1.0.0",
|
||||
"description": "Test application for hid_generic_inout example sketch",
|
||||
"main": "hid_test.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "Timon, Tod E. Kurt",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"node-hid": "^0.7.9"
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
// This sketch is enumerated as USB MIDI device with multiple ports
|
||||
// and how to set their name
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Adafruit_TinyUSB.h>
|
||||
#include <MIDI.h>
|
||||
|
||||
// USB MIDI object with 3 ports
|
||||
Adafruit_USBD_MIDI usb_midi(3);
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
||||
TinyUSB_Device_Init(0);
|
||||
#endif
|
||||
|
||||
// Set name for each cable, must be done before usb_midi.begin()
|
||||
usb_midi.setCableName(1, "Keyboard");
|
||||
usb_midi.setCableName(2, "Drum Pads");
|
||||
usb_midi.setCableName(3, "Lights");
|
||||
|
||||
usb_midi.begin();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
delay(1000);
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
delay(1000);
|
||||
}
|
@ -0,0 +1,427 @@
|
||||
//Circuit Playground PZ-1 Pizza Box DJ
|
||||
// by John Park
|
||||
// a.k.a. DJ Sternocleidomastoid
|
||||
// for Adafruit Industries
|
||||
// MIT License
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// MIDI controller for Traktor, Mixxx and other DJ software
|
||||
// Uses TinyUSB to send MIDI over USB
|
||||
//
|
||||
// MIDI controller command mapping must be set up in your DJ software, check
|
||||
// below for MIDI signal outputs
|
||||
//
|
||||
// For detail tutorial https://learn.adafruit.com/circuit-playground-pizza-box-dj-controller
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <Adafruit_CircuitPlayground.h>
|
||||
#include <Wire.h>
|
||||
#include <SPI.h>
|
||||
#include <Adafruit_TinyUSB.h>
|
||||
#include <MIDI.h>
|
||||
|
||||
// USB MIDI object
|
||||
Adafruit_USBD_MIDI usb_midi;
|
||||
|
||||
// Create a new instance of the Arduino MIDI Library,
|
||||
// and attach usb_midi as the transport.
|
||||
MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, usbMIDI);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//MIDI CC (change control) assignments
|
||||
const int CHANNEL = 14; //MIDI channel
|
||||
const int LEFT_BUTTON_CC = 4; //Play/Pause Deck A
|
||||
const int RIGHT_BUTTON_CC = 19; //MIDI CC for left button: FX 1 On
|
||||
const int CAP1_CONTROL = 1; //Select/Set+Store Hotcue 2 (1 is load point)
|
||||
const int CAP0_CONTROL = 0; //Left fader mixes Deck B volume down
|
||||
const int CAP2_CONTROL = 2; //Delete hotcue 2 point
|
||||
const int CAP3_CONTROL = 3; //Remix Trigger 6-1 or Loop Size /2
|
||||
const int CAP12_CONTROL = 12; //Right fader mixes Deck A volume down
|
||||
const int CAP6_CONTROL = 6; //Scratch (jog turn) Deck B
|
||||
const int CAP9_CONTROL = 9; //Play/Pause Deck B
|
||||
const int CAP10_CONTROL = 10; //Remix Trigger 6-4 or Loop Set 4 bar
|
||||
|
||||
int leftButtonState = 0;
|
||||
int rightButtonState = 0;
|
||||
int leftButtonLastState = 0;
|
||||
int rightButtonLastState = 0;
|
||||
int cap0State = 0;
|
||||
int cap0LastState = 0;
|
||||
int cap1State = 0;
|
||||
int cap1LastState = 0;
|
||||
int cap2State = 0;
|
||||
int cap2LastState = 0;
|
||||
int cap3State = 0;
|
||||
int cap3LastState = 0;
|
||||
int cap12State = 0;
|
||||
int cap12LastState = 0;
|
||||
int cap6State = 0;
|
||||
int cap6LastState = 0;
|
||||
int cap9State = 0;
|
||||
int cap9LastState = 0;
|
||||
int cap10State = 0;
|
||||
int cap10LastState = 0;
|
||||
bool cap1ON = false; //prevents off command from being spewed
|
||||
bool cap12ON = false; //prevents off command from being spewed
|
||||
bool cap6ON = false; //prevents off command from being spewed
|
||||
|
||||
const int CAPMIN = 25; //lowest value that's considered an intentional touch to minimize crosstalk
|
||||
const int CAPSLOP = 0; //value of capacitive pad variance that's considered noise
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//mic_meter code
|
||||
// To keep the display 'lively,' an upper and lower range of volume
|
||||
// levels are dynamically adjusted based on recent audio history, and
|
||||
// the graph is fit into this range.
|
||||
#define FRAMES 8
|
||||
uint16_t lvl[FRAMES], // Audio level for the prior #FRAMES frames
|
||||
avgLo = 6, // Audio volume lower end of range
|
||||
avgHi = 512, // Audio volume upper end of range
|
||||
sum = 256 * FRAMES; // Sum of lvl[] array
|
||||
uint8_t lvlIdx = 0; // Counter into lvl[] array
|
||||
int16_t peak = 0; // Falling dot shows recent max
|
||||
int8_t peakV = 0; // Velocity of peak dot
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void setup() {
|
||||
|
||||
usbMIDI.begin();
|
||||
Serial.begin(115200);
|
||||
|
||||
CircuitPlayground.begin();
|
||||
CircuitPlayground.setBrightness(30); //make brighter for performance, up to 255
|
||||
CircuitPlayground.clearPixels();
|
||||
for(uint8_t i=0; i<FRAMES; i++) lvl[i] = 256;
|
||||
|
||||
// Wait until device is enumerated properly before sending MIDI message
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// COLOR TABLES for animation ----------------------------------------------
|
||||
|
||||
const uint8_t PROGMEM
|
||||
reds[] = { 0x9A, 0x75, 0x00, 0x00, 0x00, 0x65, 0x84, 0x9A, 0xAD, 0xAD },
|
||||
greens[] = { 0x00, 0x00, 0x00, 0x87, 0xB1, 0x9E, 0x87, 0x66, 0x00, 0x00 },
|
||||
blues[] = { 0x95, 0xD5, 0xFF, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
gamma8[] = { // Gamma correction improves the appearance of midrange colors
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03,
|
||||
0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06,
|
||||
0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09,
|
||||
0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0E,
|
||||
0x0E, 0x0F, 0x0F, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
|
||||
0x14, 0x15, 0x15, 0x16, 0x16, 0x17, 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1B,
|
||||
0x1B, 0x1C, 0x1D, 0x1D, 0x1E, 0x1F, 0x1F, 0x20, 0x21, 0x22, 0x22, 0x23,
|
||||
0x24, 0x25, 0x26, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2A, 0x2B, 0x2C, 0x2D,
|
||||
0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
|
||||
0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x44, 0x45, 0x46,
|
||||
0x47, 0x48, 0x49, 0x4B, 0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x52, 0x54, 0x55,
|
||||
0x56, 0x58, 0x59, 0x5A, 0x5C, 0x5D, 0x5E, 0x60, 0x61, 0x63, 0x64, 0x66,
|
||||
0x67, 0x69, 0x6A, 0x6C, 0x6D, 0x6F, 0x70, 0x72, 0x73, 0x75, 0x77, 0x78,
|
||||
0x7A, 0x7C, 0x7D, 0x7F, 0x81, 0x82, 0x84, 0x86, 0x88, 0x89, 0x8B, 0x8D,
|
||||
0x8F, 0x91, 0x92, 0x94, 0x96, 0x98, 0x9A, 0x9C, 0x9E, 0xA0, 0xA2, 0xA4,
|
||||
0xA6, 0xA8, 0xAA, 0xAC, 0xAE, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC,
|
||||
0xBF, 0xC1, 0xC3, 0xC5, 0xC7, 0xCA, 0xCC, 0xCE, 0xD1, 0xD3, 0xD5, 0xD7,
|
||||
0xDA, 0xDC, 0xDF, 0xE1, 0xE3, 0xE6, 0xE8, 0xEB, 0xED, 0xF0, 0xF2, 0xF5,
|
||||
0xF7, 0xFA, 0xFC, 0xFF };
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void loop() {
|
||||
|
||||
//Sound activated lights
|
||||
uint8_t i, r, g, b;
|
||||
uint16_t minLvl, maxLvl, a, scaled;
|
||||
|
||||
a = CircuitPlayground.mic.peak(10); // 10 ms of audio
|
||||
sum -= lvl[lvlIdx];
|
||||
lvl[lvlIdx] = a;
|
||||
sum += a; // Sum of lvl[] array
|
||||
minLvl = maxLvl = lvl[0]; // Calc min, max of lvl[]...
|
||||
for(i=1; i<FRAMES; i++) {
|
||||
if(lvl[i] < minLvl) minLvl = lvl[i];
|
||||
else if(lvl[i] > maxLvl) maxLvl = lvl[i];
|
||||
}
|
||||
|
||||
// Keep some minimum distance between min & max levels,
|
||||
// else the display gets "jumpy."
|
||||
if((maxLvl - minLvl) < 40) {
|
||||
maxLvl = (minLvl < (512-40)) ? minLvl + 40 : 512;
|
||||
}
|
||||
avgLo = (avgLo * 7 + minLvl + 2) / 8; // Dampen min/max levels
|
||||
avgHi = (maxLvl >= avgHi) ? // (fake rolling averages)
|
||||
(avgHi * 3 + maxLvl + 1) / 4 : // Fast rise
|
||||
(avgHi * 31 + maxLvl + 8) / 32; // Slow decay
|
||||
|
||||
a = sum / FRAMES; // Average of lvl[] array
|
||||
if(a <= avgLo) { // Below min?
|
||||
scaled = 0; // Bargraph = zero
|
||||
} else { // Else scale to fixed-point coordspace 0-2560
|
||||
scaled = 2560L * (a - avgLo) / (avgHi - avgLo);
|
||||
if(scaled > 2560) scaled = 2560;
|
||||
}
|
||||
if(scaled >= peak) { // New peak
|
||||
peakV = (scaled - peak) / 4; // Give it an upward nudge
|
||||
peak = scaled;
|
||||
}
|
||||
|
||||
uint8_t whole = scaled / 256, // Full-brightness pixels (0-10)
|
||||
frac = scaled & 255; // Brightness of fractional pixel
|
||||
int whole2 = peak / 256, // Index of peak pixel
|
||||
frac2 = peak & 255; // Between-pixels position of peak
|
||||
uint16_t a1, a2; // Scaling factors for color blending
|
||||
|
||||
for(i=0; i<10; i++) { // For each NeoPixel...
|
||||
if(i <= whole) { // In currently-lit area?
|
||||
r = pgm_read_byte(&reds[i]), // Look up pixel color
|
||||
g = pgm_read_byte(&greens[i]),
|
||||
b = pgm_read_byte(&blues[i]);
|
||||
if(i == whole) { // Fraction pixel at top of range?
|
||||
a1 = (uint16_t)frac + 1; // Fade toward black
|
||||
r = (r * a1) >> 8;
|
||||
g = (g * a1) >> 8;
|
||||
b = (b * a1) >> 8;
|
||||
}
|
||||
} else {
|
||||
r = g = b = 0; // In unlit area
|
||||
}
|
||||
// Composite the peak pixel atop whatever else is happening...
|
||||
if(i == whole2) { // Peak pixel?
|
||||
a1 = 256 - frac2; // Existing pixel blend factor 1-256
|
||||
a2 = frac2 + 1; // Peak pixel blend factor 1-256
|
||||
r = ((r * a1) + (0x84 * a2)) >> 8; // Will
|
||||
g = ((g * a1) + (0x87 * a2)) >> 8; // it
|
||||
b = ((b * a1) + (0xC3 * a2)) >> 8; // blend?
|
||||
} else if(i == (whole2-1)) { // Just below peak pixel
|
||||
a1 = frac2 + 1; // Opposite blend ratios to above,
|
||||
a2 = 256 - frac2; // but same idea
|
||||
r = ((r * a1) + (0x84 * a2)) >> 8;
|
||||
g = ((g * a1) + (0x87 * a2)) >> 8;
|
||||
b = ((b * a1) + (0xC3 * a2)) >> 8;
|
||||
}
|
||||
CircuitPlayground.strip.setPixelColor(i,
|
||||
pgm_read_byte(&gamma8[r]),
|
||||
pgm_read_byte(&gamma8[g]),
|
||||
pgm_read_byte(&gamma8[b]));
|
||||
}
|
||||
CircuitPlayground.strip.show();
|
||||
|
||||
peak += peakV;
|
||||
if(peak <= 0) {
|
||||
peak = 0;
|
||||
peakV = 0;
|
||||
} else if(peakV >= -126) {
|
||||
peakV -= 2;
|
||||
}
|
||||
|
||||
if(++lvlIdx >= FRAMES) lvlIdx = 0;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//BUTTONS
|
||||
//
|
||||
//read the buttons
|
||||
leftButtonState = (CircuitPlayground.leftButton());
|
||||
//not pressed = 0, pressed = 1
|
||||
rightButtonState = (CircuitPlayground.rightButton());
|
||||
|
||||
//Left Button
|
||||
//compare current button states to previous button states
|
||||
if(leftButtonState != leftButtonLastState){ //the state has changed
|
||||
if(leftButtonState == 1){ //went from off to on, it's pressed
|
||||
usbMIDI.sendControlChange(LEFT_BUTTON_CC, 1, CHANNEL); //send MIDI note ON command
|
||||
CircuitPlayground.redLED(HIGH); //turn on the red LED
|
||||
}
|
||||
else{ //the button went from on to off, it isn't pressed
|
||||
usbMIDI.sendControlChange(LEFT_BUTTON_CC, 0, CHANNEL); //send MIDI note OFF
|
||||
CircuitPlayground.redLED(LOW); //turn off the red LED
|
||||
}
|
||||
leftButtonLastState = leftButtonState; //toggle
|
||||
}
|
||||
|
||||
|
||||
//Right Button
|
||||
if(rightButtonState != rightButtonLastState){
|
||||
if(rightButtonState == 1){
|
||||
usbMIDI.sendControlChange(RIGHT_BUTTON_CC, 1, CHANNEL);
|
||||
CircuitPlayground.redLED(HIGH);
|
||||
}
|
||||
else{
|
||||
usbMIDI.sendControlChange(RIGHT_BUTTON_CC, 0, CHANNEL);
|
||||
CircuitPlayground.redLED(LOW);
|
||||
}
|
||||
rightButtonLastState = rightButtonState;
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//Cap sense pads
|
||||
//
|
||||
//read the capacative pads
|
||||
int cap1 = CircuitPlayground.readCap(1);
|
||||
int cap0 = CircuitPlayground.readCap(0);
|
||||
int cap2 = CircuitPlayground.readCap(2);
|
||||
int cap3 = CircuitPlayground.readCap(3);
|
||||
int cap12 = CircuitPlayground.readCap(12);
|
||||
int cap6 = CircuitPlayground.readCap(6);
|
||||
int cap9 = CircuitPlayground.readCap(9);
|
||||
int cap10 = CircuitPlayground.readCap(10);
|
||||
|
||||
//cap1 Crossfader Deck B
|
||||
|
||||
if(cap1 > CAPMIN){
|
||||
cap1State=1;
|
||||
}
|
||||
else{
|
||||
cap1State=0;
|
||||
}
|
||||
if(cap1State != cap1LastState){
|
||||
if(cap1State==1){
|
||||
usbMIDI.sendControlChange(CAP1_CONTROL, 127, CHANNEL);
|
||||
CircuitPlayground.redLED(HIGH);
|
||||
}
|
||||
else {
|
||||
usbMIDI.sendControlChange(CAP1_CONTROL, 0, CHANNEL);
|
||||
CircuitPlayground.redLED(LOW);
|
||||
}
|
||||
cap1LastState = cap1State;
|
||||
}
|
||||
|
||||
//cap0
|
||||
if(cap0 > CAPMIN){
|
||||
cap0State=1;
|
||||
}
|
||||
else{
|
||||
cap0State=0;
|
||||
}
|
||||
if(cap0State != cap0LastState){
|
||||
if(cap0State==1){
|
||||
usbMIDI.sendControlChange(CAP0_CONTROL, 1, CHANNEL);
|
||||
CircuitPlayground.redLED(HIGH);
|
||||
}
|
||||
else {
|
||||
usbMIDI.sendControlChange(CAP0_CONTROL, 0, CHANNEL);
|
||||
CircuitPlayground.redLED(LOW);
|
||||
}
|
||||
cap0LastState = cap0State;
|
||||
}
|
||||
|
||||
//cap2
|
||||
if(cap2 > CAPMIN){
|
||||
cap2State=1;
|
||||
}
|
||||
else{
|
||||
cap2State=0;
|
||||
}
|
||||
if(cap2State != cap2LastState){
|
||||
if(cap2State==1){
|
||||
usbMIDI.sendControlChange(CAP2_CONTROL, 1, CHANNEL);
|
||||
CircuitPlayground.redLED(HIGH);
|
||||
}
|
||||
else {
|
||||
usbMIDI.sendControlChange(CAP2_CONTROL, 0, CHANNEL);
|
||||
CircuitPlayground.redLED(LOW);
|
||||
}
|
||||
cap2LastState = cap2State;
|
||||
}
|
||||
|
||||
//cap3
|
||||
if(cap3 > CAPMIN){
|
||||
cap3State=1;
|
||||
}
|
||||
else{
|
||||
cap3State=0;
|
||||
}
|
||||
if(cap3State != cap3LastState){
|
||||
if(cap3State==1){
|
||||
usbMIDI.sendControlChange(CAP3_CONTROL, 1, CHANNEL);
|
||||
CircuitPlayground.redLED(HIGH);
|
||||
}
|
||||
else {
|
||||
usbMIDI.sendControlChange(CAP3_CONTROL, 0, CHANNEL);
|
||||
CircuitPlayground.redLED(LOW);
|
||||
}
|
||||
cap3LastState = cap3State;
|
||||
}
|
||||
|
||||
//cap12 Crossfader Deck B
|
||||
|
||||
if(cap12 > CAPMIN){
|
||||
cap12State=1;
|
||||
}
|
||||
else{
|
||||
cap12State=0;
|
||||
}
|
||||
if(cap12State != cap12LastState){
|
||||
if(cap12State==1){
|
||||
usbMIDI.sendControlChange(CAP12_CONTROL, 127, CHANNEL);
|
||||
CircuitPlayground.redLED(HIGH);
|
||||
}
|
||||
else {
|
||||
usbMIDI.sendControlChange(CAP12_CONTROL, 0, CHANNEL);
|
||||
CircuitPlayground.redLED(LOW);
|
||||
}
|
||||
cap12LastState = cap12State;
|
||||
}
|
||||
|
||||
//cap6
|
||||
if (cap6>CAPMIN){
|
||||
int cap6NewVal = map(CircuitPlayground.readCap(6),0,200,0,127);
|
||||
if (abs(cap6 - cap6NewVal>CAPSLOP)) {
|
||||
cap6 = cap6NewVal;
|
||||
usbMIDI.sendControlChange(CAP6_CONTROL, cap6, CHANNEL);
|
||||
CircuitPlayground.redLED(HIGH);
|
||||
cap6ON = true;
|
||||
}
|
||||
else{
|
||||
if (cap6ON==true){
|
||||
usbMIDI.sendControlChange(CAP6_CONTROL, 0, CHANNEL); //send a 0
|
||||
CircuitPlayground.redLED(LOW);
|
||||
cap6ON=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//cap9
|
||||
if(cap9 > CAPMIN){
|
||||
cap9State=1;
|
||||
}
|
||||
else{
|
||||
cap9State=0;
|
||||
}
|
||||
if(cap9State != cap9LastState){
|
||||
if(cap9State==1){
|
||||
usbMIDI.sendControlChange(CAP9_CONTROL, 1, CHANNEL);
|
||||
CircuitPlayground.redLED(HIGH);
|
||||
}
|
||||
else {
|
||||
usbMIDI.sendControlChange(CAP9_CONTROL, 0, CHANNEL);
|
||||
CircuitPlayground.redLED(LOW);
|
||||
}
|
||||
cap9LastState = cap9State;
|
||||
}
|
||||
|
||||
//cap10
|
||||
if(cap10 > CAPMIN){
|
||||
cap10State=1;
|
||||
}
|
||||
else{
|
||||
cap10State=0;
|
||||
}
|
||||
if(cap10State != cap10LastState){
|
||||
if(cap10State==1){
|
||||
usbMIDI.sendControlChange(CAP10_CONTROL, 1, CHANNEL);
|
||||
CircuitPlayground.redLED(HIGH);
|
||||
}
|
||||
else {
|
||||
usbMIDI.sendControlChange(CAP10_CONTROL, 0, CHANNEL);
|
||||
CircuitPlayground.redLED(LOW);
|
||||
}
|
||||
cap10LastState = cap10State;
|
||||
}
|
||||
|
||||
// MIDI Controllers should discard incoming MIDI messages.
|
||||
while (usbMIDI.read()) {
|
||||
}
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
/* This sketch is enumerated as USB MIDI device.
|
||||
* Following library is required
|
||||
* - MIDI Library by Forty Seven Effects
|
||||
* https://github.com/FortySevenEffects/arduino_midi_library
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Adafruit_TinyUSB.h>
|
||||
#include <MIDI.h>
|
||||
|
||||
// USB MIDI object
|
||||
Adafruit_USBD_MIDI usb_midi;
|
||||
|
||||
// Create a new instance of the Arduino MIDI Library,
|
||||
// and attach usb_midi as the transport.
|
||||
MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MIDI);
|
||||
|
||||
// Variable that holds the current position in the sequence.
|
||||
uint32_t position = 0;
|
||||
|
||||
// Store example melody as an array of note values
|
||||
byte note_sequence[] = {
|
||||
74,78,81,86,90,93,98,102,57,61,66,69,73,78,81,85,88,92,97,100,97,92,88,85,81,78,
|
||||
74,69,66,62,57,62,66,69,74,78,81,86,90,93,97,102,97,93,90,85,81,78,73,68,64,61,
|
||||
56,61,64,68,74,78,81,86,90,93,98,102
|
||||
};
|
||||
|
||||
void setup()
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
||||
TinyUSB_Device_Init(0);
|
||||
#endif
|
||||
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
//usb_midi.setStringDescriptor("TinyUSB MIDI");
|
||||
|
||||
// Initialize MIDI, and listen to all MIDI channels
|
||||
// This will also call usb_midi's begin()
|
||||
MIDI.begin(MIDI_CHANNEL_OMNI);
|
||||
|
||||
// Attach the handleNoteOn function to the MIDI Library. It will
|
||||
// be called whenever the Bluefruit receives MIDI Note On messages.
|
||||
MIDI.setHandleNoteOn(handleNoteOn);
|
||||
|
||||
// Do the same for MIDI Note Off messages.
|
||||
MIDI.setHandleNoteOff(handleNoteOff);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
static uint32_t start_ms = 0;
|
||||
if ( millis() - start_ms > 266 )
|
||||
{
|
||||
start_ms += 266;
|
||||
|
||||
// Setup variables for the current and previous
|
||||
// positions in the note sequence.
|
||||
int previous = position - 1;
|
||||
|
||||
// If we currently are at position 0, set the
|
||||
// previous position to the last note in the sequence.
|
||||
if (previous < 0) {
|
||||
previous = sizeof(note_sequence) - 1;
|
||||
}
|
||||
|
||||
// Send Note On for current position at full velocity (127) on channel 1.
|
||||
MIDI.sendNoteOn(note_sequence[position], 127, 1);
|
||||
|
||||
// Send Note Off for previous note.
|
||||
MIDI.sendNoteOff(note_sequence[previous], 0, 1);
|
||||
|
||||
// Increment position
|
||||
position++;
|
||||
|
||||
// If we are at the end of the sequence, start over.
|
||||
if (position >= sizeof(note_sequence)) {
|
||||
position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// read any new MIDI messages
|
||||
MIDI.read();
|
||||
}
|
||||
|
||||
void handleNoteOn(byte channel, byte pitch, byte velocity)
|
||||
{
|
||||
// Log when a note is pressed.
|
||||
Serial.print("Note on: channel = ");
|
||||
Serial.print(channel);
|
||||
|
||||
Serial.print(" pitch = ");
|
||||
Serial.print(pitch);
|
||||
|
||||
Serial.print(" velocity = ");
|
||||
Serial.println(velocity);
|
||||
}
|
||||
|
||||
void handleNoteOff(byte channel, byte pitch, byte velocity)
|
||||
{
|
||||
// Log when a note is released.
|
||||
Serial.print("Note off: channel = ");
|
||||
Serial.print(channel);
|
||||
|
||||
Serial.print(" pitch = ");
|
||||
Serial.print(pitch);
|
||||
|
||||
Serial.print(" velocity = ");
|
||||
Serial.println(velocity);
|
||||
}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
@ -0,0 +1 @@
|
||||
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('8 H(t){K 21.1Y(t)}8 9(a,b){a.1S(b)}8 1O(b,t,w,h,l,m,d,f,j){6(Q b==="S"||!b)K 1f;6(Q d==="S"||!d)d=1P;w=(w>1b)?w:1b;h=(h<1N)?1N:h;4 k=1M 1L();4 n="V";4 o=(Q f==="S"&&f)?"1J":f;4 p="#1I";4 q=(Q j==="S"&&j)?1f:j;4 r=m;4 s=0;4 u=1;4 x=l;4 y=h+20;b.7.1H="1G";b.7.1F="#1s";b.7.1c="12 11 "+p;b.7.1D="N";b.7.1C="N";b.7.P=(w+2)+"1B";4 g=H("1a");g.7.1c="12 11 "+p;g.7.1z="N";g.P=w;g.1w=y;4 c=g.1v("2d");4 z=H("1j");z.M="1u: ";z.7.1m="N";4 A=H("1p");A.1i="1r";A.1e=3;A.I=u;A.1h=8(e){u=A.I};4 B=H("T");B.M="-";B.U=8(e){6(u>1)u--;A.I=u};4 C=H("T");C.M="+";C.U=8(e){u++;A.I=1n(u)};4 D=H("1j");D.M="1Q: ";D.7.1m="N";4 E=H("1p");E.1i="1r";E.1e=5;E.I=x;E.1h=8(e){x=1n(E.I)};4 F=H("T");F.M="-";F.U=8(e){6(x>l)x--;E.I=x};4 G=H("T");G.M="+";G.U=8(e){6(x<m)x++;E.I=x};9(b,z);9(b,B);9(b,A);9(b,C);9(b,D);9(b,F);9(b,E);9(b,G);9(b,H("1E"));9(b,g);8 R(v){6(v<=x)K 0;6(v>(((m-l)/u)+x))K h;K 1d.1o((v-x)*(h/((m-l)/u)))}g.1x=8(v){6(q)v=q(v);k.1y(v);6(v<r)r=v;6(v>s)s=v;6(k.L>w)k.1A();c.1a.P=w;c.1g=1;c.17=2;c.Y="V";c.O=p;c.J(0,0,w,20);c.O=o;c.X="1q Z";4 a=t+": "+(k[k.L-1])+" | 1U: "+r+" | 23: "+s;c.W(a,5,15);c.O=n;c.J(0,20,w,y);c.1K=o;18(4 i=0;i<k.L;i++){6(d){c.13(i,y);c.14(i,y-R(k[i]));c.16();1R}6(i===0){c.13(0,y-R(k[0]));c.14(0,y-R(k[0]));c.16()}19{c.13((i-1),y-R(k[i-1]));c.14(i,y-R(k[i]));c.16()}}c.O=o;c.X="1T Z";c.W(x,2,y-5);c.W(1d.1o((((m-l)/u)+x)*10)/10,2,1V)};K g}8 1W(j,t,w,h,m,k){6(Q j==="S"||!j)K 1f;w=(w>1b)?w:1b;h=(h<20)?20:h;4 l=1M 1L();4 n="V";4 o=(Q k==="S"&&k)?"1X":k;4 q="#1I";4 r=1;4 u=h+20;j.7.1H="1G";j.7.1F="#1s";j.7.1c="12 11 "+q;j.7.1D="N";j.7.1C="N";j.7.P=(w+2)+"1B";4 g=H("1a");g.7.1c="12 11 "+q;g.7.1z="N";g.P=w;g.1w=u;4 c=g.1v("2d");4 x=H("1j");x.M="1u: ";x.7.1m="N";4 y=H("1p");y.1i="1r";y.1e=3;y.I=r;y.1h=8(e){r=y.I};4 z=H("T");z.M="-";z.U=8(e){6(r>1)r--;y.I=r};4 A=H("T");A.M="+";A.U=8(e){r++;y.I=1n(r)};9(j,x);9(j,z);9(j,y);9(j,A);9(j,H("1E"));9(j,g);8 1l(p){4 a=1d.1Z(((h-((m.L-1)*2))/m.L));4 s=(p*2)+(p*a);K[s,s+a]}8 1k(i,p){K((l[i]&(1<<m[p]))!==0)}4 B=["22","1J","#1t","#24","25","26","27","#28","#29","#2a","#2b","#2c","#2e","#2f","#1t","#2g","#2h"];g.1x=8(v){l.1y(v);6(l.L>w)l.1A();c.1a.P=w;c.1g=1;c.17=2;c.Y="V";c.O=q;c.J(0,0,w,20);c.O=o;c.X="1q Z";c.W(t,5,15);c.O=n;c.J(0,20,w,u);c.1K=q;c.1g=1;c.17=0;c.Y="";18(4 p=0;p<m.L;p++){4 a=1l(p);c.13(0,20+a[1]+1);c.14(w,20+a[1]+1);c.16()}c.17=2;c.X="1q Z";4 b=1d.1o(w/r);4 d=w-b-(w-l.L);6(d<0)d=0;18(4 i=d;i<l.L;i++){18(4 p=0;p<m.L;p++){4 a=1l(p);4 e=1k(i,p);c.O=B[p];c.Y="V";c.X="2i Z";c.W(""+m[p],2,a[0]+2j);c.Y=B[p];4 f=((i-d)*r)-(r/2);4 g=1k(i-1,p);6(i&&e!=g){6(!g){c.J(f,20+(a[1]-2),r/2,2);c.J(f+(r/2),20+a[0],2,a[1]-a[0]);c.J(f+(r/2),20+a[0],r/2,2)}19{c.J(f,20+a[0],r/2,2);c.J(f+(r/2),20+a[0],2,a[1]-a[0]);c.J(f+(r/2),20+(a[1]-2),r/2,2)}}19 6(e){c.J(f,20+a[0],r,2)}19{c.J(f,20+(a[1]-2),r,2)}}}};K g}',62,144,'||||var||if|style|function|ac||||||||||||||||||||||||||||||||||ce|value|fillRect|return|length|innerText|5px|fillStyle|width|typeof|scv|undefined|button|onclick|black|fillText|font|shadowColor|Verdana||solid|1px|moveTo|lineTo||stroke|shadowBlur|for|else|canvas|360|border|Math|size|null|lineWidth|onchange|type|span|gact|gpos|paddingLeft|parseInt|round|input|14px|text|eee|FF4500|Scale|getContext|height|add|push|marginTop|shift|px|margin|padding|br|backgroundColor|block|display|444|yellow|strokeStyle|Array|new|100|createGraph|false|Offset|continue|appendChild|10px|Min|30|createDigiGraph|pink|createElement|floor||document|aqua|Max|00FF7F|orange|cyan|magenta|7FFF00|FAF0E6|00CED1|FFD700|EE82EE||00FF00|00BFFF|EEE8AA|FF1493|12px|32'.split('|'),0,{}))
|
@ -0,0 +1,97 @@
|
||||
<!--
|
||||
FSWebServer - Example Index Page
|
||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||
This file is part of the WebServer library for Arduino environment.
|
||||
|
||||
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
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<title>ESP Monitor</title>
|
||||
<script type="text/javascript" src="graphs.js"></script>
|
||||
<script type="text/javascript">
|
||||
var heap,temp,digi;
|
||||
var reloadPeriod = 1000;
|
||||
var running = false;
|
||||
|
||||
function loadValues(){
|
||||
if(!running) return;
|
||||
var xh = new XMLHttpRequest();
|
||||
xh.onreadystatechange = function(){
|
||||
if (xh.readyState == 4){
|
||||
if(xh.status == 200) {
|
||||
var res = JSON.parse(xh.responseText);
|
||||
heap.add(res.heap);
|
||||
temp.add(res.analog);
|
||||
digi.add(res.gpio);
|
||||
if(running) setTimeout(loadValues, reloadPeriod);
|
||||
} else running = false;
|
||||
}
|
||||
};
|
||||
xh.open("GET", "/all", true);
|
||||
xh.send(null);
|
||||
};
|
||||
|
||||
function run(){
|
||||
if(!running){
|
||||
running = true;
|
||||
loadValues();
|
||||
}
|
||||
}
|
||||
|
||||
function onBodyLoad(){
|
||||
var refreshInput = document.getElementById("refresh-rate");
|
||||
refreshInput.value = reloadPeriod;
|
||||
refreshInput.onchange = function(e){
|
||||
var value = parseInt(e.target.value);
|
||||
reloadPeriod = (value > 0)?value:0;
|
||||
e.target.value = reloadPeriod;
|
||||
}
|
||||
var stopButton = document.getElementById("stop-button");
|
||||
stopButton.onclick = function(e){
|
||||
running = false;
|
||||
}
|
||||
var startButton = document.getElementById("start-button");
|
||||
startButton.onclick = function(e){
|
||||
run();
|
||||
}
|
||||
|
||||
// Example with 10K thermistor
|
||||
//function calcThermistor(v) {
|
||||
// var t = Math.log(((10230000 / v) - 10000));
|
||||
// t = (1/(0.001129148+(0.000234125*t)+(0.0000000876741*t*t*t)))-273.15;
|
||||
// return (t>120)?0:Math.round(t*10)/10;
|
||||
//}
|
||||
//temp = createGraph(document.getElementById("analog"), "Temperature", 100, 128, 10, 40, false, "cyan", calcThermistor);
|
||||
|
||||
temp = createGraph(document.getElementById("analog"), "Analog Input", 100, 128, 0, 1023, false, "cyan");
|
||||
heap = createGraph(document.getElementById("heap"), "Current Heap", 100, 125, 0, 30000, true, "orange");
|
||||
digi = createDigiGraph(document.getElementById("digital"), "GPIO", 100, 146, [0, 4, 5, 16], "gold");
|
||||
run();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body id="index" style="margin:0; padding:0;" onload="onBodyLoad()">
|
||||
<div id="controls" style="display: block; border: 1px solid rgb(68, 68, 68); padding: 5px; margin: 5px; width: 362px; background-color: rgb(238, 238, 238);">
|
||||
<label>Period (ms):</label>
|
||||
<input type="number" id="refresh-rate"/>
|
||||
<input type="button" id="start-button" value="Start"/>
|
||||
<input type="button" id="stop-button" value="Stop"/>
|
||||
</div>
|
||||
<div id="heap"></div>
|
||||
<div id="analog"></div>
|
||||
<div id="digital"></div>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,437 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
/* This example is based on "arduino-esp32/libraries/WebServer/examples/FSBrowser"
|
||||
* to expose on-board external Flash as USB Mass Storage and webserver. Both interfaces
|
||||
* can make changes to file system
|
||||
*
|
||||
* How to run this example
|
||||
* 1. Create secrets.h and define your "SECRET_SSID" and "SECRET_PASSWORD"
|
||||
* 2. Compile and upload this sketch
|
||||
* 3. Your ESP will be expose as MassStorage device.
|
||||
* 4. If it is your first run (otherwise skip this step):
|
||||
* - you may need to format the drive as FAT. Note: If your PC failed to format, you could format
|
||||
* it using follow sketch "https://github.com/adafruit/Adafruit_SPIFlash/tree/master/examples/SdFat_format"
|
||||
* - Copy all files in 'data/' folder of this example to the root directory of the MassStorage disk drive
|
||||
* 5. When prompted, open http://esp32fs.local/edit to access the file browser
|
||||
* 6. Modify/Update USB drive then refresh your browser to see if the change is updated
|
||||
* 7. Upload/Edit a file using web browser then see if the USB Drive is updated. Note: the usb drive could
|
||||
* briefly disappear and reappear to force PC to refresh its cache
|
||||
*
|
||||
* NOTE: Following library is required
|
||||
* - Adafruit_SPIFlash https://github.com/adafruit/Adafruit_SPIFlash
|
||||
* - SdFat https://github.com/adafruit/SdFat
|
||||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat.h"
|
||||
#include "Adafruit_SPIFlash.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <WebServer.h>
|
||||
#include <ESPmDNS.h>
|
||||
|
||||
// check if secrets.h is includable, if not please
|
||||
// create one with SSDI & PASSWORD macro as following example:
|
||||
#if __has_include("secrets.h")
|
||||
#include "secrets.h"
|
||||
#else
|
||||
#warning "Please create secrets.h with SSID & PASSWORD defined"
|
||||
#define SECRET_SSID "your-ssid"
|
||||
#define SECRET_PASSWORD "your-password"
|
||||
#endif
|
||||
|
||||
// Debug with FTDI (Serial0) or USBCDC (Serial)
|
||||
#define DBG_SERIAL Serial
|
||||
|
||||
// ESP32 use same flash device that store code.
|
||||
// Therefore there is no need to specify the SPI and SS
|
||||
Adafruit_FlashTransport_ESP32 flashTransport;
|
||||
Adafruit_SPIFlash flash(&flashTransport);
|
||||
|
||||
// file system object from SdFat
|
||||
FatVolume fatfs;
|
||||
|
||||
// USB Mass Storage object
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
||||
bool fs_formatted; // Check if flash is formatted
|
||||
bool fs_changed; // Set to true when browser write to flash
|
||||
|
||||
const char* host = "esp32fs";
|
||||
WebServer server(80);
|
||||
//holds the current upload
|
||||
File32 fsUploadFile;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Setup
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void setupMassStorage(void)
|
||||
{
|
||||
flash.begin();
|
||||
|
||||
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
usb_msc.setID("Adafruit", "External Flash", "1.0");
|
||||
|
||||
// Set callback
|
||||
usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
|
||||
|
||||
// Set disk size, block size should be 512 regardless of spi flash page size
|
||||
usb_msc.setCapacity(flash.size()/512, 512);
|
||||
|
||||
// MSC is ready for read/write
|
||||
fs_changed = false;
|
||||
usb_msc.setReadyCallback(0, msc_ready_callback);
|
||||
|
||||
usb_msc.begin();
|
||||
|
||||
// Init file system on the flash
|
||||
fs_formatted = fatfs.begin(&flash);
|
||||
|
||||
if ( !fs_formatted )
|
||||
{
|
||||
DBG_SERIAL.println("Failed to init files system, flash may not be formatted");
|
||||
}
|
||||
}
|
||||
|
||||
void refreshMassStorage(void)
|
||||
{
|
||||
fs_changed = true;
|
||||
}
|
||||
|
||||
void setupServer(void)
|
||||
{
|
||||
//WIFI INIT
|
||||
DBG_SERIAL.printf("Connecting to %s\n", SECRET_SSID);
|
||||
if (String(WiFi.SSID()) != String(SECRET_SSID)) {
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(SECRET_SSID, SECRET_PASSWORD);
|
||||
}
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
delay(500);
|
||||
DBG_SERIAL.print(".");
|
||||
}
|
||||
DBG_SERIAL.println("");
|
||||
DBG_SERIAL.print("Connected! IP address: ");
|
||||
DBG_SERIAL.println(WiFi.localIP());
|
||||
|
||||
MDNS.begin(host);
|
||||
DBG_SERIAL.print("Open http://");
|
||||
DBG_SERIAL.print(host);
|
||||
DBG_SERIAL.println(".local/edit to access the file browser");
|
||||
|
||||
//SERVER INIT
|
||||
|
||||
//list directory
|
||||
server.on("/list", HTTP_GET, handleFileList);
|
||||
|
||||
//load editor
|
||||
server.on("/edit", HTTP_GET, []() {
|
||||
if (!handleFileRead("/edit.htm")) {
|
||||
server.send(404, "text/plain", "FileNotFound");
|
||||
}
|
||||
});
|
||||
|
||||
//create file
|
||||
server.on("/edit", HTTP_PUT, handleFileCreate);
|
||||
|
||||
//delete file
|
||||
server.on("/edit", HTTP_DELETE, handleFileDelete);
|
||||
|
||||
//first callback is called after the request has ended with all parsed arguments
|
||||
//second callback handles file uploads at that location
|
||||
server.on("/edit", HTTP_POST, []() {
|
||||
server.send(200, "text/plain", "");
|
||||
}, handleFileUpload);
|
||||
|
||||
//called when the url is not defined here
|
||||
//use it to load content from fatfs
|
||||
server.onNotFound([]() {
|
||||
if (!handleFileRead(server.uri())) {
|
||||
server.send(404, "text/plain", "FileNotFound");
|
||||
}
|
||||
});
|
||||
|
||||
//get heap status, analog input value and all GPIO statuses in one json call
|
||||
server.on("/all", HTTP_GET, []() {
|
||||
String json = "{";
|
||||
json += "\"heap\":" + String(ESP.getFreeHeap());
|
||||
json += ", \"analog\":" + String(analogRead(A0));
|
||||
json += ", \"gpio\":" + String((uint32_t)(0));
|
||||
json += "}";
|
||||
server.send(200, "text/json", json);
|
||||
json = String();
|
||||
});
|
||||
server.begin();
|
||||
DBG_SERIAL.println("HTTP server started");
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
#ifdef LED_BUILTIN
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
#endif
|
||||
|
||||
DBG_SERIAL.begin(115200);
|
||||
|
||||
setupMassStorage();
|
||||
|
||||
// while ( !DBG_SERIAL ) delay(10); // wait for native usb
|
||||
DBG_SERIAL.println("TinyUSB Mass Storage with ESP32 File Browser example");
|
||||
DBG_SERIAL.print("JEDEC ID: 0x"); DBG_SERIAL.println(flash.getJEDECID(), HEX);
|
||||
DBG_SERIAL.print("Flash size: "); DBG_SERIAL.print(flash.size() / 1024); DBG_SERIAL.println(" KB");
|
||||
|
||||
setupServer();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Handle requests
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//format bytes
|
||||
String formatBytes(size_t bytes) {
|
||||
if (bytes < 1024) {
|
||||
return String(bytes) + "B";
|
||||
} else if (bytes < (1024 * 1024)) {
|
||||
return String(bytes / 1024.0) + "KB";
|
||||
} else if (bytes < (1024 * 1024 * 1024)) {
|
||||
return String(bytes / 1024.0 / 1024.0) + "MB";
|
||||
} else {
|
||||
return String(bytes / 1024.0 / 1024.0 / 1024.0) + "GB";
|
||||
}
|
||||
}
|
||||
|
||||
String getContentType(String filename) {
|
||||
if (server.hasArg("download")) {
|
||||
return "application/octet-stream";
|
||||
} else if (filename.endsWith(".htm")) {
|
||||
return "text/html";
|
||||
} else if (filename.endsWith(".html")) {
|
||||
return "text/html";
|
||||
} else if (filename.endsWith(".css")) {
|
||||
return "text/css";
|
||||
} else if (filename.endsWith(".js")) {
|
||||
return "application/javascript";
|
||||
} else if (filename.endsWith(".png")) {
|
||||
return "image/png";
|
||||
} else if (filename.endsWith(".gif")) {
|
||||
return "image/gif";
|
||||
} else if (filename.endsWith(".jpg")) {
|
||||
return "image/jpeg";
|
||||
} else if (filename.endsWith(".ico")) {
|
||||
return "image/x-icon";
|
||||
} else if (filename.endsWith(".xml")) {
|
||||
return "text/xml";
|
||||
} else if (filename.endsWith(".pdf")) {
|
||||
return "application/x-pdf";
|
||||
} else if (filename.endsWith(".zip")) {
|
||||
return "application/x-zip";
|
||||
} else if (filename.endsWith(".gz")) {
|
||||
return "application/x-gzip";
|
||||
}
|
||||
return "text/plain";
|
||||
}
|
||||
|
||||
bool exists(String path){
|
||||
bool yes = false;
|
||||
File32 file = fatfs.open(path, O_READ);
|
||||
if(file && !file.isDirectory()){
|
||||
yes = true;
|
||||
}
|
||||
file.close();
|
||||
return yes;
|
||||
}
|
||||
|
||||
bool handleFileRead(String path) {
|
||||
DBG_SERIAL.println("handleFileRead: " + path);
|
||||
if (path.endsWith("/")) {
|
||||
path += "index.htm";
|
||||
}
|
||||
String contentType = getContentType(path);
|
||||
// String pathWithGz = path + ".gz";
|
||||
if ( /*exists(pathWithGz) ||*/ exists(path)) {
|
||||
// if (exists(pathWithGz)) {
|
||||
// path += ".gz";
|
||||
// }
|
||||
File32 file = fatfs.open(path, O_READ);
|
||||
server.streamFile(file, contentType);
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void handleFileUpload() {
|
||||
if (server.uri() != "/edit") {
|
||||
return;
|
||||
}
|
||||
HTTPUpload& upload = server.upload();
|
||||
if (upload.status == UPLOAD_FILE_START) {
|
||||
String filename = upload.filename;
|
||||
if (!filename.startsWith("/")) {
|
||||
filename = "/" + filename;
|
||||
}
|
||||
DBG_SERIAL.print("handleFileUpload Name: "); DBG_SERIAL.println(filename);
|
||||
fsUploadFile = fatfs.open(filename, O_WRITE | O_CREAT | O_TRUNC);
|
||||
filename = String();
|
||||
} else if (upload.status == UPLOAD_FILE_WRITE) {
|
||||
DBG_SERIAL.print("handleFileUpload Data: "); DBG_SERIAL.println(upload.currentSize);
|
||||
if (fsUploadFile) {
|
||||
fsUploadFile.write(upload.buf, upload.currentSize);
|
||||
}else
|
||||
{
|
||||
DBG_SERIAL.print("handleFileUpload file is not opened !!!");
|
||||
}
|
||||
} else if (upload.status == UPLOAD_FILE_END) {
|
||||
if (fsUploadFile) {
|
||||
fsUploadFile.close();
|
||||
refreshMassStorage();
|
||||
}
|
||||
DBG_SERIAL.print("handleFileUpload Size: "); DBG_SERIAL.println(upload.totalSize);
|
||||
}
|
||||
}
|
||||
|
||||
void handleFileDelete() {
|
||||
if (server.args() == 0) {
|
||||
return server.send(500, "text/plain", "BAD ARGS");
|
||||
}
|
||||
String path = server.arg(0);
|
||||
DBG_SERIAL.println("handleFileDelete: " + path);
|
||||
if (path == "/") {
|
||||
return server.send(500, "text/plain", "BAD PATH");
|
||||
}
|
||||
if (!exists(path)) {
|
||||
return server.send(404, "text/plain", "FileNotFound");
|
||||
}
|
||||
fatfs.remove(path.c_str());
|
||||
refreshMassStorage();
|
||||
server.send(200, "text/plain", "");
|
||||
path = String();
|
||||
}
|
||||
|
||||
void handleFileCreate() {
|
||||
if (server.args() == 0) {
|
||||
return server.send(500, "text/plain", "BAD ARGS");
|
||||
}
|
||||
String path = server.arg(0);
|
||||
DBG_SERIAL.println("handleFileCreate: " + path);
|
||||
if (path == "/") {
|
||||
return server.send(500, "text/plain", "BAD PATH");
|
||||
}
|
||||
if (exists(path)) {
|
||||
return server.send(500, "text/plain", "FILE EXISTS");
|
||||
}
|
||||
File32 file = fatfs.open(path, O_WRITE | O_CREAT);
|
||||
if (file) {
|
||||
file.close();
|
||||
} else {
|
||||
return server.send(500, "text/plain", "CREATE FAILED");
|
||||
}
|
||||
server.send(200, "text/plain", "");
|
||||
path = String();
|
||||
}
|
||||
|
||||
void handleFileList() {
|
||||
if (!server.hasArg("dir")) {
|
||||
server.send(500, "text/plain", "BAD ARGS");
|
||||
return;
|
||||
}
|
||||
|
||||
String path = server.arg("dir");
|
||||
DBG_SERIAL.println("handleFileList: " + path);
|
||||
|
||||
File32 root = fatfs.open(path);
|
||||
path = String();
|
||||
|
||||
String output = "[";
|
||||
if(root.isDirectory()){
|
||||
File32 file = root.openNextFile();
|
||||
char fname[256];
|
||||
while(file){
|
||||
if (output != "[") {
|
||||
output += ',';
|
||||
}
|
||||
output += "{\"type\":\"";
|
||||
output += (file.isDirectory()) ? "dir" : "file";
|
||||
output += "\",\"name\":\"";
|
||||
//output += String(file.path()).substring(1);
|
||||
file.getName(fname, sizeof(fname));
|
||||
output += fname;
|
||||
output += "\"}";
|
||||
file = root.openNextFile();
|
||||
}
|
||||
}
|
||||
output += "]";
|
||||
server.send(200, "text/json", output);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Loop
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void loop()
|
||||
{
|
||||
server.handleClient();
|
||||
delay(2);//allow the cpu to switch to other tasks
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
||||
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
#ifdef LED_BUILTIN
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
|
||||
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
||||
return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void msc_flush_cb (void)
|
||||
{
|
||||
// sync with flash
|
||||
flash.syncBlocks();
|
||||
|
||||
// clear file system's cache to force refresh
|
||||
fatfs.cacheClear();
|
||||
|
||||
#ifdef LED_BUILTIN
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Invoked when received Test Unit Ready command.
|
||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||
bool msc_ready_callback(void)
|
||||
{
|
||||
// if fs has changed, mark unit as not ready temporarily to force PC to flush cache
|
||||
bool ret = !fs_changed;
|
||||
fs_changed = false;
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Ha Thach (tinyusb.org) for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FLASH_CONFIG_H_
|
||||
#define FLASH_CONFIG_H_
|
||||
|
||||
// Un-comment to run example with custom SPI and SS e.g with FRAM breakout
|
||||
// #define CUSTOM_CS A5
|
||||
// #define CUSTOM_SPI SPI
|
||||
|
||||
#if defined(CUSTOM_CS) && defined(CUSTOM_SPI)
|
||||
Adafruit_FlashTransport_SPI flashTransport(CUSTOM_CS, CUSTOM_SPI);
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
|
||||
// ESP32 use same flash device that store code for file system.
|
||||
// SPIFlash will parse partition.cvs to detect FATFS partition to use
|
||||
Adafruit_FlashTransport_ESP32 flashTransport;
|
||||
|
||||
#elif defined(ARDUINO_ARCH_RP2040)
|
||||
|
||||
// RP2040 use same flash device that store code for file system. Therefore we
|
||||
// only need to specify start address and size (no need SPI or SS)
|
||||
// By default (start=0, size=0), values that match file system setting in
|
||||
// 'Tools->Flash Size' menu selection will be used.
|
||||
Adafruit_FlashTransport_RP2040 flashTransport;
|
||||
|
||||
// To be compatible with CircuitPython partition scheme (start_address = 1 MB,
|
||||
// size = total flash - 1 MB) use const value (CPY_START_ADDR, CPY_SIZE) or
|
||||
// subclass Adafruit_FlashTransport_RP2040_CPY. Un-comment either of the
|
||||
// following line:
|
||||
// Adafruit_FlashTransport_RP2040
|
||||
// flashTransport(Adafruit_FlashTransport_RP2040::CPY_START_ADDR,
|
||||
// Adafruit_FlashTransport_RP2040::CPY_SIZE);
|
||||
// Adafruit_FlashTransport_RP2040_CPY flashTransport;
|
||||
|
||||
#else
|
||||
|
||||
// On-board external flash (QSPI or SPI) macros should already
|
||||
// defined in your board variant if supported
|
||||
// - EXTERNAL_FLASH_USE_QSPI
|
||||
// - EXTERNAL_FLASH_USE_CS/EXTERNAL_FLASH_USE_SPI
|
||||
|
||||
#if defined(EXTERNAL_FLASH_USE_QSPI)
|
||||
|
||||
Adafruit_FlashTransport_QSPI flashTransport;
|
||||
|
||||
#elif defined(EXTERNAL_FLASH_USE_SPI)
|
||||
|
||||
Adafruit_FlashTransport_SPI flashTransport(EXTERNAL_FLASH_USE_CS,
|
||||
EXTERNAL_FLASH_USE_SPI);
|
||||
|
||||
#else
|
||||
#error No (Q)SPI flash are defined for your board !
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,174 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
/* This example demo how to expose on-board external Flash as USB Mass Storage.
|
||||
* Following library is required
|
||||
* - Adafruit_SPIFlash https://github.com/adafruit/Adafruit_SPIFlash
|
||||
* - SdFat https://github.com/adafruit/SdFat
|
||||
*
|
||||
* Note: Adafruit fork of SdFat enabled ENABLE_EXTENDED_TRANSFER_CLASS and FAT12_SUPPORT
|
||||
* in SdFatConfig.h, which is needed to run SdFat on external flash. You can use original
|
||||
* SdFat library and manually change those macros
|
||||
*
|
||||
* Note2: If your flash is not formatted as FAT12 previously, you could format it using
|
||||
* follow sketch https://github.com/adafruit/Adafruit_SPIFlash/tree/master/examples/SdFat_format
|
||||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat.h"
|
||||
#include "Adafruit_SPIFlash.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// for flashTransport definition
|
||||
#include "flash_config.h"
|
||||
|
||||
Adafruit_SPIFlash flash(&flashTransport);
|
||||
|
||||
// file system object from SdFat
|
||||
FatVolume fatfs;
|
||||
|
||||
FatFile root;
|
||||
FatFile file;
|
||||
|
||||
// USB Mass Storage object
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
||||
// Check if flash is formatted
|
||||
bool fs_formatted = false;
|
||||
|
||||
// Set to true when PC write to flash
|
||||
bool fs_changed = true;;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
flash.begin();
|
||||
|
||||
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
usb_msc.setID("Adafruit", "External Flash", "1.0");
|
||||
|
||||
// Set callback
|
||||
usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
|
||||
|
||||
// Set disk size, block size should be 512 regardless of spi flash page size
|
||||
usb_msc.setCapacity(flash.size()/512, 512);
|
||||
|
||||
// MSC is ready for read/write
|
||||
usb_msc.setUnitReady(true);
|
||||
|
||||
usb_msc.begin();
|
||||
|
||||
// Init file system on the flash
|
||||
fs_formatted = fatfs.begin(&flash);
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("Adafruit TinyUSB Mass Storage External Flash example");
|
||||
Serial.print("JEDEC ID: 0x"); Serial.println(flash.getJEDECID(), HEX);
|
||||
Serial.print("Flash size: "); Serial.print(flash.size() / 1024); Serial.println(" KB");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// check if formatted
|
||||
if ( !fs_formatted )
|
||||
{
|
||||
fs_formatted = fatfs.begin(&flash);
|
||||
|
||||
if (!fs_formatted)
|
||||
{
|
||||
Serial.println("Failed to init files system, flash may not be formatted");
|
||||
Serial.println("Please format it as FAT12 with your PC or using Adafruit_SPIFlash's SdFat_format example:");
|
||||
Serial.println("- https://github.com/adafruit/Adafruit_SPIFlash/tree/master/examples/SdFat_format");
|
||||
Serial.println();
|
||||
|
||||
delay(1000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( fs_changed )
|
||||
{
|
||||
fs_changed = false;
|
||||
|
||||
Serial.println("Opening root");
|
||||
|
||||
if ( !root.open("/") )
|
||||
{
|
||||
Serial.println("open root failed");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Flash contents:");
|
||||
|
||||
// Open next file in root.
|
||||
// Warning, openNext starts at the current directory position
|
||||
// so a rewind of the directory may be required.
|
||||
while ( file.openNext(&root, O_RDONLY) )
|
||||
{
|
||||
file.printFileSize(&Serial);
|
||||
Serial.write(' ');
|
||||
file.printName(&Serial);
|
||||
if ( file.isDir() )
|
||||
{
|
||||
// Indicate a directory.
|
||||
Serial.write('/');
|
||||
}
|
||||
Serial.println();
|
||||
file.close();
|
||||
}
|
||||
|
||||
root.close();
|
||||
|
||||
Serial.println();
|
||||
delay(1000); // refresh every 1 second
|
||||
}
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
// Note: SPIFLash Block API: readBlocks/writeBlocks/syncBlocks
|
||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
||||
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
|
||||
// Note: SPIFLash Block API: readBlocks/writeBlocks/syncBlocks
|
||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
||||
return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void msc_flush_cb (void)
|
||||
{
|
||||
// sync with flash
|
||||
flash.syncBlocks();
|
||||
|
||||
// clear file system's cache to force refresh
|
||||
fatfs.cacheClear();
|
||||
|
||||
fs_changed = true;
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Ha Thach (tinyusb.org) for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FLASH_CONFIG_H_
|
||||
#define FLASH_CONFIG_H_
|
||||
|
||||
// Un-comment to run example with custom SPI and SS e.g with FRAM breakout
|
||||
// #define CUSTOM_CS A5
|
||||
// #define CUSTOM_SPI SPI
|
||||
|
||||
#if defined(CUSTOM_CS) && defined(CUSTOM_SPI)
|
||||
Adafruit_FlashTransport_SPI flashTransport(CUSTOM_CS, CUSTOM_SPI);
|
||||
|
||||
#elif defined(ARDUINO_ARCH_ESP32)
|
||||
|
||||
// ESP32 use same flash device that store code for file system.
|
||||
// SPIFlash will parse partition.cvs to detect FATFS partition to use
|
||||
Adafruit_FlashTransport_ESP32 flashTransport;
|
||||
|
||||
#elif defined(ARDUINO_ARCH_RP2040)
|
||||
|
||||
// RP2040 use same flash device that store code for file system. Therefore we
|
||||
// only need to specify start address and size (no need SPI or SS)
|
||||
// By default (start=0, size=0), values that match file system setting in
|
||||
// 'Tools->Flash Size' menu selection will be used.
|
||||
Adafruit_FlashTransport_RP2040 flashTransport;
|
||||
|
||||
// To be compatible with CircuitPython partition scheme (start_address = 1 MB,
|
||||
// size = total flash - 1 MB) use const value (CPY_START_ADDR, CPY_SIZE) or
|
||||
// subclass Adafruit_FlashTransport_RP2040_CPY. Un-comment either of the
|
||||
// following line:
|
||||
// Adafruit_FlashTransport_RP2040
|
||||
// flashTransport(Adafruit_FlashTransport_RP2040::CPY_START_ADDR,
|
||||
// Adafruit_FlashTransport_RP2040::CPY_SIZE);
|
||||
// Adafruit_FlashTransport_RP2040_CPY flashTransport;
|
||||
|
||||
#else
|
||||
|
||||
// On-board external flash (QSPI or SPI) macros should already
|
||||
// defined in your board variant if supported
|
||||
// - EXTERNAL_FLASH_USE_QSPI
|
||||
// - EXTERNAL_FLASH_USE_CS/EXTERNAL_FLASH_USE_SPI
|
||||
|
||||
#if defined(EXTERNAL_FLASH_USE_QSPI)
|
||||
|
||||
Adafruit_FlashTransport_QSPI flashTransport;
|
||||
|
||||
#elif defined(EXTERNAL_FLASH_USE_SPI)
|
||||
|
||||
Adafruit_FlashTransport_SPI flashTransport(EXTERNAL_FLASH_USE_CS,
|
||||
EXTERNAL_FLASH_USE_SPI);
|
||||
|
||||
#else
|
||||
#error No (Q)SPI flash are defined for your board !
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,327 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
/* This example exposes both external flash and SD card as mass storage (dual LUNs)
|
||||
* Following library is required
|
||||
* - Adafruit_SPIFlash https://github.com/adafruit/Adafruit_SPIFlash
|
||||
* - SdFat https://github.com/adafruit/SdFat
|
||||
*
|
||||
* Note: Adafruit fork of SdFat enabled ENABLE_EXTENDED_TRANSFER_CLASS and FAT12_SUPPORT
|
||||
* in SdFatConfig.h, which is needed to run SdFat on external flash. You can use original
|
||||
* SdFat library and manually change those macros
|
||||
*
|
||||
* Note2: If your flash is not formatted as FAT12 previously, you could format it using
|
||||
* follow sketch https://github.com/adafruit/Adafruit_SPIFlash/tree/master/examples/SdFat_format
|
||||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat.h"
|
||||
#include "Adafruit_SPIFlash.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// External Flash Config
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// for flashTransport definition
|
||||
#include "flash_config.h"
|
||||
|
||||
Adafruit_SPIFlash flash(&flashTransport);
|
||||
|
||||
// External Flash File system
|
||||
FatVolume fatfs;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// SDCard Config
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#if defined(ARDUINO_PYPORTAL_M4) || defined(ARDUINO_PYPORTAL_M4_TITANO)
|
||||
// PyPortal has on-board card reader
|
||||
#define SDCARD_CS 32
|
||||
#define SDCARD_DETECT 33
|
||||
#else
|
||||
#define SDCARD_CS 10
|
||||
// no detect
|
||||
#endif
|
||||
|
||||
// SDCard File system
|
||||
SdFat sd;
|
||||
|
||||
// USB Mass Storage object
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
||||
// Set to true when PC write to flash
|
||||
bool sd_changed = false;
|
||||
bool sd_inited = false;
|
||||
|
||||
bool flash_formatted = false;
|
||||
bool flash_changed = false;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
Serial.begin(115200);
|
||||
|
||||
// MSC with 2 Logical Units: LUN0: External Flash, LUN1: SDCard
|
||||
usb_msc.setMaxLun(2);
|
||||
|
||||
usb_msc.setID(0, "Adafruit", "External Flash", "1.0");
|
||||
usb_msc.setID(1, "Adafruit", "SD Card", "1.0");
|
||||
|
||||
// Since initialize both external flash and SD card can take time.
|
||||
// If it takes too long, our board could be enumerated as CDC device only
|
||||
// i.e without Mass Storage. To prevent this, we call Mass Storage begin first
|
||||
// LUN readiness will always be set later on
|
||||
usb_msc.begin();
|
||||
|
||||
//------------- Lun 0 for external flash -------------//
|
||||
flash.begin();
|
||||
flash_formatted = fatfs.begin(&flash);
|
||||
|
||||
usb_msc.setCapacity(0, flash.size()/512, 512);
|
||||
usb_msc.setReadWriteCallback(0, external_flash_read_cb, external_flash_write_cb, external_flash_flush_cb);
|
||||
usb_msc.setUnitReady(0, true);
|
||||
|
||||
flash_changed = true; // to print contents initially
|
||||
|
||||
//------------- Lun 1 for SD card -------------//
|
||||
#ifdef SDCARD_DETECT
|
||||
// DETECT pin is available, detect card present on the fly with test unit ready
|
||||
pinMode(SDCARD_DETECT, INPUT);
|
||||
usb_msc.setReadyCallback(1, sdcard_ready_callback);
|
||||
#else
|
||||
// no DETECT pin, card must be inserted when powered on
|
||||
init_sdcard();
|
||||
sd_inited = true;
|
||||
usb_msc.setUnitReady(1, true);
|
||||
#endif
|
||||
|
||||
// while ( !Serial ) delay(10); // wait for native usb
|
||||
Serial.println("Adafruit TinyUSB Mass Storage External Flash + SD Card example");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
bool init_sdcard(void)
|
||||
{
|
||||
Serial.print("Init SDCard ... ");
|
||||
|
||||
if ( !sd.begin(SDCARD_CS, SD_SCK_MHZ(50)) )
|
||||
{
|
||||
Serial.print("Failed ");
|
||||
sd.errorPrint("sd.begin() failed");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t block_count;
|
||||
|
||||
#if SD_FAT_VERSION >= 20000
|
||||
block_count = sd.card()->sectorCount();
|
||||
#else
|
||||
block_count = sd.card()->cardSize();
|
||||
#endif
|
||||
|
||||
|
||||
usb_msc.setCapacity(1, block_count, 512);
|
||||
usb_msc.setReadWriteCallback(1, sdcard_read_cb, sdcard_write_cb, sdcard_flush_cb);
|
||||
|
||||
sd_changed = true; // to print contents initially
|
||||
|
||||
Serial.print("OK, Card size = ");
|
||||
Serial.print((block_count / (1024*1024)) * 512);
|
||||
Serial.println(" MB");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void print_rootdir(File32* rdir)
|
||||
{
|
||||
File32 file;
|
||||
|
||||
// Open next file in root.
|
||||
// Warning, openNext starts at the current directory position
|
||||
// so a rewind of the directory may be required.
|
||||
while ( file.openNext(rdir, O_RDONLY) )
|
||||
{
|
||||
file.printFileSize(&Serial);
|
||||
Serial.write(' ');
|
||||
file.printName(&Serial);
|
||||
if ( file.isDir() )
|
||||
{
|
||||
// Indicate a directory.
|
||||
Serial.write('/');
|
||||
}
|
||||
Serial.println();
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if ( flash_changed )
|
||||
{
|
||||
if (!flash_formatted)
|
||||
{
|
||||
flash_formatted = fatfs.begin(&flash);
|
||||
}
|
||||
|
||||
// skip if still not formatted
|
||||
if (flash_formatted)
|
||||
{
|
||||
File32 root;
|
||||
root = fatfs.open("/");
|
||||
|
||||
Serial.println("Flash contents:");
|
||||
print_rootdir(&root);
|
||||
Serial.println();
|
||||
|
||||
root.close();
|
||||
}
|
||||
|
||||
flash_changed = false;
|
||||
}
|
||||
|
||||
if ( sd_changed )
|
||||
{
|
||||
File32 root;
|
||||
root = sd.open("/");
|
||||
|
||||
Serial.println("SD contents:");
|
||||
print_rootdir(&root);
|
||||
Serial.println();
|
||||
|
||||
root.close();
|
||||
|
||||
sd_changed = false;
|
||||
}
|
||||
|
||||
delay(1000); // refresh every 1 second
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// SD Card callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
int32_t sdcard_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
bool rc;
|
||||
|
||||
#if SD_FAT_VERSION >= 20000
|
||||
rc = sd.card()->readSectors(lba, (uint8_t*) buffer, bufsize/512);
|
||||
#else
|
||||
rc = sd.card()->readBlocks(lba, (uint8_t*) buffer, bufsize/512);
|
||||
#endif
|
||||
|
||||
return rc ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t sdcard_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
bool rc;
|
||||
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
|
||||
#if SD_FAT_VERSION >= 20000
|
||||
rc = sd.card()->writeSectors(lba, buffer, bufsize/512);
|
||||
#else
|
||||
rc = sd.card()->writeBlocks(lba, buffer, bufsize/512);
|
||||
#endif
|
||||
|
||||
return rc ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void sdcard_flush_cb (void)
|
||||
{
|
||||
#if SD_FAT_VERSION >= 20000
|
||||
sd.card()->syncDevice();
|
||||
#else
|
||||
sd.card()->syncBlocks();
|
||||
#endif
|
||||
|
||||
// clear file system's cache to force refresh
|
||||
sd.cacheClear();
|
||||
|
||||
sd_changed = true;
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
||||
|
||||
#ifdef SDCARD_DETECT
|
||||
// Invoked when received Test Unit Ready command.
|
||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||
bool sdcard_ready_callback(void)
|
||||
{
|
||||
// Card is inserted
|
||||
if ( digitalRead(SDCARD_DETECT) == HIGH )
|
||||
{
|
||||
// init SD card if not already
|
||||
if ( !sd_inited )
|
||||
{
|
||||
sd_inited = init_sdcard();
|
||||
}
|
||||
}else
|
||||
{
|
||||
sd_inited = false;
|
||||
usb_msc.setReadWriteCallback(1, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
Serial.println(sd_inited);
|
||||
|
||||
return sd_inited;
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// External Flash callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t external_flash_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
||||
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t external_flash_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
|
||||
// Note: SPIFLash Bock API: readBlocks/writeBlocks/syncBlocks
|
||||
// already include 4K sector caching internally. We don't need to cache it, yahhhh!!
|
||||
return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void external_flash_flush_cb (void)
|
||||
{
|
||||
flash.syncBlocks();
|
||||
|
||||
// clear file system's cache to force refresh
|
||||
fatfs.cacheClear();
|
||||
|
||||
flash_changed = true;
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat.h"
|
||||
#include "Adafruit_InternalFlash.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// Start address and size should matches value in the CircuitPython (INTERNAL_FLASH_FILESYSTEM = 1)
|
||||
// to make it easier to switch between Arduino and CircuitPython
|
||||
#define INTERNAL_FLASH_FILESYSTEM_START_ADDR (0x00040000 - 256 - 0 - INTERNAL_FLASH_FILESYSTEM_SIZE)
|
||||
#define INTERNAL_FLASH_FILESYSTEM_SIZE (64*1024)
|
||||
|
||||
// Internal Flash object
|
||||
Adafruit_InternalFlash flash(INTERNAL_FLASH_FILESYSTEM_START_ADDR, INTERNAL_FLASH_FILESYSTEM_SIZE);
|
||||
|
||||
// file system object from SdFat
|
||||
FatVolume fatfs;
|
||||
|
||||
FatFile root;
|
||||
FatFile file;
|
||||
|
||||
// USB MSC object
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
||||
// Set to true when PC write to flash
|
||||
bool fs_changed;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
// Initialize internal flash
|
||||
flash.begin();
|
||||
|
||||
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
usb_msc.setID("Adafruit", "Internal Flash", "1.0");
|
||||
|
||||
// Set callback
|
||||
usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_callback);
|
||||
usb_msc.setWritableCallback(msc_writable_callback);
|
||||
|
||||
// Set disk size, block size should be 512 regardless of flash page size
|
||||
usb_msc.setCapacity(flash.size()/512, 512);
|
||||
|
||||
// Set Lun ready
|
||||
usb_msc.setUnitReady(true);
|
||||
|
||||
usb_msc.begin();
|
||||
|
||||
// Init file system on the flash
|
||||
fatfs.begin(&flash);
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
fs_changed = true; // to print contents initially
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if ( fs_changed )
|
||||
{
|
||||
fs_changed = false;
|
||||
|
||||
if ( !root.open("/") )
|
||||
{
|
||||
Serial.println("open root failed");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Flash contents:");
|
||||
|
||||
// Open next file in root.
|
||||
// Warning, openNext starts at the current directory position
|
||||
// so a rewind of the directory may be required.
|
||||
while ( file.openNext(&root, O_RDONLY) )
|
||||
{
|
||||
file.printFileSize(&Serial);
|
||||
Serial.write(' ');
|
||||
file.printName(&Serial);
|
||||
if ( file.isDir() )
|
||||
{
|
||||
// Indicate a directory.
|
||||
Serial.write('/');
|
||||
}
|
||||
Serial.println();
|
||||
file.close();
|
||||
}
|
||||
|
||||
root.close();
|
||||
|
||||
Serial.println();
|
||||
delay(1000); // refresh every 1 second
|
||||
}
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
// Note: InternalFlash Block API: readBlocks/writeBlocks/syncBlocks
|
||||
// already include sector caching (if needed). We don't need to cache it, yahhhh!!
|
||||
return flash.readBlocks(lba, (uint8_t*) buffer, bufsize/512) ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t msc_write_callback (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
// Note: InternalFlash Block API: readBlocks/writeBlocks/syncBlocks
|
||||
// already include sector caching (if needed). We don't need to cache it, yahhhh!!
|
||||
return flash.writeBlocks(lba, buffer, bufsize/512) ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void msc_flush_callback (void)
|
||||
{
|
||||
// sync with flash
|
||||
flash.syncBlocks();
|
||||
|
||||
// clear file system's cache to force refresh
|
||||
fatfs.cacheClear();
|
||||
|
||||
fs_changed = true;
|
||||
}
|
||||
|
||||
// Invoked to check if device is writable as part of SCSI WRITE10
|
||||
// Default mode is writable
|
||||
bool msc_writable_callback(void)
|
||||
{
|
||||
// true for writable, false for read-only
|
||||
return true;
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// 8KB is the smallest size that windows allow to mount
|
||||
#define DISK_BLOCK_NUM 16
|
||||
#define DISK_BLOCK_SIZE 512
|
||||
#include "ramdisk.h"
|
||||
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
||||
// Eject button to demonstrate medium is not ready e.g SDCard is not present
|
||||
// whenever this button is pressed and hold, it will report to host as not ready
|
||||
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY)
|
||||
#define BTN_EJECT 4 // Left Button
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined(ARDUINO_FUNHOUSE_ESP32S2)
|
||||
#define BTN_EJECT BUTTON_DOWN
|
||||
bool activeState = true;
|
||||
|
||||
#elif defined PIN_BUTTON1
|
||||
#define BTN_EJECT PIN_BUTTON1
|
||||
bool activeState = false;
|
||||
#endif
|
||||
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
||||
// Manual begin() is required on core without built-in support for TinyUSB such as
|
||||
// - mbed rp2040
|
||||
TinyUSB_Device_Init(0);
|
||||
#endif
|
||||
|
||||
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
usb_msc.setID("Adafruit", "Mass Storage", "1.0");
|
||||
|
||||
// Set disk size
|
||||
usb_msc.setCapacity(DISK_BLOCK_NUM, DISK_BLOCK_SIZE);
|
||||
|
||||
// Set callback
|
||||
usb_msc.setReadWriteCallback(msc_read_callback, msc_write_callback, msc_flush_callback);
|
||||
|
||||
// Set Lun ready (RAM disk is always ready)
|
||||
usb_msc.setUnitReady(true);
|
||||
|
||||
#ifdef BTN_EJECT
|
||||
pinMode(BTN_EJECT, activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
|
||||
usb_msc.setReadyCallback(msc_ready_callback);
|
||||
#endif
|
||||
|
||||
usb_msc.begin();
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("Adafruit TinyUSB Mass Storage RAM Disk example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t msc_read_callback (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t const* addr = msc_disk[lba];
|
||||
memcpy(buffer, addr, bufsize);
|
||||
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t msc_write_callback (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t* addr = msc_disk[lba];
|
||||
memcpy(addr, buffer, bufsize);
|
||||
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void msc_flush_callback (void)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
||||
#ifdef BTN_EJECT
|
||||
// Invoked when received Test Unit Ready command.
|
||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||
bool msc_ready_callback(void)
|
||||
{
|
||||
// button not active --> medium ready
|
||||
return digitalRead(BTN_EJECT) != activeState;
|
||||
}
|
||||
#endif
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef RAMDISK_H_
|
||||
#define RAMDISK_H_
|
||||
|
||||
#define README_CONTENTS \
|
||||
"This is TinyUSB MassStorage device demo for Arduino on RAM disk."
|
||||
|
||||
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
|
||||
//------------- Block0: Boot Sector -------------//
|
||||
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 =
|
||||
// DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num =
|
||||
// 1; fat12_root_entry_num = 16; sector_per_fat = 1; sector_per_track =
|
||||
// 1; head_num = 1; hidden_sectors = 0; drive_number = 0x80;
|
||||
// media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type =
|
||||
// "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
|
||||
// FAT magic code at offset 510-511
|
||||
{0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00,
|
||||
0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00,
|
||||
0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S',
|
||||
'B', ' ', 'M', 'S', 'C', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20,
|
||||
0x00, 0x00,
|
||||
|
||||
// Zero up to 2 last bytes of FAT magic code
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x55, 0xAA},
|
||||
|
||||
//------------- Block1: FAT12 Table -------------//
|
||||
{
|
||||
0xF8, 0xFF, 0x00, // The first 2 12bit entries of the FAT linked list are reserved. Therefore the first 3 bytes are reserved.
|
||||
// The 2 12 bit values must be 0xF8 and 0xFF
|
||||
|
||||
// [Entry2 | Entry3]
|
||||
0xFF, 0x0F, 0x00 // <<< These 3 bytes represents the 12 bit entries 2 and 3 of the FAT linked list.
|
||||
// The README.TXT file first block is 2 (see line 112), therefore to find the next block, we go to this section Entry[2]
|
||||
// to read the address of the next block. Since the size of the README.TXT is 65 bytes and less then one sector (512) byte.
|
||||
// There is no next block to read therefore the Entry[2] contains the value 0xFFF, which is the EOF.
|
||||
},
|
||||
|
||||
//------------- Block2: Root Directory -------------//
|
||||
{
|
||||
// first entry is volume label
|
||||
'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', 'M', 'S', 'C', 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// second entry is readme file
|
||||
'R', 'E', 'A', 'D', 'M', 'E', ' ', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6,
|
||||
0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43,
|
||||
0x02, 0x00, sizeof(README_CONTENTS) - 1, 0x00, 0x00,
|
||||
0x00 // readme's files size (4 Bytes)
|
||||
},
|
||||
|
||||
//------------- Block3: Readme Content -------------//
|
||||
README_CONTENTS};
|
||||
|
||||
#endif /* RAMDISK_H_ */
|
@ -0,0 +1,122 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// 8KB is the smallest size that windows allow to mount
|
||||
#define DISK_BLOCK_NUM 16
|
||||
#define DISK_BLOCK_SIZE 512
|
||||
#include "ramdisk.h"
|
||||
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
||||
TinyUSB_Device_Init(0);
|
||||
#endif
|
||||
|
||||
usb_msc.setMaxLun(2);
|
||||
|
||||
// Set disk size and callback for Logical Unit 0 (LUN 0)
|
||||
usb_msc.setID(0, "Adafruit", "Lun0", "1.0");
|
||||
usb_msc.setCapacity(0, DISK_BLOCK_NUM, DISK_BLOCK_SIZE);
|
||||
usb_msc.setReadWriteCallback(0, ram0_read_cb, ram0_write_cb, ram0_flush_cb);
|
||||
usb_msc.setUnitReady(0, true);
|
||||
|
||||
// Set disk size and callback for Logical Unit 1 (LUN 1)
|
||||
usb_msc.setID(1, "Adafruit", "Lun1", "1.0");
|
||||
usb_msc.setCapacity(1, DISK_BLOCK_NUM, DISK_BLOCK_SIZE);
|
||||
usb_msc.setReadWriteCallback(1, ram1_read_cb, ram1_write_cb, ram1_flush_cb);
|
||||
usb_msc.setUnitReady(1, true);
|
||||
|
||||
usb_msc.begin();
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("Adafruit TinyUSB Mass Storage Dual RAM Disks example");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// LUN 0 callback
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t ram0_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t const* addr = msc_disk0[lba];
|
||||
memcpy(buffer, addr, bufsize);
|
||||
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t ram0_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t* addr = msc_disk0[lba];
|
||||
memcpy(addr, buffer, bufsize);
|
||||
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void ram0_flush_cb (void)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// LUN 1 callback
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t ram1_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t const* addr = msc_disk1[lba];
|
||||
memcpy(buffer, addr, bufsize);
|
||||
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t ram1_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
uint8_t* addr = msc_disk1[lba];
|
||||
memcpy(addr, buffer, bufsize);
|
||||
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void ram1_flush_cb (void)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef RAMDISK_H_
|
||||
#define RAMDISK_H_
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// LUN 0
|
||||
//--------------------------------------------------------------------+
|
||||
#define README0_CONTENTS \
|
||||
"LUN0: This is TinyUSB MassStorage device demo for Arduino on RAM disk."
|
||||
|
||||
uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
|
||||
//------------- Block0: Boot Sector -------------//
|
||||
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 =
|
||||
// DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num =
|
||||
// 1; fat12_root_entry_num = 16; sector_per_fat = 1; sector_per_track =
|
||||
// 1; head_num = 1; hidden_sectors = 0; drive_number = 0x80;
|
||||
// media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type =
|
||||
// "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB 0 ";
|
||||
// FAT magic code at offset 510-511
|
||||
{0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00,
|
||||
0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00,
|
||||
0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S',
|
||||
'B', ' ', '0', ' ', ' ', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20,
|
||||
0x00, 0x00,
|
||||
|
||||
// Zero up to 2 last bytes of FAT magic code
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x55, 0xAA},
|
||||
|
||||
//------------- Block1: FAT12 Table -------------//
|
||||
{
|
||||
0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third
|
||||
// entry is cluster end of readme file
|
||||
},
|
||||
|
||||
//------------- Block2: Root Directory -------------//
|
||||
{
|
||||
// first entry is volume label
|
||||
'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', '0', ' ', ' ', 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// second entry is readme file
|
||||
'R', 'E', 'A', 'D', 'M', 'E', '0', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6,
|
||||
0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43,
|
||||
0x02, 0x00, sizeof(README0_CONTENTS) - 1, 0x00, 0x00,
|
||||
0x00 // readme's files size (4 Bytes)
|
||||
},
|
||||
|
||||
//------------- Block3: Readme Content -------------//
|
||||
README0_CONTENTS};
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// LUN 1
|
||||
//--------------------------------------------------------------------+
|
||||
#define README1_CONTENTS \
|
||||
"LUN1: This is TinyUSB MassStorage device demo for Arduino on RAM disk."
|
||||
|
||||
uint8_t msc_disk1[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = {
|
||||
//------------- Block0: Boot Sector -------------//
|
||||
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 =
|
||||
// DISK_BLOCK_NUM; sector_per_cluster = 1; reserved_sectors = 1; fat_num =
|
||||
// 1; fat12_root_entry_num = 16; sector_per_fat = 1; sector_per_track =
|
||||
// 1; head_num = 1; hidden_sectors = 0; drive_number = 0x80;
|
||||
// media_type = 0xf8; extended_boot_signature = 0x29; filesystem_type =
|
||||
// "FAT12 "; volume_serial_number = 0x5678; volume_label = "TinyUSB 1 ";
|
||||
// FAT magic code at offset 510-511
|
||||
{0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00,
|
||||
0x02, 0x01, 0x01, 0x00, 0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00,
|
||||
0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x80, 0x00, 0x29, 0x78, 0x56, 0x00, 0x00, 'T', 'i', 'n', 'y', 'U', 'S',
|
||||
'B', ' ', '1', ' ', ' ', 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20,
|
||||
0x00, 0x00,
|
||||
|
||||
// Zero up to 2 last bytes of FAT magic code
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x55, 0xAA},
|
||||
|
||||
//------------- Block1: FAT12 Table -------------//
|
||||
{
|
||||
0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third
|
||||
// entry is cluster end of readme file
|
||||
},
|
||||
|
||||
//------------- Block2: Root Directory -------------//
|
||||
{
|
||||
// first entry is volume label
|
||||
'T', 'i', 'n', 'y', 'U', 'S', 'B', ' ', '1', ' ', ' ', 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// second entry is readme file
|
||||
'R', 'E', 'A', 'D', 'M', 'E', '1', ' ', 'T', 'X', 'T', 0x20, 0x00, 0xC6,
|
||||
0x52, 0x6D, 0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43,
|
||||
0x02, 0x00, sizeof(README1_CONTENTS) - 1, 0x00, 0x00,
|
||||
0x00 // readme's files size (4 Bytes)
|
||||
},
|
||||
|
||||
//------------- Block3: Readme Content -------------//
|
||||
README1_CONTENTS};
|
||||
|
||||
#endif /* RAMDISK_H_ */
|
@ -0,0 +1,102 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
/* This example expose SD card as mass storage using
|
||||
* default SD Library
|
||||
*/
|
||||
|
||||
#include "SD.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
const int chipSelect = 10;
|
||||
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
usb_msc.setID("Adafruit", "SD Card", "1.0");
|
||||
|
||||
// Set read write callback
|
||||
usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
|
||||
|
||||
// Still initialize MSC but tell usb stack that MSC is not ready to read/write
|
||||
// If we don't initialize, board will be enumerated as CDC only
|
||||
usb_msc.setUnitReady(false);
|
||||
usb_msc.begin();
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("Adafruit TinyUSB Mass Storage SD Card example");
|
||||
|
||||
Serial.println("\nInitializing SD card...");
|
||||
|
||||
if ( !card.init(SPI_HALF_SPEED, chipSelect) )
|
||||
{
|
||||
Serial.println("initialization failed. Things to check:");
|
||||
Serial.println("* is a card inserted?");
|
||||
Serial.println("* is your wiring correct?");
|
||||
Serial.println("* did you change the chipSelect pin to match your shield or module?");
|
||||
while (1) delay(1);
|
||||
}
|
||||
|
||||
// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
|
||||
if (!volume.init(card)) {
|
||||
Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
|
||||
while (1) delay(1);
|
||||
}
|
||||
|
||||
uint32_t block_count = volume.blocksPerCluster()*volume.clusterCount();
|
||||
|
||||
Serial.print("Volume size (MB): ");
|
||||
Serial.println((block_count/2) / 1024);
|
||||
|
||||
// Set disk size, SD block size is always 512
|
||||
usb_msc.setCapacity(block_count, 512);
|
||||
|
||||
// MSC is ready for read/write
|
||||
usb_msc.setUnitReady(true);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
(void) bufsize;
|
||||
return card.readBlock(lba, (uint8_t*) buffer) ? 512 : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
(void) bufsize;
|
||||
return card.writeBlock(lba, buffer) ? 512 : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void msc_flush_cb (void)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
/* This example expose SD card as mass storage using
|
||||
* SdFat Library
|
||||
*/
|
||||
|
||||
#include "SPI.h"
|
||||
#include "SdFat.h"
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
const int chipSelect = 10;
|
||||
|
||||
// File system on SD Card
|
||||
SdFat sd;
|
||||
|
||||
SdFile root;
|
||||
SdFile file;
|
||||
|
||||
// USB Mass Storage object
|
||||
Adafruit_USBD_MSC usb_msc;
|
||||
|
||||
// Set to true when PC write to flash
|
||||
bool fs_changed;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
|
||||
// Set disk vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
usb_msc.setID("Adafruit", "SD Card", "1.0");
|
||||
|
||||
// Set read write callback
|
||||
usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
|
||||
|
||||
// Still initialize MSC but tell usb stack that MSC is not ready to read/write
|
||||
// If we don't initialize, board will be enumerated as CDC only
|
||||
usb_msc.setUnitReady(false);
|
||||
usb_msc.begin();
|
||||
|
||||
Serial.begin(115200);
|
||||
//while ( !Serial ) delay(10); // wait for native usb
|
||||
|
||||
Serial.println("Adafruit TinyUSB Mass Storage SD Card example");
|
||||
|
||||
Serial.print("\nInitializing SD card ... ");
|
||||
Serial.print("CS = "); Serial.println(chipSelect);
|
||||
|
||||
if ( !sd.begin(chipSelect, SD_SCK_MHZ(50)) )
|
||||
{
|
||||
Serial.println("initialization failed. Things to check:");
|
||||
Serial.println("* is a card inserted?");
|
||||
Serial.println("* is your wiring correct?");
|
||||
Serial.println("* did you change the chipSelect pin to match your shield or module?");
|
||||
while (1) delay(1);
|
||||
}
|
||||
|
||||
// Size in blocks (512 bytes)
|
||||
#if SD_FAT_VERSION >= 20000
|
||||
uint32_t block_count = sd.card()->sectorCount();
|
||||
#else
|
||||
uint32_t block_count = sd.card()->cardSize();
|
||||
#endif
|
||||
|
||||
Serial.print("Volume size (MB): ");
|
||||
Serial.println((block_count/2) / 1024);
|
||||
|
||||
// Set disk size, SD block size is always 512
|
||||
usb_msc.setCapacity(block_count, 512);
|
||||
|
||||
// MSC is ready for read/write
|
||||
usb_msc.setUnitReady(true);
|
||||
|
||||
fs_changed = true; // to print contents initially
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if ( fs_changed )
|
||||
{
|
||||
root.open("/");
|
||||
Serial.println("SD contents:");
|
||||
|
||||
// Open next file in root.
|
||||
// Warning, openNext starts at the current directory position
|
||||
// so a rewind of the directory may be required.
|
||||
while ( file.openNext(&root, O_RDONLY) )
|
||||
{
|
||||
file.printFileSize(&Serial);
|
||||
Serial.write(' ');
|
||||
file.printName(&Serial);
|
||||
if ( file.isDir() )
|
||||
{
|
||||
// Indicate a directory.
|
||||
Serial.write('/');
|
||||
}
|
||||
Serial.println();
|
||||
file.close();
|
||||
}
|
||||
|
||||
root.close();
|
||||
|
||||
Serial.println();
|
||||
|
||||
fs_changed = false;
|
||||
delay(1000); // refresh every 0.5 second
|
||||
}
|
||||
}
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and
|
||||
// return number of copied bytes (must be multiple of block size)
|
||||
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize)
|
||||
{
|
||||
bool rc;
|
||||
|
||||
#if SD_FAT_VERSION >= 20000
|
||||
rc = sd.card()->readSectors(lba, (uint8_t*) buffer, bufsize/512);
|
||||
#else
|
||||
rc = sd.card()->readBlocks(lba, (uint8_t*) buffer, bufsize/512);
|
||||
#endif
|
||||
|
||||
return rc ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and
|
||||
// return number of written bytes (must be multiple of block size)
|
||||
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize)
|
||||
{
|
||||
bool rc;
|
||||
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
|
||||
#if SD_FAT_VERSION >= 20000
|
||||
rc = sd.card()->writeSectors(lba, buffer, bufsize/512);
|
||||
#else
|
||||
rc = sd.card()->writeBlocks(lba, buffer, bufsize/512);
|
||||
#endif
|
||||
|
||||
return rc ? bufsize : -1;
|
||||
}
|
||||
|
||||
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
|
||||
// used to flush any pending cache.
|
||||
void msc_flush_cb (void)
|
||||
{
|
||||
#if SD_FAT_VERSION >= 20000
|
||||
sd.card()->syncDevice();
|
||||
#else
|
||||
sd.card()->syncBlocks();
|
||||
#endif
|
||||
|
||||
// clear file system's cache to force refresh
|
||||
sd.cacheClear();
|
||||
|
||||
fs_changed = true;
|
||||
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Ha Thach (tinyusb.org) for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Reference:
|
||||
* - https://github.com/torvalds/linux/blob/master/drivers/i2c/busses/i2c-tiny-usb.c
|
||||
* - https://github.com/harbaum/I2C-Tiny-USB
|
||||
*
|
||||
* Requirement:
|
||||
* - Install i2c-tools with
|
||||
* sudo apt install i2c-tools
|
||||
*
|
||||
* How to test example:
|
||||
* - Compile and flash this sketch on your board with an i2c device, it should enumerated as
|
||||
* ID 1c40:0534 EZPrototypes i2c-tiny-usb interface
|
||||
*
|
||||
* - Run "i2cdetect -l" to find our bus ID e.g
|
||||
* i2c-8 i2c i2c-tiny-usb at bus 003 device 039 I2C adapter
|
||||
*
|
||||
* - Run "i2cdetect -y 8" to scan for on-board device (8 is the above bus ID)
|
||||
* 0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
00: -- -- -- -- -- -- -- --
|
||||
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
70: -- -- -- -- -- -- -- 77
|
||||
|
||||
- You can then interact with sensor using following commands:
|
||||
i2cget i2cset i2cdump i2ctransfer or using any driver/tools that work on i2c device.
|
||||
*/
|
||||
|
||||
#include "Adafruit_USBD_I2C.h"
|
||||
|
||||
Adafruit_USBD_I2C::Adafruit_USBD_I2C(TwoWire* wire) {
|
||||
_wire = wire;
|
||||
_buf = NULL;
|
||||
_bufsize = 0; // not used to verify length yet
|
||||
_state = I2C_STATUS_IDLE;
|
||||
_functionality = 0x8eff0001; // check out _functionality_* defines
|
||||
setStringDescriptor("I2C Interface");
|
||||
}
|
||||
|
||||
uint16_t Adafruit_USBD_I2C::getInterfaceDescriptor(uint8_t itfnum, uint8_t* buf, uint16_t bufsize) {
|
||||
uint8_t desc[] = { TUD_VENDOR_DESCRIPTOR(itfnum, 0, 0x00, 0x80, 64) };
|
||||
uint16_t const len = sizeof(desc);
|
||||
if (buf) {
|
||||
if (bufsize < len) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(buf, desc, len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
bool Adafruit_USBD_I2C::begin(uint8_t* buffer, size_t bufsize) {
|
||||
_buf = buffer;
|
||||
_bufsize = (uint16_t) bufsize;
|
||||
|
||||
if (!_wire || !_buf || !_bufsize) return false;
|
||||
|
||||
// needed to identify as a device for i2c_tiny_usb (EZPrototypes VID/PID)
|
||||
TinyUSBDevice.setID(0x1c40, 0x0534);
|
||||
if (!TinyUSBDevice.addInterface(*this)) return false;
|
||||
|
||||
_wire->begin();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t Adafruit_USBD_I2C::i2c_read(uint8_t addr, uint8_t* buf, uint16_t len, bool stop_bit)
|
||||
{
|
||||
uint16_t const rd_count = (uint16_t) _wire->requestFrom(addr, len, stop_bit);
|
||||
|
||||
_state = (len && !rd_count) ? I2C_STATUS_NAK : I2C_STATUS_ACK;
|
||||
|
||||
// Serial.printf("I2C Read: addr = 0x%02X, len = %u, rd_count %u bytes, status = %u\r\n", addr, len, rd_count, i2c_state);
|
||||
|
||||
for(uint16_t i = 0; i <rd_count; i++)
|
||||
{
|
||||
buf[i] = (uint8_t) _wire->read();
|
||||
}
|
||||
|
||||
return rd_count;
|
||||
}
|
||||
|
||||
uint16_t Adafruit_USBD_I2C::i2c_write(uint8_t addr, uint8_t const* buf, uint16_t len, bool stop_bit)
|
||||
{
|
||||
_wire->beginTransmission(addr);
|
||||
uint16_t wr_count = (uint16_t) _wire->write(buf, len);
|
||||
uint8_t const sts = _wire->endTransmission(stop_bit);
|
||||
|
||||
_state = (sts == 0) ? I2C_STATUS_ACK : I2C_STATUS_NAK;
|
||||
|
||||
// Serial.printf("I2C Write: addr = 0x%02X, len = %u, wr_count = %u, status = %u\r\n", addr, len, wr_count, i2c_state);
|
||||
|
||||
return wr_count;
|
||||
}
|
||||
|
||||
bool Adafruit_USBD_I2C::handleControlTransfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) {
|
||||
uint8_t const cmd = request->bRequest;
|
||||
|
||||
if ( stage == CONTROL_STAGE_SETUP )
|
||||
{
|
||||
switch ( cmd )
|
||||
{
|
||||
case CMD_ECHO:
|
||||
// echo
|
||||
return tud_control_xfer(rhport, request, (void*) &request->wValue, sizeof(request->wValue));
|
||||
|
||||
case CMD_GET_FUNC:
|
||||
// capabilities
|
||||
return tud_control_xfer(rhport, request, (void*) &_functionality, sizeof(_functionality));
|
||||
|
||||
case CMD_SET_DELAY:
|
||||
if ( request->wValue == 0 )
|
||||
{
|
||||
_wire->setClock(115200);
|
||||
}
|
||||
else
|
||||
{
|
||||
int baudrate = 1000000 / request->wValue;
|
||||
if ( baudrate > 400000 ) baudrate = 400000;
|
||||
_wire->setClock(baudrate);
|
||||
}
|
||||
return tud_control_status(rhport, request);
|
||||
|
||||
case CMD_GET_STATUS:
|
||||
return tud_control_xfer(rhport, request, (void*) &_state, sizeof(_state));
|
||||
|
||||
case CMD_I2C_IO:
|
||||
case CMD_I2C_IO | CMD_I2C_IO_BEGIN:
|
||||
case CMD_I2C_IO | CMD_I2C_IO_END:
|
||||
case CMD_I2C_IO | CMD_I2C_IO_BEGIN | CMD_I2C_IO_END:
|
||||
{
|
||||
uint8_t const addr = (uint8_t) request->wIndex;
|
||||
// uint16_t const flags = request->wValue;
|
||||
uint16_t const len = tu_min16(request->wLength, _bufsize);
|
||||
bool const stop_bit = (cmd & CMD_I2C_IO_END) ? true : false;
|
||||
|
||||
if (request->bmRequestType_bit.direction == TUSB_DIR_OUT)
|
||||
{
|
||||
if (len == 0)
|
||||
{
|
||||
// zero write: do it here since there will be no data stage for len = 0
|
||||
i2c_write(addr, _buf, len, stop_bit);
|
||||
}
|
||||
return tud_control_xfer(rhport, request, _buf, len);
|
||||
}else
|
||||
{
|
||||
uint16_t const rd_count = i2c_read(addr, _buf, len, stop_bit);
|
||||
return tud_control_xfer(rhport, request, rd_count ? _buf : NULL, rd_count);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
else if ( stage == CONTROL_STAGE_DATA )
|
||||
{
|
||||
switch ( cmd )
|
||||
{
|
||||
case CMD_I2C_IO:
|
||||
case CMD_I2C_IO | CMD_I2C_IO_BEGIN:
|
||||
case CMD_I2C_IO | CMD_I2C_IO_END:
|
||||
case CMD_I2C_IO | CMD_I2C_IO_BEGIN | CMD_I2C_IO_END:
|
||||
if (request->bmRequestType_bit.direction == TUSB_DIR_OUT)
|
||||
{
|
||||
uint8_t const addr = (uint8_t) request->wIndex;
|
||||
// uint16_t const flags = request->wValue;
|
||||
uint16_t const len = tu_min16(request->wLength, _bufsize);
|
||||
bool const stop_bit = (cmd & CMD_I2C_IO_END) ? true : false;
|
||||
|
||||
i2c_write(addr, _buf, len, stop_bit);
|
||||
}
|
||||
return true;
|
||||
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// CONTROL_STAGE_STATUS
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
107
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/examples/Vendor/i2c_tiny_usb_adapter/Adafruit_USBD_I2C.h
vendored
Normal file
107
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/examples/Vendor/i2c_tiny_usb_adapter/Adafruit_USBD_I2C.h
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Ha Thach (tinyusb.org) for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ADAFRUIT_USBD_I2C_H_
|
||||
#define ADAFRUIT_USBD_I2C_H_
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
#include "Wire.h"
|
||||
|
||||
/* commands from USB, must e.g. match command ids in kernel driver */
|
||||
#define CMD_ECHO 0
|
||||
#define CMD_GET_FUNC 1
|
||||
#define CMD_SET_DELAY 2
|
||||
#define CMD_GET_STATUS 3
|
||||
|
||||
#define CMD_I2C_IO 4
|
||||
#define CMD_I2C_IO_BEGIN (1<<0) // flag for I2C_IO
|
||||
#define CMD_I2C_IO_END (1<<1) // flag for I2C_IO
|
||||
|
||||
/* linux kernel flags */
|
||||
#define I2C_M_TEN 0x10 /* we have a ten bit chip address */
|
||||
#define I2C_M_RD 0x01
|
||||
#define I2C_M_NOSTART 0x4000
|
||||
#define I2C_M_REV_DIR_ADDR 0x2000
|
||||
#define I2C_M_IGNORE_NAK 0x1000
|
||||
#define I2C_M_NO_RD_ACK 0x0800
|
||||
|
||||
/* To determine what functionality is present */
|
||||
#define I2C_FUNC_I2C 0x00000001
|
||||
#define I2C_FUNC_10BIT_ADDR 0x00000002 /* required for I2C_M_TEN */
|
||||
#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* required for I2C_M_IGNORE_NAK etc. */
|
||||
#define I2C_FUNC_SMBUS_PEC 0x00000008
|
||||
#define I2C_FUNC_NOSTART 0x00000010 /* required for I2C_M_NOSTART */
|
||||
#define I2C_FUNC_SLAVE 0x00000020
|
||||
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 or later */
|
||||
#define I2C_FUNC_SMBUS_QUICK 0x00010000
|
||||
#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000
|
||||
#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000
|
||||
#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000
|
||||
#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000
|
||||
#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000
|
||||
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000
|
||||
#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000
|
||||
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 /* required for I2C_M_RECV_LEN */
|
||||
#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
|
||||
#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */
|
||||
#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */
|
||||
#define I2C_FUNC_SMBUS_HOST_NOTIFY 0x10000000 /* SMBus 2.0 or later */
|
||||
|
||||
#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE)
|
||||
#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)
|
||||
#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | I2C_FUNC_SMBUS_WRITE_WORD_DATA)
|
||||
#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA)
|
||||
#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)
|
||||
|
||||
#define I2C_FUNC_SMBUS_EMUL (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | \
|
||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_PEC)
|
||||
|
||||
/* if I2C_M_RECV_LEN is also supported */
|
||||
#define I2C_FUNC_SMBUS_EMUL_ALL (I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL)
|
||||
|
||||
#define I2C_STATUS_IDLE 0
|
||||
#define I2C_STATUS_ACK 1
|
||||
#define I2C_STATUS_NAK 2
|
||||
|
||||
class Adafruit_USBD_I2C : public Adafruit_USBD_Interface {
|
||||
public:
|
||||
Adafruit_USBD_I2C(TwoWire* wire);
|
||||
uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t* buf, uint16_t bufsize);
|
||||
bool begin(uint8_t* buffer, size_t bufsize);
|
||||
|
||||
bool handleControlTransfer(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request);
|
||||
|
||||
private:
|
||||
TwoWire* _wire;
|
||||
uint8_t _state;
|
||||
uint32_t _functionality;
|
||||
uint8_t* _buf;
|
||||
uint16_t _bufsize;
|
||||
|
||||
uint16_t i2c_write(uint8_t addr, uint8_t const* buf, uint16_t len, bool stop_bit);
|
||||
uint16_t i2c_read(uint8_t addr, uint8_t* buf, uint16_t len, bool stop_bit);
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,77 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
#include <Wire.h>
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
#include "Adafruit_USBD_I2C.h"
|
||||
|
||||
/* This sketch demonstrates how to use tinyusb vendor interface to implement
|
||||
* i2c-tiny-usb adapter to use with Linux
|
||||
*
|
||||
* Reference:
|
||||
* - https://github.com/torvalds/linux/blob/master/drivers/i2c/busses/i2c-tiny-usb.c
|
||||
* - https://github.com/harbaum/I2C-Tiny-USB
|
||||
*
|
||||
* Requirement:
|
||||
* - Install i2c-tools with
|
||||
* sudo apt install i2c-tools
|
||||
*
|
||||
* How to test example:
|
||||
* - Compile and flash this sketch on your board with an i2c device, it should enumerated as
|
||||
* ID 1c40:0534 EZPrototypes i2c-tiny-usb interface
|
||||
*
|
||||
* - Run "i2cdetect -l" to find our bus ID e.g
|
||||
* i2c-8 i2c i2c-tiny-usb at bus 003 device 039 I2C adapter
|
||||
*
|
||||
* - Run "i2cdetect -y 8" to scan for on-board device (8 is the above bus ID)
|
||||
* 0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
00: -- -- -- -- -- -- -- --
|
||||
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||
70: -- -- -- -- -- -- -- 77
|
||||
|
||||
- You can then interact with sensor using following commands:
|
||||
i2cget i2cset i2cdump i2ctransfer or using any driver/tools that work on i2c device.
|
||||
|
||||
Adafruit CircuitPython library for PC
|
||||
- You can use run CircuitPython library with Extended Bus to read sensor data.
|
||||
- 'i2c_usb.py' is provided a sample script
|
||||
*/
|
||||
|
||||
static uint8_t i2c_buf[800];
|
||||
|
||||
#define MyWire Wire
|
||||
//#define MyWire Wire1
|
||||
|
||||
Adafruit_USBD_I2C i2c_usb(&MyWire);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// init i2c usb with buffer and size
|
||||
i2c_usb.begin(i2c_buf, sizeof(i2c_buf));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
||||
|
||||
|
||||
// callback from tinyusb
|
||||
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request)
|
||||
{
|
||||
return i2c_usb.handleControlTransfer(rhport, stage, request);
|
||||
}
|
||||
|
18
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/examples/Vendor/i2c_tiny_usb_adapter/i2c_usb.py
vendored
Normal file
18
JumperlessNano/lib/Adafruit_TinyUSB_Arduino/examples/Vendor/i2c_tiny_usb_adapter/i2c_usb.py
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
#! /usr/bin/env python3
|
||||
#
|
||||
# before running, install required libraries:
|
||||
# pip3 install adafruit-extended-bus
|
||||
# pip3 install adafruit-circuitpython-bme280
|
||||
|
||||
import time
|
||||
import adafruit_extended_bus
|
||||
from adafruit_bme280 import basic as adafruit_bme280
|
||||
|
||||
# Run "i2cdetect -l" to find your bus number
|
||||
i2c_usb = adafruit_extended_bus.ExtendedI2C(8)
|
||||
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c_usb)
|
||||
while 1:
|
||||
print("\nTemperature: %0.1f C" % bme280.temperature)
|
||||
print("Humidity: %0.1f %%" % bme280.humidity)
|
||||
print("Pressure: %0.1f hPa" % bme280.pressure)
|
||||
time.sleep(1)
|
@ -0,0 +1,121 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
/* This sketch demonstrates WebUSB as web serial with browser with WebUSB support (e.g Chrome).
|
||||
* After enumerated successfully, Browser will pop-up notification
|
||||
* with URL to landing page, click on it to test
|
||||
* - Click "Connect" and select device, When connected the neopixel LED will change color to Green.
|
||||
* - When received color from browser in format '#RRGGBB', device will change the color of neopixel accordingly
|
||||
*
|
||||
* Note:
|
||||
* - The WebUSB landing page notification is currently disabled in Chrome
|
||||
* on Windows due to Chromium issue 656702 (https://crbug.com/656702). You have to
|
||||
* go to landing page (below) to test
|
||||
*
|
||||
* - On Windows 7 and prior: You need to use Zadig tool to manually bind the
|
||||
* WebUSB interface with the WinUSB driver for Chrome to access. From windows 8 and 10, this
|
||||
* is done automatically by firmware.
|
||||
*/
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
|
||||
// Which pin on the Arduino is connected to the NeoPixels?
|
||||
// On a Trinket or Gemma we suggest changing this to 1
|
||||
// use on-board neopixel PIN_NEOPIXEL if existed
|
||||
#ifndef PIN_NEOPIXEL
|
||||
#define PIN_NEOPIXEL 8
|
||||
#endif
|
||||
|
||||
// How many NeoPixels are attached to the Arduino?
|
||||
// use on-board defined NEOPIXEL_NUM if existed
|
||||
#ifndef NEOPIXEL_NUM
|
||||
#define NEOPIXEL_NUM 10
|
||||
#endif
|
||||
|
||||
// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
|
||||
// Note that for older NeoPixel strips you might need to change the third parameter--see the strandtest
|
||||
// example for more information on possible values.
|
||||
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NEOPIXEL_NUM, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
|
||||
|
||||
// USB WebUSB object
|
||||
Adafruit_USBD_WebUSB usb_web;
|
||||
|
||||
// Landing Page: scheme (0: http, 1: https), url
|
||||
// Page source can be found at https://github.com/hathach/tinyusb-webusb-page/tree/main/webusb-rgb
|
||||
WEBUSB_URL_DEF(landingPage, 1 /*https*/, "example.tinyusb.org/webusb-rgb/index.html");
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
||||
TinyUSB_Device_Init(0);
|
||||
#endif
|
||||
//usb_web.setStringDescriptor("TinyUSB WebUSB");
|
||||
usb_web.setLandingPage(&landingPage);
|
||||
usb_web.setLineStateCallback(line_state_callback);
|
||||
usb_web.begin();
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// This initializes the NeoPixel with RED
|
||||
#ifdef NEOPIXEL_POWER
|
||||
pinMode(NEOPIXEL_POWER, OUTPUT);
|
||||
digitalWrite(NEOPIXEL_POWER, NEOPIXEL_POWER_ON);
|
||||
#endif
|
||||
|
||||
pixels.begin();
|
||||
pixels.setBrightness(50);
|
||||
pixels.fill(0xff0000);
|
||||
pixels.show();
|
||||
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
|
||||
Serial.println("TinyUSB WebUSB RGB example");
|
||||
}
|
||||
|
||||
// convert a hex character to number
|
||||
uint8_t char2num(char c)
|
||||
{
|
||||
if (c >= 'a') return c - 'a' + 10;
|
||||
if (c >= 'A') return c - 'A' + 10;
|
||||
return c - '0';
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Landing Page 7 characters as hex color '#RRGGBB'
|
||||
if (usb_web.available() < 7) return;
|
||||
|
||||
uint8_t input[7];
|
||||
usb_web.readBytes(input, 7);
|
||||
|
||||
// Print to serial for debugging
|
||||
Serial.write(input, 7);
|
||||
Serial.println();
|
||||
|
||||
uint8_t red = 16*char2num(input[1]) + char2num(input[2]);
|
||||
uint8_t green = 16*char2num(input[3]) + char2num(input[4]);
|
||||
uint8_t blue = 16*char2num(input[5]) + char2num(input[6]);
|
||||
|
||||
uint32_t color = (red << 16) | (green << 8) | blue;
|
||||
pixels.fill(color);
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void line_state_callback(bool connected)
|
||||
{
|
||||
// connected = green, disconnected = red
|
||||
pixels.fill(connected ? 0x00ff00 : 0xff0000);
|
||||
pixels.show();
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*********************************************************************
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit and open-source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
MIT license, check LICENSE for more information
|
||||
Copyright (c) 2019 Ha Thach for Adafruit Industries
|
||||
All text above, and the splash screen below must be included in
|
||||
any redistribution
|
||||
*********************************************************************/
|
||||
|
||||
/* This sketch demonstrates WebUSB as web serial with browser with WebUSB support (e.g Chrome).
|
||||
* After enumerated successfully, Browser will pop-up notification
|
||||
* with URL to landing page, click on it to test
|
||||
* - Click "Connect" and select device, When connected the on-board LED will litted up.
|
||||
* - Any charters received from either webusb/Serial will be echo back to webusb and Serial
|
||||
*
|
||||
* Note:
|
||||
* - The WebUSB landing page notification is currently disabled in Chrome
|
||||
* on Windows due to Chromium issue 656702 (https://crbug.com/656702). You have to
|
||||
* go to landing page (below) to test
|
||||
*
|
||||
* - On Windows 7 and prior: You need to use Zadig tool to manually bind the
|
||||
* WebUSB interface with the WinUSB driver for Chrome to access. From windows 8 and 10, this
|
||||
* is done automatically by firmware.
|
||||
*/
|
||||
|
||||
#include "Adafruit_TinyUSB.h"
|
||||
|
||||
// USB WebUSB object
|
||||
Adafruit_USBD_WebUSB usb_web;
|
||||
|
||||
// Landing Page: scheme (0: http, 1: https), url
|
||||
// Page source can be found at https://github.com/hathach/tinyusb-webusb-page/tree/main/webusb-serial
|
||||
WEBUSB_URL_DEF(landingPage, 1 /*https*/, "example.tinyusb.org/webusb-serial/index.html");
|
||||
|
||||
int led_pin = LED_BUILTIN;
|
||||
|
||||
// the setup function runs once when you press reset or power the board
|
||||
void setup()
|
||||
{
|
||||
#if defined(ARDUINO_ARCH_MBED) && defined(ARDUINO_ARCH_RP2040)
|
||||
// Manual begin() is required on core without built-in support for TinyUSB such as mbed rp2040
|
||||
TinyUSB_Device_Init(0);
|
||||
#endif
|
||||
|
||||
pinMode(led_pin, OUTPUT);
|
||||
digitalWrite(led_pin, LOW);
|
||||
|
||||
usb_web.setLandingPage(&landingPage);
|
||||
usb_web.setLineStateCallback(line_state_callback);
|
||||
//usb_web.setStringDescriptor("TinyUSB WebUSB");
|
||||
usb_web.begin();
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// wait until device mounted
|
||||
while( !TinyUSBDevice.mounted() ) delay(1);
|
||||
|
||||
Serial.println("TinyUSB WebUSB Serial example");
|
||||
}
|
||||
|
||||
// function to echo to both Serial and WebUSB
|
||||
void echo_all(uint8_t buf[], uint32_t count)
|
||||
{
|
||||
if (usb_web.connected())
|
||||
{
|
||||
usb_web.write(buf, count);
|
||||
usb_web.flush();
|
||||
}
|
||||
|
||||
if ( Serial )
|
||||
{
|
||||
for(uint32_t i=0; i<count; i++)
|
||||
{
|
||||
Serial.write(buf[i]);
|
||||
if ( buf[i] == '\r' ) Serial.write('\n');
|
||||
}
|
||||
Serial.flush();
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint8_t buf[64];
|
||||
uint32_t count;
|
||||
|
||||
// From Serial to both Serial & webUSB
|
||||
if (Serial.available())
|
||||
{
|
||||
count = Serial.read(buf, 64);
|
||||
echo_all(buf, count);
|
||||
}
|
||||
|
||||
// from WebUSB to both Serial & webUSB
|
||||
if (usb_web.available())
|
||||
{
|
||||
count = usb_web.read(buf, 64);
|
||||
echo_all(buf, count);
|
||||
}
|
||||
}
|
||||
|
||||
void line_state_callback(bool connected)
|
||||
{
|
||||
digitalWrite(led_pin, connected);
|
||||
|
||||
if ( connected )
|
||||
{
|
||||
usb_web.println("WebUSB interface connected !!");
|
||||
usb_web.flush();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user