marius
6 months ago
18 changed files with 3644 additions and 69 deletions
@ -0,0 +1,47 @@ |
|||||||
|
FROM espressif/idf |
||||||
|
|
||||||
|
ARG DEBIAN_FRONTEND=nointeractive |
||||||
|
ARG CONTAINER_USER=esp |
||||||
|
ARG USER_UID=1000 |
||||||
|
ARG USER_GID=$USER_UID |
||||||
|
|
||||||
|
RUN apt-get update \ |
||||||
|
&& apt install -y -q \ |
||||||
|
cmake \ |
||||||
|
git \ |
||||||
|
libglib2.0-0 \ |
||||||
|
libnuma1 \ |
||||||
|
libpixman-1-0 \ |
||||||
|
&& rm -rf /var/lib/apt/lists/* |
||||||
|
|
||||||
|
# QEMU |
||||||
|
ENV QEMU_REL=esp_develop_8.2.0_20240122 |
||||||
|
ENV QEMU_SHA256=e7c72ef5705ad1444d391711088c8717fc89f42e9bf6d1487f9c2a326b8cfa83 |
||||||
|
ENV QEMU_DIST=qemu-xtensa-softmmu-${QEMU_REL}-x86_64-linux-gnu.tar.xz |
||||||
|
ENV QEMU_URL=https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/${QEMU_DIST} |
||||||
|
|
||||||
|
ENV LC_ALL=C.UTF-8 |
||||||
|
ENV LANG=C.UTF-8 |
||||||
|
|
||||||
|
RUN wget --no-verbose ${QEMU_URL} \ |
||||||
|
&& echo "${QEMU_SHA256} *${QEMU_DIST}" | sha256sum --check --strict - \ |
||||||
|
&& tar -xf $QEMU_DIST -C /opt \ |
||||||
|
&& rm ${QEMU_DIST} |
||||||
|
|
||||||
|
ENV PATH=/opt/qemu/bin:${PATH} |
||||||
|
|
||||||
|
RUN groupadd --gid $USER_GID $CONTAINER_USER \ |
||||||
|
&& adduser --uid $USER_UID --gid $USER_GID --disabled-password --gecos "" ${CONTAINER_USER} \ |
||||||
|
&& usermod -a -G root $CONTAINER_USER && usermod -a -G dialout $CONTAINER_USER |
||||||
|
|
||||||
|
RUN chmod -R 775 /opt/esp/python_env/ |
||||||
|
|
||||||
|
USER ${CONTAINER_USER} |
||||||
|
ENV USER=${CONTAINER_USER} |
||||||
|
WORKDIR /home/${CONTAINER_USER} |
||||||
|
|
||||||
|
RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc |
||||||
|
|
||||||
|
ENTRYPOINT [ "/opt/esp/entrypoint.sh" ] |
||||||
|
|
||||||
|
CMD ["/bin/bash", "-c"] |
@ -0,0 +1,45 @@ |
|||||||
|
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: |
||||||
|
// https://github.com/microsoft/vscode-dev-containers/tree/v0.183.0/containers/ubuntu |
||||||
|
{ |
||||||
|
"name": "ESP-IDF QEMU", |
||||||
|
"build": { |
||||||
|
"dockerfile": "Dockerfile" |
||||||
|
}, |
||||||
|
// Add the IDs of extensions you want installed when the container is created |
||||||
|
"workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind", |
||||||
|
/* the path of workspace folder to be opened after container is running |
||||||
|
*/ |
||||||
|
"workspaceFolder": "${localWorkspaceFolder}", |
||||||
|
"mounts": [ |
||||||
|
"source=extensionCache,target=/root/.vscode-server/extensions,type=volume" |
||||||
|
], |
||||||
|
"customizations": { |
||||||
|
"vscode": { |
||||||
|
"settings": { |
||||||
|
"terminal.integrated.defaultProfile.linux": "bash", |
||||||
|
"idf.espIdfPath": "/opt/esp/idf", |
||||||
|
"idf.customExtraPaths": "", |
||||||
|
"idf.pythonBinPath": "/opt/esp/python_env/idf5.3_py3.10_env/bin/python", |
||||||
|
"idf.toolsPath": "/opt/esp", |
||||||
|
"idf.gitPath": "/usr/bin/git" |
||||||
|
}, |
||||||
|
"extensions": [ |
||||||
|
"espressif.esp-idf-extension" |
||||||
|
], |
||||||
|
}, |
||||||
|
"codespaces": { |
||||||
|
"settings": { |
||||||
|
"terminal.integrated.defaultProfile.linux": "bash", |
||||||
|
"idf.espIdfPath": "/opt/esp/idf", |
||||||
|
"idf.customExtraPaths": "", |
||||||
|
"idf.pythonBinPath": "/opt/esp/python_env/idf5.3_py3.10_env/bin/python", |
||||||
|
"idf.toolsPath": "/opt/esp", |
||||||
|
"idf.gitPath": "/usr/bin/git" |
||||||
|
}, |
||||||
|
"extensions": [ |
||||||
|
"espressif.esp-idf-extension" |
||||||
|
], |
||||||
|
} |
||||||
|
}, |
||||||
|
"runArgs": ["--privileged"] |
||||||
|
} |
@ -0,0 +1,4 @@ |
|||||||
|
.pio |
||||||
|
.vscode |
||||||
|
build |
||||||
|
managed_components |
@ -0,0 +1,6 @@ |
|||||||
|
# The following five lines of boilerplate have to be in your project's |
||||||
|
# CMakeLists in this exact order for cmake to work correctly |
||||||
|
cmake_minimum_required(VERSION 3.16) |
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake) |
||||||
|
project(maddius_joy) |
@ -0,0 +1,83 @@ |
|||||||
|
| Supported Targets | ESP32-S2 | ESP32-S3 | |
||||||
|
| ----------------- | -------- | -------- | |
||||||
|
|
||||||
|
# TinyUSB MIDI Device Example |
||||||
|
|
||||||
|
(See the README.md file in the upper level 'examples' directory for more information about examples.) |
||||||
|
|
||||||
|
This example shows how to set up ESP chip to work as a USB MIDI Device. |
||||||
|
It outputs a MIDI note sequence via the native USB port. |
||||||
|
|
||||||
|
As a USB stack, a TinyUSB component is used. |
||||||
|
|
||||||
|
## How to use example |
||||||
|
|
||||||
|
### Hardware Required |
||||||
|
|
||||||
|
Any ESP board that have USB-OTG supported. |
||||||
|
|
||||||
|
#### Pin Assignment |
||||||
|
|
||||||
|
_Note:_ In case your board doesn't have micro-USB connector connected to USB-OTG peripheral, you may have to DIY a cable and connect **D+** and **D-** to the pins listed below. |
||||||
|
|
||||||
|
See common pin assignments for USB Device examples from [upper level](../../README.md#common-pin-assignments). |
||||||
|
|
||||||
|
### Build and Flash |
||||||
|
|
||||||
|
Build the project and flash it to the board, then run monitor tool to view serial output: |
||||||
|
|
||||||
|
```bash |
||||||
|
idf.py -p PORT flash monitor |
||||||
|
``` |
||||||
|
|
||||||
|
(Replace PORT with the name of the serial port to use.) |
||||||
|
|
||||||
|
(To exit the serial monitor, type ``Ctrl-]``.) |
||||||
|
|
||||||
|
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. |
||||||
|
|
||||||
|
## MIDI output |
||||||
|
|
||||||
|
You can use several programs on your computer to listen to the ESP's MIDI output depending on your operating system, e.g.: |
||||||
|
|
||||||
|
* Windows: `MIDI-OX` |
||||||
|
* Linux: `qsynth` with `qjackctl` |
||||||
|
* macOS: `SimpleSynth` |
||||||
|
|
||||||
|
## Example Output |
||||||
|
|
||||||
|
After the flashing you should see the output at idf monitor: |
||||||
|
|
||||||
|
``` |
||||||
|
I (285) example: USB initialization |
||||||
|
I (285) tusb_desc: |
||||||
|
┌─────────────────────────────────┐ |
||||||
|
│ USB Device Descriptor Summary │ |
||||||
|
├───────────────────┬─────────────┤ |
||||||
|
│bDeviceClass │ 0 │ |
||||||
|
├───────────────────┼─────────────┤ |
||||||
|
│bDeviceSubClass │ 0 │ |
||||||
|
├───────────────────┼─────────────┤ |
||||||
|
│bDeviceProtocol │ 0 │ |
||||||
|
├───────────────────┼─────────────┤ |
||||||
|
│bMaxPacketSize0 │ 64 │ |
||||||
|
├───────────────────┼─────────────┤ |
||||||
|
│idVendor │ 0x303a │ |
||||||
|
├───────────────────┼─────────────┤ |
||||||
|
│idProduct │ 0x4008 │ |
||||||
|
├───────────────────┼─────────────┤ |
||||||
|
│bcdDevice │ 0x100 │ |
||||||
|
├───────────────────┼─────────────┤ |
||||||
|
│iManufacturer │ 0x1 │ |
||||||
|
├───────────────────┼─────────────┤ |
||||||
|
│iProduct │ 0x2 │ |
||||||
|
├───────────────────┼─────────────┤ |
||||||
|
│iSerialNumber │ 0x3 │ |
||||||
|
├───────────────────┼─────────────┤ |
||||||
|
│bNumConfigurations │ 0x1 │ |
||||||
|
└───────────────────┴─────────────┘ |
||||||
|
I (455) TinyUSB: TinyUSB Driver installed |
||||||
|
I (465) example: USB initialization DONE |
||||||
|
``` |
||||||
|
|
||||||
|
Disconnect UART-to-USB port and connect the native USB port to a computer then the device should show up as a USB MIDI Device while outputting notes. |
@ -0,0 +1,147 @@ |
|||||||
|
dependencies: |
||||||
|
chmorgan/esp-libhelix-mp3: |
||||||
|
component_hash: cbb76089dc2c5749f7b470e2e70aedc44c9da519e04eb9a67d4c7ec275229e53 |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.0.3 |
||||||
|
espressif/arduino-esp32: |
||||||
|
component_hash: c518a55e52a50d662a7c71202e42a90a64bd2122a08089cbb1f76d925e812afc |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 3.0.1 |
||||||
|
espressif/cbor: |
||||||
|
component_hash: 440f4ee4504841cc9b4f3a8ef755776a612ac9dace355514c68b999868f990ff |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 0.6.0~1 |
||||||
|
espressif/esp-dsp: |
||||||
|
component_hash: 3e7bbd487f1357a1d4944d0c85966d049501ea281b8a4c7f93f7cfedd5b7f23d |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.4.12 |
||||||
|
espressif/esp-sr: |
||||||
|
component_hash: 16af25295f531495fe7e36cf2e8c8bb49629be42c38a56f55f4ded825ada0ffc |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.7.1 |
||||||
|
espressif/esp-zboss-lib: |
||||||
|
component_hash: c7020f631cd4ad25e159ddb812bdc80906b5b424457abc81c9b8b0e92687837a |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.3.2 |
||||||
|
espressif/esp-zigbee-lib: |
||||||
|
component_hash: 752dbc8abb2befd2d49ee902051699fac5e32c6962950d64cd888d75d6566ca0 |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.3.2 |
||||||
|
espressif/esp_diag_data_store: |
||||||
|
component_hash: 8849195251dbb8a2d7268335277cfa310cef36e4ac1e90cd59ad3be4269a30d7 |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.0.1 |
||||||
|
espressif/esp_diagnostics: |
||||||
|
component_hash: 2350938db074002ef088c05cd32d80a528185e47afdb3642427156256c3e13c5 |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.1.0 |
||||||
|
espressif/esp_insights: |
||||||
|
component_hash: 72ece1dcf0146275e1df976c713a9b193af0907931f3810957ee68a0a84b077d |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.1.0 |
||||||
|
espressif/esp_modem: |
||||||
|
component_hash: e48da33fee082dd9d9a97a354a228057e07a14ac108766b40ad84e018205410a |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.1.0 |
||||||
|
espressif/esp_rainmaker: |
||||||
|
component_hash: 232425d1c9b9dbdaa5c109b3e359fba0e6956e35fcf22725f07ed7e4389e1191 |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.1.0 |
||||||
|
espressif/esp_schedule: |
||||||
|
component_hash: 80d3694717a537156f61a072dfe1d1498a2a4f32819a5735bf8a50bcadf79941 |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.1.1 |
||||||
|
espressif/esp_secure_cert_mgr: |
||||||
|
component_hash: a20007d67e65a000670ab77e45d7554c943eb8dcb0abeada0a57dd9adac3a703 |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 2.4.1 |
||||||
|
espressif/esp_tinyusb: |
||||||
|
component_hash: 5e37c53a10518f40b288a48afec4ab549784be9e6eb74add699a30395543418a |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.0.3 |
||||||
|
espressif/jsmn: |
||||||
|
component_hash: d80350c41bbaa827c98a25b6072df00884e72f54885996fab4a4f0aebce6b6c3 |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.1.0 |
||||||
|
espressif/json_generator: |
||||||
|
component_hash: 45033e1c199b13f1c8c1b544fb7d4e2df6a8e3071ebdcb1b22582b61a7974ff2 |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.1.2 |
||||||
|
espressif/json_parser: |
||||||
|
component_hash: d74b81729ad06ec11ff5eb5b1b0d7df1d00e6027fc11471f4b139c70dcf1b1e4 |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.0.3 |
||||||
|
espressif/mdns: |
||||||
|
component_hash: 31117d76cae83a6d83ffd7f035f6fdae5bd05b914fc30b641afeb208b84de19a |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.3.2 |
||||||
|
espressif/qrcode: |
||||||
|
component_hash: 3b493771bc5d6ad30cbf87c25bf784aada8a08c941504355b55d6b75518ed7bc |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 0.1.0~2 |
||||||
|
espressif/rmaker_common: |
||||||
|
component_hash: 021c02465e4996dd3292db36ea47b5e3122e7e2d3514797735a96bc12598b44f |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.4.5 |
||||||
|
espressif/tinyusb: |
||||||
|
component_hash: 256fd8aee92ae9f1014538b8601508907a2da386b64f6d42f35a67f9288d1b20 |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 0.15.0~9 |
||||||
|
idf: |
||||||
|
component_hash: null |
||||||
|
source: |
||||||
|
type: idf |
||||||
|
version: 5.1.4 |
||||||
|
joltwallet/littlefs: |
||||||
|
component_hash: 8373229a6c63ccc08747117cd937b35de5721ba49468e4ca29dad006235e655e |
||||||
|
source: |
||||||
|
service_url: https://api.components.espressif.com/ |
||||||
|
type: service |
||||||
|
version: 1.14.5 |
||||||
|
manifest_hash: 534b60a796c994201c1fe175ee341e4e13962f7a0dcbdbb550f369327daedf28 |
||||||
|
target: esp32s3 |
||||||
|
version: 1.0.0 |
@ -0,0 +1,3 @@ |
|||||||
|
idf_component_register(SRCS "tusb_midi_main.c" "controls.cpp" "ezButton.cpp" |
||||||
|
INCLUDE_DIRS "." |
||||||
|
) |
@ -0,0 +1,282 @@ |
|||||||
|
// #include "Adafruit_Keypad.h"
|
||||||
|
// #include "led_strip_rmt_ws2812.cpp"
|
||||||
|
// #include "ESPRotary.h"
|
||||||
|
#include <Wire.h> // I2C |
||||||
|
#include "driver/gpio.h" |
||||||
|
#include "controls.h" |
||||||
|
#include "tinyusb.h" |
||||||
|
#include <ezButton.h> |
||||||
|
|
||||||
|
#define LED_STRIP_LED_NUMBERS 30 |
||||||
|
#define I2C_INTERRUPT_REQUEST 57 //
|
||||||
|
|
||||||
|
#define ROWS 5 // rows
|
||||||
|
#define COLS 6 // columns
|
||||||
|
|
||||||
|
#define CLICKS_PER_STEP 4 // this number depends on your rotary encoder
|
||||||
|
#define BUTTON_PIN 1 |
||||||
|
|
||||||
|
#define BUTTON_DEBOUNCE 20 |
||||||
|
|
||||||
|
// buttons
|
||||||
|
ezButton button[1] = {{7}}; |
||||||
|
|
||||||
|
// joystick
|
||||||
|
#define BUTTON_PIN2 41 |
||||||
|
#define JOY_X 40 |
||||||
|
#define JOY_Y 39 |
||||||
|
// I2C
|
||||||
|
#define I2C_SDA 37 |
||||||
|
#define I2C_SCL 36 |
||||||
|
|
||||||
|
#define I2C_INTERUPT GPIO_NUM_38 |
||||||
|
|
||||||
|
static const char *TAG = "controls"; |
||||||
|
// #define SERIAL_SPEED 115200
|
||||||
|
|
||||||
|
uint8_t controls[512] = {0}; |
||||||
|
|
||||||
|
// Basic MIDI Messages
|
||||||
|
#define NOTE_OFF 0x80 |
||||||
|
#define NOTE_ON 0x90 |
||||||
|
#define SET_CONTROL 0xB0 |
||||||
|
|
||||||
|
void setControl(uint16_t controlNum, uint8_t value) |
||||||
|
{ |
||||||
|
uint16_t keynum = controlNum; |
||||||
|
bool litValue = false; |
||||||
|
if (value > 0) |
||||||
|
{ |
||||||
|
litValue = true; |
||||||
|
} |
||||||
|
if ((controlNum / 6) % 2 == 1) |
||||||
|
{ |
||||||
|
keynum = controlNum + 5 - (controlNum % 6) * 2; |
||||||
|
} |
||||||
|
ESP_LOGI(TAG, "begin litValue %i ,%i, %i", (controlNum % 6), controlNum, keynum); |
||||||
|
// lit[keynum] = litValue; // invert neopixel status
|
||||||
|
controls[controlNum] = value; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void task_read_all(void *args) |
||||||
|
{ |
||||||
|
// init
|
||||||
|
static uint8_t const cable_num = 0; // MIDI jack associated with USB endpoint
|
||||||
|
static uint8_t const channel = 0; // 0 for channel 1
|
||||||
|
bool changeDetected = false; |
||||||
|
// BUTTON
|
||||||
|
for (int i = 0; i < 1; i++) |
||||||
|
{ |
||||||
|
button[i].setDebounceTime(BUTTON_DEBOUNCE); |
||||||
|
} |
||||||
|
uint8_t buttonLastState[9] = {0, 0, 0, 0, 0, 0, 0, 0}; |
||||||
|
uint8_t buttonNextState[9] = {0, 0, 0, 0, 0, 0, 0, 0}; |
||||||
|
uint8_t buttonExternalState[9] = {0}; |
||||||
|
// FADER
|
||||||
|
ESP_LOGI(TAG, "begin "); |
||||||
|
uint16_t threshold = 250; |
||||||
|
uint16_t speed = 100; |
||||||
|
uint16_t joy_x_init = 0; |
||||||
|
uint16_t joy_y_init = 0; |
||||||
|
uint16_t joy_zoom_init = 0; |
||||||
|
for (int i=0;i<10;i++) |
||||||
|
{ |
||||||
|
joy_x_init += analogRead(4); |
||||||
|
joy_y_init += analogRead(5); |
||||||
|
joy_zoom_init += analogRead(6); |
||||||
|
} |
||||||
|
joy_x_init = joy_x_init/10; |
||||||
|
joy_y_init = joy_y_init/10; |
||||||
|
joy_zoom_init = joy_zoom_init/10; |
||||||
|
ESP_LOGI(TAG, "joy_x_init %i",joy_x_init); |
||||||
|
ESP_LOGI(TAG, "joy_y_init %i",joy_y_init); |
||||||
|
ESP_LOGI(TAG, "joy_zoom_init %i",joy_zoom_init); |
||||||
|
uint16_t joy_x = 0; |
||||||
|
uint16_t joy_y = 0; |
||||||
|
uint16_t joy_zoom = 0; |
||||||
|
int16_t joy_x_dir = 0; |
||||||
|
int16_t joy_y_dir = 0; |
||||||
|
int16_t joy_zoom_dir = 0; |
||||||
|
float joy_float_x = 0; |
||||||
|
float joy_float_y = 0; |
||||||
|
float joy_float_zoom = 0; |
||||||
|
// uint8_t controls[64] = 0;
|
||||||
|
// uint8_t controls[65] = 0;
|
||||||
|
// uint8_t controls[66] = 0;
|
||||||
|
uint8_t faderLastState[3] = {0, 0, 0}; |
||||||
|
for (;;) |
||||||
|
{ |
||||||
|
// BUTTON
|
||||||
|
for (int i = 0; i < 1; i++) |
||||||
|
{ |
||||||
|
// uint8_t buttonValue = digitalRead(buttonPins[i]);
|
||||||
|
// buttonNextState[i] = buttonValue ? 0 : 255;
|
||||||
|
button[i].loop(); |
||||||
|
if (button[i].isPressed()) |
||||||
|
{ |
||||||
|
buttonNextState[i] = 255; |
||||||
|
} |
||||||
|
else if (button[i].isReleased()) |
||||||
|
{ |
||||||
|
buttonNextState[i] = 0; |
||||||
|
} |
||||||
|
// Serial.print("r");
|
||||||
|
// Serial.print(read);
|
||||||
|
// Serial.print(": ");
|
||||||
|
// Serial.println(faderNextState[i]);
|
||||||
|
} |
||||||
|
// JOY
|
||||||
|
if(controls[64] != (uint8_t)round(joy_float_x)){ |
||||||
|
ESP_LOGI(TAG, "joy_float_x = controls[64] %f %i",joy_float_x,controls[64]); |
||||||
|
joy_float_x = controls[64]; |
||||||
|
} |
||||||
|
if(controls[65] != (uint8_t)round(joy_float_y)){ |
||||||
|
joy_float_y = controls[65]; |
||||||
|
} |
||||||
|
|
||||||
|
joy_x = analogRead(4); |
||||||
|
joy_y = analogRead(5); |
||||||
|
|
||||||
|
joy_x_dir = joy_x_init-joy_x; |
||||||
|
joy_y_dir = joy_y_init-joy_y; |
||||||
|
if(abs(joy_x_dir)>threshold){ |
||||||
|
joy_x_dir = joy_x_dir+ (joy_x_dir <0 ? threshold:-threshold); |
||||||
|
// ESP_LOGI(TAG, "joy_x_dir %i",joy_x_dir);
|
||||||
|
joy_float_x = joy_float_x + ((float)joy_x_dir / 900000 * speed); |
||||||
|
if(joy_float_x > 255){ |
||||||
|
joy_float_x = 255; |
||||||
|
} |
||||||
|
if(joy_float_x < 0){ |
||||||
|
joy_float_x = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
if(abs(joy_y_dir)>threshold){ |
||||||
|
joy_y_dir = joy_y_dir+ (joy_y_dir <0 ? threshold:-threshold); |
||||||
|
// ESP_LOGI(TAG, "joy_y_dir %i",joy_y_dir);
|
||||||
|
joy_float_y = joy_float_y + ((float)joy_y_dir / 900000 * speed); |
||||||
|
if(joy_float_y > 255){ |
||||||
|
joy_float_y = 255; |
||||||
|
} |
||||||
|
if(joy_float_y < 0){ |
||||||
|
joy_float_y = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
if(controls[64] != (uint8_t)round(joy_float_x)){ |
||||||
|
controls[64] = (uint8_t)round(joy_float_x); |
||||||
|
ESP_LOGI(TAG, "controls[64] %i",controls[64]); |
||||||
|
uint8_t control[3] = {SET_CONTROL | channel, 64, (uint8_t)(controls[64]>>1)}; |
||||||
|
tud_midi_stream_write(cable_num, control, 3); |
||||||
|
} |
||||||
|
if(controls[65] != (uint8_t)round(joy_float_y)){ |
||||||
|
controls[65] = (uint8_t)round(joy_float_y); |
||||||
|
ESP_LOGI(TAG, "controls[65] %i",controls[65]); |
||||||
|
uint8_t control[3] = {SET_CONTROL | channel, 65, (uint8_t)(controls[65]>>1)}; |
||||||
|
tud_midi_stream_write(cable_num, control, 3); |
||||||
|
} |
||||||
|
|
||||||
|
// ZOOM
|
||||||
|
if(controls[66] != (uint8_t)round(joy_float_zoom)){ |
||||||
|
joy_float_zoom = controls[66]; |
||||||
|
} |
||||||
|
joy_zoom = analogRead(6); |
||||||
|
joy_zoom_dir = joy_zoom_init-joy_zoom; |
||||||
|
if(abs(joy_zoom_dir)>threshold){ |
||||||
|
joy_zoom_dir = joy_zoom_dir+ (joy_zoom_dir <0 ? threshold:-threshold); |
||||||
|
joy_float_zoom = joy_float_zoom + ((float)joy_zoom_dir / 900000 * speed); |
||||||
|
if(joy_float_zoom > 255){ |
||||||
|
joy_float_zoom = 255; |
||||||
|
} |
||||||
|
if(joy_float_zoom < 0){ |
||||||
|
joy_float_zoom = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
if(controls[66] != (uint8_t)round(joy_float_zoom)){ |
||||||
|
controls[66] = (uint8_t)round(joy_float_zoom); |
||||||
|
ESP_LOGI(TAG, "controls[66] %i",controls[66]); |
||||||
|
uint8_t control[3] = {SET_CONTROL | channel, 66, (uint8_t)(controls[66]>>1)}; |
||||||
|
tud_midi_stream_write(cable_num, control, 3); |
||||||
|
} |
||||||
|
// WIRE I2C
|
||||||
|
bool nextChangeDetected = false; |
||||||
|
// better only on change?
|
||||||
|
for (uint8_t i = 0; i < 1; i++) |
||||||
|
{ |
||||||
|
// Buttons
|
||||||
|
if (buttonNextState[i] != buttonLastState[i]) |
||||||
|
{ |
||||||
|
buttonLastState[i] = buttonNextState[i]; |
||||||
|
Serial.print("B"); |
||||||
|
Serial.print(i); |
||||||
|
Serial.print(": "); |
||||||
|
Serial.println(buttonNextState[i]); |
||||||
|
nextChangeDetected = true; |
||||||
|
uint8_t control[3] = {SET_CONTROL | channel, i, 127}; |
||||||
|
ESP_LOGI(TAG, "buttonNextState[%i] %i",i,buttonNextState[i]); |
||||||
|
tud_midi_stream_write(cable_num, control, 3); |
||||||
|
} |
||||||
|
if (buttonLastState[i] == 255 || buttonExternalState[i] == 255) |
||||||
|
{ |
||||||
|
// digitalWrite(ledPins[i], HIGH);
|
||||||
|
|
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
// digitalWrite(ledPins[i], LOW);
|
||||||
|
} |
||||||
|
} |
||||||
|
if (nextChangeDetected && !changeDetected) |
||||||
|
{ |
||||||
|
changeDetected = nextChangeDetected; |
||||||
|
// pinMode(I2C_INTERRUPT_REQUEST, OUTPUT);
|
||||||
|
// resetIRQCount++;
|
||||||
|
} |
||||||
|
else if (!changeDetected) |
||||||
|
{ |
||||||
|
// pinMode(I2C_INTERRUPT_REQUEST, INPUT);
|
||||||
|
} |
||||||
|
|
||||||
|
vTaskDelay(1); |
||||||
|
} |
||||||
|
|
||||||
|
// bool lastAvailable = false;
|
||||||
|
// I2C
|
||||||
|
// Wire.begin(I2C_SDA, I2C_SCL, 400000L);
|
||||||
|
// pinMode(I2C_INTERUPT, INPUT_PULLUP); // i2c available
|
||||||
|
// for (;;)
|
||||||
|
// {
|
||||||
|
// // i2c
|
||||||
|
// bool nextAvailable = gpio_get_level(I2C_INTERUPT) == 0;
|
||||||
|
// if (nextAvailable) // || lastAvailable
|
||||||
|
// {
|
||||||
|
|
||||||
|
// // ESP_LOGI(TAG, "i2cAvailable: %i", i2cAvailable);
|
||||||
|
// // fader9
|
||||||
|
// Wire.requestFrom(55, 18);
|
||||||
|
// while (Wire.available())
|
||||||
|
// { // peripheral may send less than requested
|
||||||
|
// int c = Wire.read(); // receive a byte
|
||||||
|
// ESP_LOGI(TAG, "value: %i", c);
|
||||||
|
// }
|
||||||
|
// // button8
|
||||||
|
// Wire.requestFrom(56, 8);
|
||||||
|
// while (Wire.available())
|
||||||
|
// { // peripheral may send less than requested
|
||||||
|
// int c = Wire.read(); // receive a byte
|
||||||
|
// ESP_LOGI(TAG, "value: %i", c);
|
||||||
|
// }
|
||||||
|
// // lastAvailable = nextAvailable;
|
||||||
|
// }
|
||||||
|
// // task delay time?
|
||||||
|
// vTaskDelay(1);
|
||||||
|
// }
|
||||||
|
} |
||||||
|
|
||||||
|
void init_controls(controls_config *cfg) |
||||||
|
{ |
||||||
|
// ESP_LOGI(TAG, "cfg.matrix_keys.led_io: %i", cfg->matrix_keys.led_io);
|
||||||
|
for (int i = 0; i < 9; i++) |
||||||
|
{ |
||||||
|
button[i].setDebounceTime(BUTTON_DEBOUNCE); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
#include <stdlib.h> |
||||||
|
#ifdef __cplusplus |
||||||
|
extern "C" |
||||||
|
{ |
||||||
|
#endif |
||||||
|
typedef struct |
||||||
|
{ |
||||||
|
uint16_t *row_io; |
||||||
|
uint16_t rows; |
||||||
|
uint16_t *col_io; |
||||||
|
uint16_t cols; |
||||||
|
uint16_t led_io; |
||||||
|
} matrix_keys_config; |
||||||
|
|
||||||
|
typedef struct |
||||||
|
{ |
||||||
|
matrix_keys_config matrix_keys; |
||||||
|
} controls_config; |
||||||
|
|
||||||
|
void setControl(uint16_t controlNum, uint8_t value); |
||||||
|
void task_read_all(void *args); |
||||||
|
void task_led_strip(void *arg); |
||||||
|
void init_controls(controls_config *cfg); |
||||||
|
#ifdef __cplusplus |
||||||
|
} |
||||||
|
#endif |
@ -0,0 +1,127 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, ArduinoGetStarted.com. All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the ArduinoGetStarted.com nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived from |
||||||
|
* this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY ARDUINOGETSTARTED.COM "AS IS" AND ANY EXPRESS OR |
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ARDUINOGETSTARTED.COM BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||||
|
* POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <ezButton.h> |
||||||
|
|
||||||
|
ezButton::ezButton(int pin): ezButton(pin, INPUT_PULLUP) {}; |
||||||
|
|
||||||
|
ezButton::ezButton(int pin, int mode) { |
||||||
|
btnPin = pin; |
||||||
|
debounceTime = 0; |
||||||
|
count = 0; |
||||||
|
countMode = COUNT_FALLING; |
||||||
|
|
||||||
|
pinMode(btnPin, mode); |
||||||
|
|
||||||
|
previousSteadyState = digitalRead(btnPin); |
||||||
|
lastSteadyState = previousSteadyState; |
||||||
|
lastFlickerableState = previousSteadyState; |
||||||
|
|
||||||
|
lastDebounceTime = 0; |
||||||
|
} |
||||||
|
|
||||||
|
void ezButton::setDebounceTime(unsigned long time) { |
||||||
|
debounceTime = time; |
||||||
|
} |
||||||
|
|
||||||
|
int ezButton::getState(void) { |
||||||
|
return lastSteadyState; |
||||||
|
} |
||||||
|
|
||||||
|
int ezButton::getStateRaw(void) { |
||||||
|
return digitalRead(btnPin); |
||||||
|
} |
||||||
|
|
||||||
|
bool ezButton::isPressed(void) { |
||||||
|
if(previousSteadyState == HIGH && lastSteadyState == LOW) |
||||||
|
return true; |
||||||
|
else |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
bool ezButton::isReleased(void) { |
||||||
|
if(previousSteadyState == LOW && lastSteadyState == HIGH) |
||||||
|
return true; |
||||||
|
else |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
void ezButton::setCountMode(int mode) { |
||||||
|
countMode = mode; |
||||||
|
} |
||||||
|
|
||||||
|
unsigned long ezButton::getCount(void) { |
||||||
|
return count; |
||||||
|
} |
||||||
|
|
||||||
|
void ezButton::resetCount(void) { |
||||||
|
count = 0; |
||||||
|
} |
||||||
|
|
||||||
|
void ezButton::loop(void) { |
||||||
|
// read the state of the switch/button:
|
||||||
|
int currentState = digitalRead(btnPin); |
||||||
|
unsigned long currentTime = millis(); |
||||||
|
|
||||||
|
// check to see if you just pressed the button
|
||||||
|
// (i.e. the input went from LOW to HIGH), and you've waited long enough
|
||||||
|
// since the last press to ignore any noise:
|
||||||
|
|
||||||
|
// If the switch/button changed, due to noise or pressing:
|
||||||
|
if (currentState != lastFlickerableState) { |
||||||
|
// reset the debouncing timer
|
||||||
|
lastDebounceTime = currentTime; |
||||||
|
// save the the last flickerable state
|
||||||
|
lastFlickerableState = currentState; |
||||||
|
} |
||||||
|
|
||||||
|
if ((currentTime - lastDebounceTime) >= debounceTime) { |
||||||
|
// whatever the reading is at, it's been there for longer than the debounce
|
||||||
|
// delay, so take it as the actual current state:
|
||||||
|
|
||||||
|
// save the the steady state
|
||||||
|
previousSteadyState = lastSteadyState; |
||||||
|
lastSteadyState = currentState; |
||||||
|
} |
||||||
|
|
||||||
|
if(previousSteadyState != lastSteadyState){ |
||||||
|
if(countMode == COUNT_BOTH) |
||||||
|
count++; |
||||||
|
else if(countMode == COUNT_FALLING){ |
||||||
|
if(previousSteadyState == HIGH && lastSteadyState == LOW) |
||||||
|
count++; |
||||||
|
} |
||||||
|
else if(countMode == COUNT_RISING){ |
||||||
|
if(previousSteadyState == LOW && lastSteadyState == HIGH) |
||||||
|
count++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,69 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, ArduinoGetStarted.com. All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of the ArduinoGetStarted.com nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived from |
||||||
|
* this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY ARDUINOGETSTARTED.COM "AS IS" AND ANY EXPRESS OR |
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ARDUINOGETSTARTED.COM BE LIABLE FOR ANY DIRECT, |
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||||||
|
* POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef ezButton_h |
||||||
|
#define ezButton_h |
||||||
|
|
||||||
|
#include <Arduino.h> |
||||||
|
|
||||||
|
#define COUNT_FALLING 0 |
||||||
|
#define COUNT_RISING 1 |
||||||
|
#define COUNT_BOTH 2 |
||||||
|
|
||||||
|
class ezButton |
||||||
|
{ |
||||||
|
private: |
||||||
|
int btnPin; |
||||||
|
unsigned long debounceTime; |
||||||
|
unsigned long count; |
||||||
|
int countMode; |
||||||
|
|
||||||
|
int previousSteadyState; // the previous steady state from the input pin, used to detect pressed and released event
|
||||||
|
int lastSteadyState; // the last steady state from the input pin
|
||||||
|
int lastFlickerableState; // the last flickerable state from the input pin
|
||||||
|
|
||||||
|
unsigned long lastDebounceTime; // the last time the output pin was toggled
|
||||||
|
|
||||||
|
public: |
||||||
|
ezButton(int pin); |
||||||
|
ezButton(int pin, int mode); |
||||||
|
void setDebounceTime(unsigned long time); |
||||||
|
int getState(void); |
||||||
|
int getStateRaw(void); |
||||||
|
bool isPressed(void); |
||||||
|
bool isReleased(void); |
||||||
|
void setCountMode(int mode); |
||||||
|
unsigned long getCount(void); |
||||||
|
void resetCount(void); |
||||||
|
void loop(void); |
||||||
|
}; |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,5 @@ |
|||||||
|
## IDF Component Manager Manifest File |
||||||
|
dependencies: |
||||||
|
esp_tinyusb: "~1.0.0" |
||||||
|
idf: "^5.1" |
||||||
|
espressif/arduino-esp32: "^3.0.0" |
@ -0,0 +1,174 @@ |
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2019 Ha Thach (tinyusb.org) |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: MIT |
||||||
|
* |
||||||
|
* SPDX-FileContributor: 2022-2023 Espressif Systems (Shanghai) CO LTD |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <stdlib.h> |
||||||
|
#include "esp_log.h" |
||||||
|
#include "freertos/FreeRTOS.h" |
||||||
|
#include "freertos/task.h" |
||||||
|
#include "tinyusb.h" |
||||||
|
#include "esp_timer.h" |
||||||
|
#include "controls.h" |
||||||
|
|
||||||
|
static const char *TAG = "example"; |
||||||
|
|
||||||
|
/** Helper defines **/ |
||||||
|
|
||||||
|
// Interface counter
|
||||||
|
enum interface_count { |
||||||
|
#if CFG_TUD_MIDI |
||||||
|
ITF_NUM_MIDI = 0, |
||||||
|
ITF_NUM_MIDI_STREAMING, |
||||||
|
#endif |
||||||
|
ITF_COUNT |
||||||
|
}; |
||||||
|
|
||||||
|
// USB Endpoint numbers
|
||||||
|
enum usb_endpoints { |
||||||
|
// Available USB Endpoints: 5 IN/OUT EPs and 1 IN EP
|
||||||
|
EP_EMPTY = 0, |
||||||
|
#if CFG_TUD_MIDI |
||||||
|
EPNUM_MIDI, |
||||||
|
#endif |
||||||
|
}; |
||||||
|
|
||||||
|
/** TinyUSB descriptors **/ |
||||||
|
|
||||||
|
#define TUSB_DESCRIPTOR_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_MIDI * TUD_MIDI_DESC_LEN) |
||||||
|
// Basic MIDI Messages
|
||||||
|
#define NOTE_OFF 0x80 |
||||||
|
#define NOTE_ON 0x90 |
||||||
|
#define SET_CONTROL 0xB0 |
||||||
|
/**
|
||||||
|
* @brief String descriptor |
||||||
|
*/ |
||||||
|
static const char* s_str_desc[5] = { |
||||||
|
// array of pointer to string descriptors
|
||||||
|
(char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
|
||||||
|
"TinyUSB", // 1: Manufacturer
|
||||||
|
"TinyUSB Device", // 2: Product
|
||||||
|
"123456", // 3: Serials, should use chip ID
|
||||||
|
"Example MIDI device", // 4: MIDI
|
||||||
|
}; |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configuration descriptor |
||||||
|
* |
||||||
|
* This is a simple configuration descriptor that defines 1 configuration and a MIDI interface |
||||||
|
*/ |
||||||
|
static const uint8_t s_midi_cfg_desc[] = { |
||||||
|
// Configuration number, interface count, string index, total length, attribute, power in mA
|
||||||
|
TUD_CONFIG_DESCRIPTOR(1, ITF_COUNT, 0, TUSB_DESCRIPTOR_TOTAL_LEN, 0, 100), |
||||||
|
|
||||||
|
// Interface number, string index, EP Out & EP In address, EP size
|
||||||
|
TUD_MIDI_DESCRIPTOR(ITF_NUM_MIDI, 4, EPNUM_MIDI, (0x80 | EPNUM_MIDI), 64), |
||||||
|
}; |
||||||
|
|
||||||
|
static void midi_task_read_example(void *arg) |
||||||
|
{ |
||||||
|
// The MIDI interface always creates input and output port/jack descriptors
|
||||||
|
// regardless of these being used or not. Therefore incoming traffic should be read
|
||||||
|
// (possibly just discarded) to avoid the sender blocking in IO
|
||||||
|
uint8_t packet[4]; |
||||||
|
bool read = false; |
||||||
|
for (;;) { |
||||||
|
vTaskDelay(1); |
||||||
|
while (tud_midi_available()) { |
||||||
|
read = tud_midi_packet_read(packet); |
||||||
|
if (read) { |
||||||
|
if(packet[1] == SET_CONTROL){ |
||||||
|
setControl(packet[2], packet[3]<<1); |
||||||
|
ESP_LOGI(TAG, "setControl(packet[2]%i, packet[3]%i<1/%i)", packet[2], packet[3],packet[3]<<1); |
||||||
|
} |
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Read - Time (ms since boot): %lld, Data: %02hhX %02hhX %02hhX %02hhX", |
||||||
|
esp_timer_get_time(), packet[0], packet[1], packet[2], packet[3]); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void periodic_midi_write_example_cb(void *arg) |
||||||
|
{ |
||||||
|
// Example melody stored as an array of note values
|
||||||
|
uint8_t const 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 |
||||||
|
}; |
||||||
|
|
||||||
|
static uint8_t const cable_num = 0; // MIDI jack associated with USB endpoint
|
||||||
|
static uint8_t const channel = 0; // 0 for channel 1
|
||||||
|
static uint32_t note_pos = 0; |
||||||
|
|
||||||
|
// Previous positions in the note sequence.
|
||||||
|
int previous = note_pos - 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.
|
||||||
|
ESP_LOGI(TAG, "Writing MIDI data %d", note_sequence[note_pos]); |
||||||
|
|
||||||
|
if (tud_midi_mounted()) { |
||||||
|
uint8_t note_on[3] = {NOTE_ON | channel, note_sequence[note_pos], 127}; |
||||||
|
tud_midi_stream_write(cable_num, note_on, 3); |
||||||
|
|
||||||
|
// Send Note Off for previous note.
|
||||||
|
uint8_t note_off[3] = {NOTE_OFF | channel, note_sequence[previous], 0}; |
||||||
|
tud_midi_stream_write(cable_num, note_off, 3); |
||||||
|
} |
||||||
|
|
||||||
|
// Increment position
|
||||||
|
note_pos++; |
||||||
|
|
||||||
|
// If we are at the end of the sequence, start over.
|
||||||
|
if (note_pos >= sizeof(note_sequence)) { |
||||||
|
note_pos = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void app_main(void) |
||||||
|
{ |
||||||
|
ESP_LOGI(TAG, "USB initialization"); |
||||||
|
|
||||||
|
tinyusb_config_t const tusb_cfg = { |
||||||
|
.device_descriptor = NULL, // If device_descriptor is NULL, tinyusb_driver_install() will use Kconfig
|
||||||
|
.string_descriptor = s_str_desc, |
||||||
|
|
||||||
|
.external_phy = false, |
||||||
|
.configuration_descriptor = s_midi_cfg_desc, |
||||||
|
}; |
||||||
|
// .string_descriptor_count = sizeof(s_str_desc) / sizeof(s_str_desc[0]),
|
||||||
|
ESP_ERROR_CHECK(tinyusb_driver_install(&tusb_cfg)); |
||||||
|
|
||||||
|
ESP_LOGI(TAG, "USB initialization DONE"); |
||||||
|
|
||||||
|
// // Periodically send MIDI packets
|
||||||
|
// int const tempo = 286;
|
||||||
|
// const esp_timer_create_args_t periodic_midi_args = {
|
||||||
|
// .callback = &periodic_midi_write_example_cb,
|
||||||
|
// /* name is optional, but may help identify the timer when debugging */
|
||||||
|
// .name = "periodic_midi"
|
||||||
|
// };
|
||||||
|
|
||||||
|
// ESP_LOGI(TAG, "MIDI write task init");
|
||||||
|
// esp_timer_handle_t periodic_midi_timer;
|
||||||
|
// ESP_ERROR_CHECK(esp_timer_create(&periodic_midi_args, &periodic_midi_timer));
|
||||||
|
// ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_midi_timer, tempo * 1000));
|
||||||
|
|
||||||
|
// Read recieved MIDI packets
|
||||||
|
ESP_LOGI(TAG, "MIDI read task init"); |
||||||
|
xTaskCreate(midi_task_read_example, "midi_task_read_example", 8 * 1024, NULL, 5, NULL); |
||||||
|
ESP_LOGI(TAG, "read inputs task init"); |
||||||
|
xTaskCreate(task_read_all, "task_read_all", 8 * 1024, NULL, 21, NULL); |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD |
||||||
|
# SPDX-License-Identifier: CC0-1.0 |
||||||
|
import pytest |
||||||
|
from pytest_embedded import Dut |
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.esp32s2 |
||||||
|
@pytest.mark.usb_device |
||||||
|
def test_usb_device_midi_example(dut: Dut) -> None: |
||||||
|
dut.expect_exact('USB initialization DONE') |
||||||
|
dut.expect_exact('MIDI write task init') |
||||||
|
dut.expect_exact('MIDI read task init') |
||||||
|
dut.expect_exact('Writing MIDI data 74') |
@ -0,0 +1 @@ |
|||||||
|
CONFIG_TINYUSB_MIDI_COUNT=1 |
@ -1,69 +0,0 @@ |
|||||||
dependencies: |
|
||||||
chmorgan/esp-libhelix-mp3: |
|
||||||
component_hash: cbb76089dc2c5749f7b470e2e70aedc44c9da519e04eb9a67d4c7ec275229e53 |
|
||||||
source: |
|
||||||
service_url: https://api.components.espressif.com/ |
|
||||||
type: service |
|
||||||
version: 1.0.3 |
|
||||||
espressif/button: |
|
||||||
component_hash: ba2b069cc8d7d485f3d528c5187fd80599144e8d9ef53a883bc09b46cd608aab |
|
||||||
source: |
|
||||||
service_url: https://api.components.espressif.com/ |
|
||||||
type: service |
|
||||||
version: 3.1.3 |
|
||||||
espressif/cmake_utilities: |
|
||||||
component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f |
|
||||||
source: |
|
||||||
service_url: https://api.components.espressif.com/ |
|
||||||
type: service |
|
||||||
version: 0.5.3 |
|
||||||
espressif/esp_tinyusb: |
|
||||||
component_hash: f8682cfddb743297ec1350d7cc52dff6b535c737c60c6a388cdcf2e9dc0eca4b |
|
||||||
source: |
|
||||||
service_url: https://api.components.espressif.com/ |
|
||||||
type: service |
|
||||||
version: 1.4.2~2 |
|
||||||
espressif/esp_websocket_client: |
|
||||||
component_hash: af69df6a85b26a1e129814ba033fd0c704cdf925b114d9bf90f885db1bb3f8a9 |
|
||||||
source: |
|
||||||
service_url: https://api.components.espressif.com/ |
|
||||||
type: service |
|
||||||
version: 1.2.1 |
|
||||||
espressif/jsmn: |
|
||||||
component_hash: d80350c41bbaa827c98a25b6072df00884e72f54885996fab4a4f0aebce6b6c3 |
|
||||||
source: |
|
||||||
service_url: https://api.components.espressif.com/ |
|
||||||
type: service |
|
||||||
version: 1.1.0 |
|
||||||
espressif/json_parser: |
|
||||||
component_hash: d74b81729ad06ec11ff5eb5b1b0d7df1d00e6027fc11471f4b139c70dcf1b1e4 |
|
||||||
source: |
|
||||||
service_url: https://api.components.espressif.com/ |
|
||||||
type: service |
|
||||||
version: 1.0.3 |
|
||||||
espressif/led_strip: |
|
||||||
component_hash: ed1d5c6113fa545e20c7be17e6e7c09d43b18fcb43068e2b2b27a412de6a405a |
|
||||||
source: |
|
||||||
service_url: https://api.components.espressif.com/ |
|
||||||
type: service |
|
||||||
version: 2.5.2 |
|
||||||
espressif/mdns: |
|
||||||
component_hash: 810ec139689ae93bf42520d05de4855fbb68f7140ef67797d91d8d61829589cb |
|
||||||
source: |
|
||||||
service_url: https://api.components.espressif.com/ |
|
||||||
type: service |
|
||||||
version: 1.2.2 |
|
||||||
espressif/tinyusb: |
|
||||||
component_hash: 632ddbd9c73bee5005e7684eed3142649a08d1f304dbe42abed8110b7384e2c2 |
|
||||||
source: |
|
||||||
service_url: https://api.components.espressif.com/ |
|
||||||
type: service |
|
||||||
version: 0.15.0~3 |
|
||||||
idf: |
|
||||||
component_hash: null |
|
||||||
source: |
|
||||||
type: idf |
|
||||||
version: 5.1.2 |
|
||||||
manifest_hash: 4ed6e24795a74233b024b7c04a08daf95687434889ce45bc5fc86b8074fae5f6 |
|
||||||
target: esp32s3 |
|
||||||
version: 1.0.0 |
|
@ -0,0 +1,218 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!DOCTYPE Workspace> |
||||||
|
<Workspace xmlns="http://www.qlcplus.org/Workspace" CurrentWindow="InputOutputManager"> |
||||||
|
<Creator> |
||||||
|
<Name>Q Light Controller Plus</Name> |
||||||
|
<Version>4.12.7</Version> |
||||||
|
<Author>maxei</Author> |
||||||
|
</Creator> |
||||||
|
<Engine> |
||||||
|
<InputOutputMap> |
||||||
|
<Universe Name="Universe 1" ID="0"> |
||||||
|
<Input Plugin="OSC" UID="169.254.14.165" Line="1" Profile="Maddius JOY"/> |
||||||
|
<Output Plugin="ArtNet" UID="169.254.14.165" Line="1"/> |
||||||
|
</Universe> |
||||||
|
<Universe Name="Universe 2" ID="1"/> |
||||||
|
<Universe Name="Universe 3" ID="2"/> |
||||||
|
<Universe Name="Universe 4" ID="3"> |
||||||
|
<Input Plugin="MIDI" UID="Example MIDI device" Line="0" Profile="Maddius JOY"/> |
||||||
|
<Feedback Plugin="MIDI" UID="Example MIDI device" Line="1"/> |
||||||
|
</Universe> |
||||||
|
</InputOutputMap> |
||||||
|
<Fixture> |
||||||
|
<Manufacturer>Varytec</Manufacturer> |
||||||
|
<Model>BAT.PAR 6 RGBUV</Model> |
||||||
|
<Mode>1 channel</Mode> |
||||||
|
<ID>0</ID> |
||||||
|
<Name>BAT.PAR 6 RGBUV</Name> |
||||||
|
<Universe>0</Universe> |
||||||
|
<Address>0</Address> |
||||||
|
<Channels>1</Channels> |
||||||
|
</Fixture> |
||||||
|
<Fixture> |
||||||
|
<Manufacturer>UKing</Manufacturer> |
||||||
|
<Model>LED Spot Moving Head 100W</Model> |
||||||
|
<Mode>9 Channel</Mode> |
||||||
|
<ID>1</ID> |
||||||
|
<Name>moving</Name> |
||||||
|
<Universe>0</Universe> |
||||||
|
<Address>1</Address> |
||||||
|
<Channels>9</Channels> |
||||||
|
</Fixture> |
||||||
|
<Function ID="0" Type="RGBMatrix" Name="Neue RGB Matrix 0"> |
||||||
|
<Speed FadeIn="0" FadeOut="0" Duration="500"/> |
||||||
|
<Direction>Forward</Direction> |
||||||
|
<RunOrder>Loop</RunOrder> |
||||||
|
<Algorithm Type="Script">Stripes</Algorithm> |
||||||
|
<MonoColor>4294901760</MonoColor> |
||||||
|
<ControlMode>RGB</ControlMode> |
||||||
|
<FixtureGroup>4294967295</FixtureGroup> |
||||||
|
</Function> |
||||||
|
<Function ID="1" Type="EFX" Name="Neuer Effekt 1"> |
||||||
|
<PropagationMode>Parallel</PropagationMode> |
||||||
|
<Speed FadeIn="0" FadeOut="0" Duration="20000"/> |
||||||
|
<Direction>Forward</Direction> |
||||||
|
<RunOrder>Loop</RunOrder> |
||||||
|
<Algorithm>Circle</Algorithm> |
||||||
|
<Width>127</Width> |
||||||
|
<Height>127</Height> |
||||||
|
<Rotation>0</Rotation> |
||||||
|
<StartOffset>0</StartOffset> |
||||||
|
<IsRelative>0</IsRelative> |
||||||
|
<Axis Name="X"> |
||||||
|
<Offset>127</Offset> |
||||||
|
<Frequency>2</Frequency> |
||||||
|
<Phase>90</Phase> |
||||||
|
</Axis> |
||||||
|
<Axis Name="Y"> |
||||||
|
<Offset>127</Offset> |
||||||
|
<Frequency>3</Frequency> |
||||||
|
<Phase>0</Phase> |
||||||
|
</Axis> |
||||||
|
</Function> |
||||||
|
<Function ID="2" Type="Scene" Name="Neue Szene 2"> |
||||||
|
<Speed FadeIn="0" FadeOut="0" Duration="0"/> |
||||||
|
<FixtureVal ID="0">0,179</FixtureVal> |
||||||
|
</Function> |
||||||
|
<Function ID="3" Type="Script" Name="Neues Skript 3"> |
||||||
|
<Speed FadeIn="0" FadeOut="0" Duration="0"/> |
||||||
|
<Direction>Forward</Direction> |
||||||
|
<RunOrder>Loop</RunOrder> |
||||||
|
</Function> |
||||||
|
<Function ID="4" Type="Scene" Name="Neue Szene 4"> |
||||||
|
<Speed FadeIn="0" FadeOut="0" Duration="0"/> |
||||||
|
<FixtureVal ID="0">0,52</FixtureVal> |
||||||
|
</Function> |
||||||
|
<Function ID="5" Type="Scene" Name="New Scene" Hidden="True"> |
||||||
|
<Speed FadeIn="0" FadeOut="0" Duration="0"/> |
||||||
|
</Function> |
||||||
|
<Function ID="6" Type="Sequence" Name="Neue Sequenz 6" BoundScene="5"> |
||||||
|
<Speed FadeIn="0" FadeOut="0" Duration="0"/> |
||||||
|
<Direction>Forward</Direction> |
||||||
|
<RunOrder>Loop</RunOrder> |
||||||
|
<SpeedModes FadeIn="Default" FadeOut="Default" Duration="Common"/> |
||||||
|
<Step Number="0" FadeIn="0" Hold="0" FadeOut="0" Values="0"/> |
||||||
|
<Step Number="1" FadeIn="0" Hold="0" FadeOut="0" Values="0"/> |
||||||
|
</Function> |
||||||
|
<Function ID="7" Type="Chaser" Name="Neuer Chaser 7"> |
||||||
|
<Speed FadeIn="0" FadeOut="0" Duration="100000"/> |
||||||
|
<Direction>Forward</Direction> |
||||||
|
<RunOrder>Loop</RunOrder> |
||||||
|
<SpeedModes FadeIn="Default" FadeOut="Default" Duration="Common"/> |
||||||
|
<Step Number="0" FadeIn="0" Hold="0" FadeOut="0">2</Step> |
||||||
|
<Step Number="1" FadeIn="0" Hold="0" FadeOut="0">4</Step> |
||||||
|
</Function> |
||||||
|
</Engine> |
||||||
|
<VirtualConsole> |
||||||
|
<Frame Caption=""> |
||||||
|
<Appearance> |
||||||
|
<FrameStyle>None</FrameStyle> |
||||||
|
<ForegroundColor>Default</ForegroundColor> |
||||||
|
<BackgroundColor>Default</BackgroundColor> |
||||||
|
<BackgroundImage>None</BackgroundImage> |
||||||
|
<Font>Default</Font> |
||||||
|
</Appearance> |
||||||
|
<Button Caption="Schalter 0" ID="0" Icon=""> |
||||||
|
<WindowState Visible="False" X="290" Y="160" Width="50" Height="50"/> |
||||||
|
<Appearance> |
||||||
|
<FrameStyle>None</FrameStyle> |
||||||
|
<ForegroundColor>Default</ForegroundColor> |
||||||
|
<BackgroundColor>Default</BackgroundColor> |
||||||
|
<BackgroundImage>None</BackgroundImage> |
||||||
|
<Font>Default</Font> |
||||||
|
</Appearance> |
||||||
|
<Function ID="4294967295"/> |
||||||
|
<Action>Toggle</Action> |
||||||
|
<Intensity Adjust="False">100</Intensity> |
||||||
|
</Button> |
||||||
|
<Frame Caption="" ID="1"> |
||||||
|
<Appearance> |
||||||
|
<FrameStyle>Sunken</FrameStyle> |
||||||
|
<ForegroundColor>Default</ForegroundColor> |
||||||
|
<BackgroundColor>Default</BackgroundColor> |
||||||
|
<BackgroundImage>None</BackgroundImage> |
||||||
|
<Font>Default</Font> |
||||||
|
</Appearance> |
||||||
|
<WindowState Visible="False" X="475" Y="140" Width="845" Height="665"/> |
||||||
|
<AllowChildren>True</AllowChildren> |
||||||
|
<AllowResize>True</AllowResize> |
||||||
|
<ShowHeader>True</ShowHeader> |
||||||
|
<ShowEnableButton>True</ShowEnableButton> |
||||||
|
<Collapsed>False</Collapsed> |
||||||
|
<Disabled>False</Disabled> |
||||||
|
<Button Caption="Neue RGB Matrix 0" ID="2" Icon=""> |
||||||
|
<WindowState Visible="False" X="45" Y="95" Width="50" Height="50"/> |
||||||
|
<Appearance> |
||||||
|
<FrameStyle>None</FrameStyle> |
||||||
|
<ForegroundColor>Default</ForegroundColor> |
||||||
|
<BackgroundColor>Default</BackgroundColor> |
||||||
|
<BackgroundImage>None</BackgroundImage> |
||||||
|
<Font>Default</Font> |
||||||
|
</Appearance> |
||||||
|
<Function ID="4"/> |
||||||
|
<Action>Toggle</Action> |
||||||
|
<Intensity Adjust="False">100</Intensity> |
||||||
|
<Input Universe="3" Channel="0"/> |
||||||
|
</Button> |
||||||
|
<XYPad Caption="XY Pad" ID="3" InvertedAppearance="0"> |
||||||
|
<WindowState Visible="False" X="165" Y="140" Width="230" Height="230"/> |
||||||
|
<Appearance> |
||||||
|
<FrameStyle>Sunken</FrameStyle> |
||||||
|
<ForegroundColor>Default</ForegroundColor> |
||||||
|
<BackgroundColor>Default</BackgroundColor> |
||||||
|
<BackgroundImage>None</BackgroundImage> |
||||||
|
<Font>Default</Font> |
||||||
|
</Appearance> |
||||||
|
<Pan Position="114"> |
||||||
|
<Input Universe="3" Channel="64"/> |
||||||
|
</Pan> |
||||||
|
<Tilt Position="162"> |
||||||
|
<Input Universe="3" Channel="65"/> |
||||||
|
</Tilt> |
||||||
|
</XYPad> |
||||||
|
<Slider Caption="Schieberegler 4" ID="4" WidgetStyle="Slider" InvertedAppearance="false"> |
||||||
|
<WindowState Visible="False" X="435" Y="140" Width="85" Height="230"/> |
||||||
|
<Appearance> |
||||||
|
<FrameStyle>Sunken</FrameStyle> |
||||||
|
<ForegroundColor>Default</ForegroundColor> |
||||||
|
<BackgroundColor>Default</BackgroundColor> |
||||||
|
<BackgroundImage>None</BackgroundImage> |
||||||
|
<Font>Default</Font> |
||||||
|
</Appearance> |
||||||
|
<Input Universe="3" Channel="66"/> |
||||||
|
<SliderMode ValueDisplayStyle="Exact" ClickAndGoType="None">Playback</SliderMode> |
||||||
|
<Level LowLimit="0" HighLimit="255" Value="0"/> |
||||||
|
<Playback> |
||||||
|
<Function>4294967295</Function> |
||||||
|
</Playback> |
||||||
|
</Slider> |
||||||
|
<CueList Caption="Cue-Liste" ID="5"> |
||||||
|
<WindowState Visible="False" X="245" Y="395" Width="300" Height="220"/> |
||||||
|
<Appearance> |
||||||
|
<FrameStyle>Sunken</FrameStyle> |
||||||
|
<ForegroundColor>Default</ForegroundColor> |
||||||
|
<BackgroundColor>Default</BackgroundColor> |
||||||
|
<BackgroundImage>None</BackgroundImage> |
||||||
|
<Font>Default</Font> |
||||||
|
</Appearance> |
||||||
|
<Chaser>7</Chaser> |
||||||
|
<NextPrevBehavior>3</NextPrevBehavior> |
||||||
|
<Next> |
||||||
|
<Input Universe="3" Channel="0"/> |
||||||
|
</Next> |
||||||
|
<Previous/> |
||||||
|
<Playback/> |
||||||
|
<Stop/> |
||||||
|
<SlidersMode>Steps</SlidersMode> |
||||||
|
</CueList> |
||||||
|
</Frame> |
||||||
|
</Frame> |
||||||
|
<Properties> |
||||||
|
<Size Width="1920" Height="1080"/> |
||||||
|
<GrandMaster ChannelMode="Intensity" ValueMode="Reduce" SliderMode="Normal"/> |
||||||
|
</Properties> |
||||||
|
</VirtualConsole> |
||||||
|
<SimpleDesk> |
||||||
|
<Engine/> |
||||||
|
</SimpleDesk> |
||||||
|
</Workspace> |
Loading…
Reference in new issue