diff --git a/data/blueboard4.cfg b/data/blueboard4.cfg new file mode 100644 index 0000000..13bb029 --- /dev/null +++ b/data/blueboard4.cfg @@ -0,0 +1 @@ +{"Pedals":[{"Pedal":1,"Mode":"Momentary 1","InvertPolarity":false,"PressMode":"1","LatchEmulation":true,"AnalogResponse":"Linear","Min":0,"Max":127,"Easing":0.001,"ActivityThreshold":32,"AutoSensing":false},{"Pedal":2,"Mode":"Momentary 1","InvertPolarity":false,"PressMode":"1","LatchEmulation":true,"AnalogResponse":"Linear","Min":0,"Max":127,"Easing":0.001,"ActivityThreshold":32,"AutoSensing":false},{"Pedal":3,"Mode":"Momentary 1","InvertPolarity":false,"PressMode":"1","LatchEmulation":true,"AnalogResponse":"Linear","Min":0,"Max":127,"Easing":0.001,"ActivityThreshold":32,"AutoSensing":false},{"Pedal":4,"Mode":"Momentary 1","InvertPolarity":false,"PressMode":"1","LatchEmulation":true,"AnalogResponse":"Linear","Min":0,"Max":127,"Easing":0.001,"ActivityThreshold":32,"AutoSensing":false},{"Pedal":5,"Mode":"None","InvertPolarity":false,"PressMode":"None","LatchEmulation":false,"AnalogResponse":"Linear","Min":0,"Max":1023,"Easing":0.001,"ActivityThreshold":2,"AutoSensing":false},{"Pedal":6,"Mode":"None","InvertPolarity":false,"PressMode":"None","LatchEmulation":false,"AnalogResponse":"Linear","Min":1023,"Max":0,"Easing":0.01,"ActivityThreshold":8,"AutoSensing":true},{"Pedal":7,"Mode":"Momentary 1","InvertPolarity":false,"PressMode":"1","LatchEmulation":false,"AnalogResponse":"Linear","Min":0,"Max":127,"Easing":0.001,"ActivityThreshold":32,"AutoSensing":false},{"Pedal":8,"Mode":"Momentary 1","InvertPolarity":false,"PressMode":"12L","LatchEmulation":false,"AnalogResponse":"Linear","Min":0,"Max":127,"Easing":0.001,"ActivityThreshold":32,"AutoSensing":false}],"Controls":[{"Control":1,"Pedal1":1,"Button1":1,"Pedal2":0,"Button2":0,"Led":7},{"Control":2,"Pedal1":2,"Button1":1,"Pedal2":0,"Button2":0,"Led":5},{"Control":3,"Pedal1":3,"Button1":1,"Pedal2":0,"Button2":0,"Led":3},{"Control":4,"Pedal1":4,"Button1":1,"Pedal2":0,"Button2":0,"Led":1},{"Control":5,"Pedal1":5,"Button1":1,"Pedal2":0,"Button2":0,"Led":7},{"Control":6,"Pedal1":6,"Button1":1,"Pedal2":0,"Button2":0,"Led":8},{"Control":37,"Pedal1":7,"Button1":1,"Pedal2":0,"Button2":0,"Led":0},{"Control":38,"Pedal1":8,"Button1":1,"Pedal2":0,"Button2":0,"Led":0}],"BankNames":[{"Bank":0,"Name":"Global"},{"Bank":1,"Name":":Mode 1"},{"Bank":2,"Name":":Mode 2"},{"Bank":3,"Name":""},{"Bank":4,"Name":""},{"Bank":5,"Name":""},{"Bank":6,"Name":""},{"Bank":7,"Name":""},{"Bank":8,"Name":""},{"Bank":9,"Name":""},{"Bank":10,"Name":""},{"Bank":11,"Name":""},{"Bank":12,"Name":""},{"Bank":13,"Name":""},{"Bank":14,"Name":""},{"Bank":15,"Name":""},{"Bank":16,"Name":""},{"Bank":17,"Name":""},{"Bank":18,"Name":""},{"Bank":19,"Name":""},{"Bank":20,"Name":""}],"Actions":[{"Bank":0,"Control":37,"Led":255,"Color0":"#000000","Color1":"#000000","NameOff":"","NameOn":"","Slot":0,"Event":"Press","Message":"Bank+","Channel":1,"Code":0,"Value1":1,"Value2":2,"OSCAddress":""},{"Bank":0,"Control":38,"Led":255,"Color0":"#000000","Color1":"#000000","NameOff":"","NameOn":"","Slot":0,"Event":"Click","Message":"Profile+","Channel":1,"Code":0,"Value1":1,"Value2":3,"OSCAddress":""},{"Bank":0,"Control":38,"Led":255,"Color0":"#000000","Color1":"#000000","NameOff":"","NameOn":"","Slot":0,"Event":"Double Click","Message":"Power On/Off","Channel":1,"Code":0,"Value1":0,"Value2":0,"OSCAddress":""},{"Bank":0,"Control":38,"Led":255,"Color0":"#000000","Color1":"#000000","NameOff":"","NameOn":"","Slot":0,"Event":"Long Press","Message":"Device Info","Channel":1,"Code":0,"Value1":0,"Value2":0,"OSCAddress":""},{"Bank":1,"Control":1,"Led":255,"Color0":"#000000","Color1":"#0433ff","NameOff":"","NameOn":"[ A ]","Slot":0,"Event":"Press","Message":"Note On","Channel":1,"Code":60,"Value1":0,"Value2":100,"OSCAddress":""},{"Bank":1,"Control":1,"Led":255,"Color0":"#000000","Color1":"#000000","NameOff":"> A <","NameOn":"","Slot":0,"Event":"Release","Message":"Note Off","Channel":1,"Code":60,"Value1":0,"Value2":0,"OSCAddress":""},{"Bank":1,"Control":2,"Led":255,"Color0":"#000000","Color1":"#0433ff","NameOff":"","NameOn":"[ B ]","Slot":2,"Event":"Press","Message":"Note On","Channel":1,"Code":62,"Value1":0,"Value2":100,"OSCAddress":""},{"Bank":1,"Control":2,"Led":255,"Color0":"#000000","Color1":"#000000","NameOff":"> B <","NameOn":"","Slot":2,"Event":"Release","Message":"Note Off","Channel":1,"Code":62,"Value1":0,"Value2":0,"OSCAddress":""},{"Bank":1,"Control":3,"Led":255,"Color0":"#000000","Color1":"#0433ff","NameOff":"","NameOn":"[ C ]","Slot":3,"Event":"Press","Message":"Note On","Channel":1,"Code":64,"Value1":0,"Value2":100,"OSCAddress":""},{"Bank":1,"Control":3,"Led":255,"Color0":"#000000","Color1":"#000000","NameOff":"> C <","NameOn":"","Slot":3,"Event":"Release","Message":"Note Off","Channel":1,"Code":64,"Value1":0,"Value2":0,"OSCAddress":""},{"Bank":1,"Control":4,"Led":255,"Color0":"#000000","Color1":"#0433ff","NameOff":"","NameOn":"[ D ]","Slot":5,"Event":"Press","Message":"Note On","Channel":1,"Code":65,"Value1":0,"Value2":100,"OSCAddress":""},{"Bank":1,"Control":4,"Led":255,"Color0":"#000000","Color1":"#000000","NameOff":"> D <","NameOn":"","Slot":5,"Event":"Release","Message":"Note Off","Channel":1,"Code":65,"Value1":0,"Value2":0,"OSCAddress":""},{"Bank":2,"Control":1,"Led":255,"Color0":"#000000","Color1":"#0433ff","NameOff":"","NameOn":"[ A ]","Slot":0,"Event":"Press","Message":"Control Change","Channel":1,"Code":20,"Value1":0,"Value2":127,"OSCAddress":""},{"Bank":2,"Control":1,"Led":255,"Color0":"#000000","Color1":"#000000","NameOff":"> A <","NameOn":"","Slot":0,"Event":"Release","Message":"Control Change","Channel":1,"Code":20,"Value1":0,"Value2":0,"OSCAddress":""},{"Bank":2,"Control":2,"Led":255,"Color0":"#000000","Color1":"#0433ff","NameOff":"","NameOn":"[ B ]","Slot":2,"Event":"Press","Message":"Control Change","Channel":1,"Code":21,"Value1":0,"Value2":127,"OSCAddress":""},{"Bank":2,"Control":2,"Led":255,"Color0":"#000000","Color1":"#000000","NameOff":"> B <","NameOn":"","Slot":2,"Event":"Release","Message":"Control Change","Channel":1,"Code":21,"Value1":0,"Value2":0,"OSCAddress":""},{"Bank":2,"Control":3,"Led":255,"Color0":"#000000","Color1":"#0433ff","NameOff":"","NameOn":"[ C ]","Slot":3,"Event":"Press","Message":"Control Change","Channel":1,"Code":22,"Value1":0,"Value2":0,"OSCAddress":""},{"Bank":2,"Control":3,"Led":255,"Color0":"#000000","Color1":"#000000","NameOff":"> C <","NameOn":"","Slot":3,"Event":"Release","Message":"Control Change","Channel":1,"Code":22,"Value1":127,"Value2":0,"OSCAddress":""},{"Bank":2,"Control":4,"Led":255,"Color0":"#000000","Color1":"#0433ff","NameOff":"","NameOn":"[ D ]","Slot":5,"Event":"Press","Message":"Control Change","Channel":1,"Code":23,"Value1":0,"Value2":0,"OSCAddress":""},{"Bank":2,"Control":4,"Led":255,"Color0":"#000000","Color1":"#000000","NameOff":"> D <","NameOn":"","Slot":5,"Event":"Release","Message":"Control Change","Channel":1,"Code":23,"Value1":127,"Value2":0,"OSCAddress":""}]} \ No newline at end of file diff --git a/data/css/bootstrap.min.css.gz b/data/css/bootstrap.min.css.gz index cc414b5..07c2e9b 100644 Binary files a/data/css/bootstrap.min.css.gz and b/data/css/bootstrap.min.css.gz differ diff --git a/data/js/Sortable.min.js.gz b/data/js/Sortable.min.js.gz index a232093..b5ea6f4 100644 Binary files a/data/js/Sortable.min.js.gz and b/data/js/Sortable.min.js.gz differ diff --git a/data/js/bootstrap.bundle.min.js.gz b/data/js/bootstrap.bundle.min.js.gz index 87346fb..df2c92b 100644 Binary files a/data/js/bootstrap.bundle.min.js.gz and b/data/js/bootstrap.bundle.min.js.gz differ diff --git a/data/schema.json b/data/schema.json index 5eaabed..4ba8210 100644 --- a/data/schema.json +++ b/data/schema.json @@ -274,7 +274,7 @@ }, "Channel": { "type": "integer", - "enum": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] + "enum": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] }, "Code": { "type": "integer", @@ -412,7 +412,7 @@ }, "Mode": { "type": "string", - "enum": ["None", "Momentary 1", "Latch", "Analog", "Jog Wheel", "Momentary 2","Momentary 3", "Latch 2", "Ladder", "Ultrasonic", "Analog+Momentary", "Analog+Latch", "Analog Pad", "Analog Pad+Momentary"] + "enum": ["None", "Momentary 1", "Latch", "Analog", "Jog Wheel", "Momentary 2","Momentary 3", "Latch 2", "Ladder", "Ultrasonic", "Analog+Momentary", "Analog+Latch", "Analog Pad", "Analog Pad+Momentary", "Analog 4"] }, "InvertPolarity": { "type": "boolean" diff --git a/esp32_platform_version.py b/esp32_platform_version.py new file mode 100644 index 0000000..0a0583b --- /dev/null +++ b/esp32_platform_version.py @@ -0,0 +1,16 @@ +import subprocess + +def get_platform_version(): + result = subprocess.run(['pio', 'pkg', 'show', 'espressif32'], stdout=subprocess.PIPE) + output = result.stdout.decode() + for line in output.splitlines(): + if "Platform" in line: + return line.split()[2] + +Import("env") + +platform_version = get_platform_version() +print(f"ESP32 Platform Version: {platform_version}") + +# Pass the version to the compiler +env.Append(CPPDEFINES=[("ESP32_PLATFORM_VERSION", f'"{platform_version}"')]) \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 7bda0fd..7cbb851 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,24 +13,27 @@ workspace_dir = ${sysenv.TMPDIR}/PedalinoMini [common] lib_deps = - bxparks/AceButton@^1.10.1 ; https://github.com/bxparks/AceButton - bblanchon/ArduinoJson@^6.21.5 ; https://github.com/bblanchon/ArduinoJson - me-no-dev/AsyncTCP@^1.1.1 ; https://github.com/me-no-dev/AsyncTCP + bxparks/AceButton@1.10.1 ; https://github.com/bxparks/AceButton + bblanchon/ArduinoJson@7.2.0 ; https://github.com/bblanchon/ArduinoJson +; me-no-dev/AsyncTCP@1.1.1 ; https://github.com/me-no-dev/AsyncTCP ; https://github.com/me-no-dev/ESPAsyncWebServer.git ; https://github.com/me-no-dev/ESPAsyncWebServer - ESPAsyncWebServer-esphome@^3.1.0 ; https://github.com/esphome/ESPAsyncWebServer/ - fastled/FastLED@^3.6.0 ; https://github.com/FastLED/FastLED - d03n3rfr1tz3/HC-SR04@^1.1.2 ; https://github.com/d03n3rfr1tz3/HC-SR04 - esphome/Improv@^1.2.3 ; https://github.com/improv-wifi/sdk-cpp - majicdesigns/MD_REncoder@^1.0.1 ; https://github.com/MajicDesigns/MD_REncoder - h2zero/NimBLE-Arduino@^1.4.1 ; https://github.com/h2zero/NimBLE-Arduino - https://github.com/CNMAT/OSC@^1.3.7 ; https://github.com/CNMAT/OSC - dxinteractive/ResponsiveAnalogRead@^1.2.1 ; https://github.com/dxinteractive/ResponsiveAnalogRead + esphome/AsyncTCP-esphome@2.1.4 ; https://github.com/esphome/AsyncTCP + esphome/ESPAsyncWebServer-esphome@3.2.2 ; https://github.com/esphome/ESPAsyncWebServer + fastled/FastLED@3.7.4 ; https://github.com/FastLED/FastLED + d03n3rfr1tz3/HC-SR04@1.1.2 ; https://github.com/d03n3rfr1tz3/HC-SR04 + esphome/Improv@1.2.3 ; https://github.com/improv-wifi/sdk-cpp + majicdesigns/MD_REncoder@1.0.1 ; https://github.com/MajicDesigns/MD_REncoder + h2zero/NimBLE-Arduino@1.4.2 ; https://github.com/h2zero/NimBLE-Arduino + https://github.com/CNMAT/OSC@3.5.8 ; https://github.com/CNMAT/OSC + dxinteractive/ResponsiveAnalogRead@1.2.1 ; https://github.com/dxinteractive/ResponsiveAnalogRead bodmer/TFT_eSPI@2.5.33 ; https://github.com/Bodmer/TFT_eSPI - fortyseveneffects/MIDI Library@^5.0.2 ; https://github.com/FortySevenEffects/arduino_midi_library - lathoub/AppleMIDI@^3.2.0 ; https://github.com/lathoub/Arduino-AppleMIDI-Library - lathoub/BLE-MIDI@^2.2 ; https://github.com/lathoub/Arduino-BLE-MIDI - lathoub/ipMIDI@^1.0.3 ; https://github.com/lathoub/Arduino-ipMIDI - ryokosaka/Hello Drum@^0.7.7 ; https://github.com/RyoKosaka/HelloDrum-arduino-Library + fortyseveneffects/MIDI Library@5.0.2 ; https://github.com/FortySevenEffects/arduino_midi_library + lathoub/AppleMIDI@3.3.0 ; https://github.com/lathoub/Arduino-AppleMIDI-Library + lathoub/BLE-MIDI@2.2 ; https://github.com/lathoub/Arduino-BLE-MIDI + ;ESP32-BLE-MIDI@0.3.2 ; https://github.com/max22-/ESP32-BLE-MIDI + lathoub/ipMIDI@1.0.3 ; https://github.com/lathoub/Arduino-ipMIDI + ryokosaka/Hello Drum@0.7.7 ; https://github.com/RyoKosaka/HelloDrum-arduino-Library + adafruit/Adafruit ADS1X15@2.5.0 ; https://github.com/adafruit/Adafruit_ADS1X15 build_flags = -D PEDALINO_MINI @@ -67,7 +70,7 @@ build_flags_heltec_wifi_kit_32 = build_flags_ttgo_t_eight = -D TTGO_T_EIGHT - -DBOARD_HAS_PSRAM ; not enabled by default + -D BOARD_HAS_PSRAM ; not enabled by default -mfix-esp32-psram-cache-issue build_flags_ttgo_t_eight-ble = @@ -108,7 +111,8 @@ build_flags_ttgo_t_display = -D ARDUINO_LILYGO_T_DISPLAY build_flags_bpi_leaf_s3 = - -D ARDUINO_USB_CDC_ON_BOOT=1 + -D ARDUINO_USB_CDC_ON_BOOT=1 ; Initialize the USB CDC (serial over USB) interface at the start of the program, even before the setup() function is executed. + ; Communication over USB starts as soon as it powers on or resets, without waiting for the setup code to run. -D ARDUINO_USB_MODE=0 ; Disables CDC mode and turns on OTG. ; In order to flash the firmware you had to set the device manually into boot mode by pressing the BOOT and the RESET button. ; The device stay in download mode after flashing so you had to press the RESET button once more. @@ -116,10 +120,12 @@ build_flags_bpi_leaf_s3 = -D SSD1306WIRE build_flags_lilygo-t-display-s3 = - -D ARDUINO_USB_CDC_ON_BOOT=1 + -D ARDUINO_USB_CDC_ON_BOOT=1 ; Initialize the USB CDC (serial over USB) interface at the start of the program, even before the setup() function is executed. + ; Communication over USB starts as soon as it powers on or resets, without waiting for the setup code to run. -D ARDUINO_USB_MODE=0 ; Disables CDC mode and turns on OTG. ; In order to flash the firmware you had to set the device manually into boot mode by pressing the BOOT and the RESET button. ; The device stay in download mode after flashing so you had to press the RESET button once more. + -D BOARD_HAS_PSRAM ; PSRAM not enabled by default -D BATTERY -D USER_SETUP_LOADED ; TFT_eSPI configuration setup defined in platformio.ini -D ST7789_DRIVER @@ -150,7 +156,7 @@ build_flags_lilygo-t-display-s3 = -D SMOOTH_FONT [env] -platform = espressif32@^3.5.0 +platform = espressif32@3.5.0 framework = arduino board = esp32dev board_build.f_flash = 80000000L @@ -159,26 +165,27 @@ build_type = release ; release, test, debug lib_deps = ${common.lib_deps} monitor_speed = 115200 monitor_filters = esp32_exception_decoder, default +;extra_scripts = pre:esp32_platform_version.py [env:esp32dev] build_flags = ${common.build_flags} ${common.build_flags_esp32} lib_deps = ${common.lib_deps} - thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.3.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 + thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@4.5.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 [env:esp32doit-devkit-v1] board = esp32doit-devkit-v1 build_flags = ${common.build_flags} ${common.build_flags_esp32} lib_deps = ${common.lib_deps} - thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.3.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 + thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@4.5.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 [env:esp32doit-devkit-v1-ble] board = esp32doit-devkit-v1 build_flags = ${common.build_flags} ${common.build_flags_esp32-ble} lib_deps = ${common.lib_deps} - thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.3.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 + thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@4.5.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 board_build.partitions = src/partitions_ota.csv [env:esp32doit-devkit-v1-wifi] @@ -186,7 +193,7 @@ board = esp32doit-devkit-v1 build_flags = ${common.build_flags} ${common.build_flags_esp32-wifi} lib_deps = ${common.lib_deps} - thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.3.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 + thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@4.5.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 board_build.partitions = src/partitions_ota.csv [env:esp-wrover-kit] @@ -194,39 +201,39 @@ board = esp-wrover-kit build_flags = ${common.build_flags} ${common.build_flags_esp32} lib_deps = ${common.lib_deps} - thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.3.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 + thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@4.5.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 [env:heltec_wifi_kit_32] board = heltec_wifi_kit_32 build_flags = ${common.build_flags} ${common.build_flags_heltec_wifi_kit_32} lib_deps = ${common.lib_deps} - HelTecAutomation/Heltec ESP32 Dev-Boards@^1.1.2 ; https://github.com/HelTecAutomation/Heltec_ESP32 ; replacement of https://github.com/ThingPulse/esp8266-oled-ssd1306 + HelTecAutomation/Heltec ESP32 Dev-Boards@1.1.2 ; https://github.com/HelTecAutomation/Heltec_ESP32 ; replacement of https://github.com/ThingPulse/esp8266-oled-ssd1306 [env:ttgo-t-eight] build_flags = ${common.build_flags} ${common.build_flags_ttgo_t_eight} lib_deps = ${common.lib_deps} - thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.3.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 + thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@4.5.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 [env:ttgo-t-eight-ble] build_flags = ${common.build_flags} ${common.build_flags_ttgo_t_eight-ble} lib_deps = ${common.lib_deps} - thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.3.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 + thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@4.5.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 [env:ttgo-t-eight-wifi] build_flags = ${common.build_flags} ${common.build_flags_ttgo_t_eight-wifi} lib_deps = ${common.lib_deps} - thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.3.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 + thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@4.5.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 [env:ttgo-t-display] build_flags = ${common.build_flags} ${common.build_flags_ttgo_t_display} [env:lilygo-t-display] -platform = espressif32@^6.5.0 +platform = espressif32@6.9.0 framework = arduino board = lilygo-t-display build_flags = ${common.build_flags} @@ -238,29 +245,31 @@ build_flags = ${common.build_flags} ;monitor_port = /dev/tty.SLAB_USBtoUART [env:lilygo-t-display-s3] -platform = espressif32@^6.0.0 +platform = espressif32@6.9.0 framework = arduino -board = lilygo-t-display-s3 +board = lilygo-t-display-s3 ; https://docs.platformio.org/en/latest/boards/espressif32/lilygo-t-display-s3.html board_build.partitions = src/partitions_lilygo-t-display-s3.csv +build_unflags = -D ARDUINO_USB_MODE=1 ; Undefine symbol defined in https://github.com/platformio/platform-espressif32/blob/master/boards/lilygo-t-display-s3.json + ; to avoid redefinition warnings build_flags = ${common.build_flags} ${common.build_flags_lilygo-t-display-s3} lib_deps = ${common.lib_deps} - adafruit/Adafruit TinyUSB Library@^2.2.7 ; https://github.com/adafruit/Adafruit_TinyUSB_Arduino + adafruit/Adafruit TinyUSB Library@3.3.4 ; https://github.com/adafruit/Adafruit_TinyUSB_Arduino [env:bpi-leaf-s3] -platform = espressif32@^6.0.0 +platform = espressif32@6.9.0 framework = arduino -board = bpi_leaf_s3 +board = bpi_leaf_s3 ; https://docs.platformio.org/en/latest/boards/espressif32/bpi_leaf_s3.html board_build.partitions = src/partitions_bpi_leaf_s3.csv build_flags = ${common.build_flags} ${common.build_flags_bpi_leaf_s3} lib_deps = ${common.lib_deps} - thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.3.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 - adafruit/Adafruit TinyUSB Library@^2.2.7 ; https://github.com/adafruit/Adafruit_TinyUSB_Arduino + thingpulse/ESP8266 and ESP32 OLED driver for SSD1306 displays@4.5.0 ; https://github.com/ThingPulse/esp8266-oled-ssd1306 + adafruit/Adafruit TinyUSB Library@3.3.4 ; https://github.com/adafruit/Adafruit_TinyUSB_Arduino ;upload_port = /dev/cu.usbmodem14201 ; enter Bootloader mode to enable flash via USB-CDC: connect it via USB, hold BOOT button, press RST button once, then release BOOT button. ; RST to exit Bootloader mode ;monitor_port = ${env:bpi-leaf-s3.upload_port} ;build_type = debug ;debug_speed = 12000 ;debug_tool = esp-builtin -;debug_init_break = tbreak setup +;debug_init_break = tbreak setup \ No newline at end of file diff --git a/src/Config.h b/src/Config.h index 6aa8f99..457df7c 100644 --- a/src/Config.h +++ b/src/Config.h @@ -22,16 +22,21 @@ extern String httpUsername; extern String httpPassword; #ifdef BOARD_HAS_PSRAM -struct SpiRamAllocator { - void* allocate(size_t size) { +struct SpiRamAllocator : ArduinoJson::Allocator { + void* allocate(size_t size) override { return heap_caps_malloc(size, MALLOC_CAP_SPIRAM); } - void deallocate(void* pointer) { + + void deallocate(void* pointer) override { heap_caps_free(pointer); } + + void* reallocate(void* ptr, size_t new_size) override { + return heap_caps_realloc(ptr, new_size, MALLOC_CAP_SPIRAM); + } }; -using SpiRamJsonDocument = BasicJsonDocument; +SpiRamAllocator allocator; #endif bool control_not_defined (unsigned int c) { @@ -276,20 +281,15 @@ void spiffs_remove_profile(byte profile) { void spiffs_save_config(const String& filename, bool saveActions = true, bool savePedals = true, bool saveControls = true, bool saveInterfaces = true, bool saveSequences = true, bool saveOptions = true) { - uint32_t allocated; - #ifdef BOARD_HAS_PSRAM - allocated = 256*1024; - SpiRamJsonDocument jdoc(allocated); + JsonDocument jdoc(&allocator); #else - allocated = ESP.getMaxAllocHeap(); - DynamicJsonDocument jdoc(ESP.getMaxAllocHeap()); + JsonDocument jdoc; #endif - DPRINT("Memory allocated for JSON document: %d bytes\n", allocated); if (saveOptions) { - JsonArray jglobals = jdoc.createNestedArray("Globals"); - JsonObject jo = jglobals.createNestedObject(); + JsonArray jglobals = jdoc["Globals"].to(); + JsonObject jo = jglobals.add(); jo["Hostname"] = host; jo["BootMode"] = bootMode; jo["BLEServer"] = bleServer; @@ -339,18 +339,18 @@ void spiffs_save_config(const String& filename, bool saveActions = true, bool sa jo["OSCLocalPort"] = oscLocalPort; jo["OSCRemoteHost"] = oscRemoteHost; jo["OSCRemotePort"] = oscRemotePort; - JsonArray jladder = jdoc.createNestedArray("Ladder"); + JsonArray jladder = jdoc["Ladder"].to(); for (byte s = 0; s < LADDER_STEPS + 1; s++) { - JsonObject jo = jladder.createNestedObject(); + JsonObject jo = jladder.add(); jo["Step"] = s + 1; jo["Level"] = ladderLevels[s]; } } if (savePedals) { - JsonArray jpedals = jdoc.createNestedArray("Pedals"); + JsonArray jpedals = jdoc["Pedals"].to(); for (byte p = 0; p < PEDALS; p++) { - JsonObject jo = jpedals.createNestedObject(); + JsonObject jo = jpedals.add(); jo["Pedal"] = p + 1; jo["Mode"] = pedalModeName[pedals[p].mode]; jo["InvertPolarity"] = (pedals[p].invertPolarity == PED_ENABLE); @@ -366,10 +366,10 @@ void spiffs_save_config(const String& filename, bool saveActions = true, bool sa } if (saveControls) { - JsonArray jpedals = jdoc.createNestedArray("Controls"); + JsonArray jpedals = jdoc["Controls"].to(); for (byte c = 0; c < CONTROLS; c++) { if (control_not_defined(c)) continue; - JsonObject jo = jpedals.createNestedObject(); + JsonObject jo = jpedals.add(); jo["Control"] = c + 1; jo["Pedal1"] = (controls[c].pedal1 == PEDALS ? 0 : controls[c].pedal1 + 1); jo["Button1"] = (controls[c].button1 == LADDER_STEPS ? 0 : controls[c].button1 + 1); @@ -380,20 +380,20 @@ void spiffs_save_config(const String& filename, bool saveActions = true, bool sa } if (saveActions) { - JsonArray jbnames = jdoc.createNestedArray("BankNames"); + JsonArray jbnames = jdoc["BankNames"].to(); for (byte b = 0; b < BANKS; b++) { - JsonObject jo = jbnames.createNestedObject(); + JsonObject jo = jbnames.add(); jo["Bank"] = b; jo["Name"] = banknames[b]; } - JsonArray jactions = jdoc.createNestedArray("Actions"); + JsonArray jactions = jdoc["Actions"].to(); for (byte b = 0; b < BANKS; b++) { action *act = actions[b]; while (act != nullptr) { char color[8]; - JsonObject jo = jactions.createNestedObject(); + JsonObject jo = jactions.add(); jo["Bank"] = b; jo["Control"] = act->control + 1; jo["Led"] = (act->led == LEDS ? 0 : (act->led == 255 ? 255 : act->led + 1)); @@ -417,9 +417,9 @@ void spiffs_save_config(const String& filename, bool saveActions = true, bool sa } if (saveInterfaces) { - JsonArray jinterfaces = jdoc.createNestedArray("Interfaces"); + JsonArray jinterfaces = jdoc["Interfaces"].to(); for (byte i = 0; i < INTERFACES; i++) { - JsonObject jo = jinterfaces.createNestedObject(); + JsonObject jo = jinterfaces.add(); jo["Interface"] = i + 1; jo["Name"] = interfaces[i].name; jo["In"] = (IS_INTERFACE_ENABLED(interfaces[i].midiIn)); @@ -432,14 +432,21 @@ void spiffs_save_config(const String& filename, bool saveActions = true, bool sa } if (saveSequences) { - JsonArray jsequences = jdoc.createNestedArray("Sequences"); + JsonArray jsequences = jdoc["Sequences"].to(); for (byte s = 0; s < SEQUENCES; s++) { for (byte t = 0; t < STEPS; t++) { - JsonObject jo = jsequences.createNestedObject(); + JsonObject jo = jsequences.add(); jo["Sequence"] = s + 1; jo["Step"] = t + 1; jo["Message"] = ActionEnumToString(sequences[s][t].midiMessage); - jo["Channel"] = sequences[s][t].midiChannel; + switch (sequences[s][t].midiMessage) { + case PED_SEQUENCE: + jo["Channel"] = sequences[s][t].midiChannel + 1; + break; + default: + jo["Channel"] = sequences[s][t].midiChannel; + break; + } jo["Code"] = sequences[s][t].midiCode; jo["Value"] = sequences[s][t].midiValue; jo["Led"] = (sequences[s][t].led == LEDS ? 0 : (sequences[s][t].led == 255 ? 255 : sequences[s][t].led + 1)); @@ -516,16 +523,11 @@ void spiffs_save_profile(byte profile) { void spiffs_load_config(const String& filename, bool loadActions = true, bool loadPedals = true, bool loadControls = true, bool loadInterfaces = true, bool loadSequences = true, bool loadOptions = true, bool append = false) { - uint32_t allocated; - #ifdef BOARD_HAS_PSRAM - allocated = 256*1024; - SpiRamJsonDocument jdoc(allocated); + JsonDocument jdoc(&allocator); #else - allocated = ESP.getMaxAllocHeap(); - DynamicJsonDocument jdoc(ESP.getMaxAllocHeap()); + JsonDocument jdoc; #endif - DPRINT("Memory allocated for JSON document: %d bytes\n", allocated); DPRINT("Reading %s from SPIFFS ... ", filename.c_str()); File file = SPIFFS.open(filename, FILE_READ); @@ -543,11 +545,6 @@ void spiffs_load_config(const String& filename, bool loadActions = true, bool lo file.close(); DPRINT("done\n"); -#ifndef BOARD_HAS_PSRAM - jdoc.shrinkToFit(); - DPRINT("Memory used by JSON document: %d bytes\n", jdoc.memoryUsage()); -#endif - #ifdef DEBUG_ESP_PORT serializeJson(jdoc, SERIALDEBUG); #endif @@ -786,7 +783,14 @@ void spiffs_load_config(const String& filename, bool loadActions = true, bool lo t = constrain(t, 0, STEPS - 1); sequences[s][t].midiMessage = ActionStringToEnum(jo["Message"]); sequences[s][t].midiChannel = jo["Channel"]; - sequences[s][t].midiChannel = constrain(sequences[s][t].midiChannel, 0, 17); + switch (sequences[s][t].midiMessage) { + case PED_SEQUENCE: + sequences[s][t].midiChannel = constrain(sequences[s][t].midiChannel - 1, 0, SEQUENCES - 1); + break; + default: + sequences[s][t].midiChannel = constrain(sequences[s][t].midiChannel, 0, 17); + break; + } sequences[s][t].midiCode = jo["Code"]; sequences[s][t].midiCode = constrain(sequences[s][t].midiCode, 0, MIDI_RESOLUTION - 1); sequences[s][t].midiValue = jo["Value"]; @@ -840,8 +844,8 @@ void load_factory_default() wifiPassword = ""; ssidSoftAP = String("Pedalino-") + getChipId(); passwordSoftAP = getChipId(); - httpUsername = "admin"; - httpPassword = getChipId(); + httpUsername = ""; + httpPassword = ""; theme = "bootstrap"; currentBank = 1; currentProfile = 0; @@ -889,6 +893,8 @@ void load_factory_default() nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr }; } @@ -985,6 +991,8 @@ void load_factory_default() nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr }; pedals[PEDALS-1].pressMode = PED_PRESS_1_2_L; @@ -1079,6 +1087,8 @@ void load_factory_default() nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr }; action *act; @@ -1194,12 +1204,12 @@ void load_factory_default() } // TC-Helicon Switch 6 - ladderLevels[0] = 352; - ladderLevels[1] = 533; - ladderLevels[2] = 640; - ladderLevels[3] = 723; - ladderLevels[4] = 806; - ladderLevels[5] = 908; + ladderLevels[0] = 352/2; + ladderLevels[1] = 533/2; + ladderLevels[2] = 640/2; + ladderLevels[3] = 723/2; + ladderLevels[4] = 806/2; + ladderLevels[5] = 908/2; ladderLevels[6] = ADC_RESOLUTION - 1; } @@ -1283,7 +1293,7 @@ void eeprom_update_ap_wifi_credentials(const String& ssid = String("Pedalino-") #endif } -void eeprom_update_login_credentials(const String& username = "admin", const String& password = getChipId()) +void eeprom_update_login_credentials(const String& username = "", const String& password = "") { #ifdef NVS DPRINT("Updating NVS ... "); @@ -1537,9 +1547,12 @@ void eeprom_update_profile(byte profile = currentProfile) pedals_copy[i].pedalValue[1] = 0; pedals_copy[i].lastUpdate[0] = 0; pedals_copy[i].lastUpdate[1] = 0; - pedals_copy[i].analogPedal = nullptr; + for (byte j = 0; j < ADC_INPUTS; j++) + pedals_copy[i].analogPedal[j] = nullptr; pedals_copy[i].jogwheel = nullptr; pedals_copy[i].buttonConfig = nullptr; + for (byte a = 0; a < 4; a++) + pedals_copy[i].ads[a] = nullptr; for (byte s = 0; s < LADDER_STEPS; s++) { pedals_copy[i].latchStatus[s] = 0; pedals_copy[i].button[s] = nullptr; @@ -1689,8 +1702,8 @@ void eeprom_read_global() void eeprom_read_profile(byte profile = currentProfile) { #ifdef NVS - controller_delete(); delete_actions(); + controller_delete(); DPRINT("Reading NVS Profile "); switch (profile) { case 0: @@ -1714,7 +1727,8 @@ void eeprom_read_profile(byte profile = currentProfile) pedals[i].pedalValue[1] = 0; pedals[i].lastUpdate[0] = 0; pedals[i].lastUpdate[1] = 0; - pedals[i].analogPedal = nullptr; + for (byte j = 0; j < ADC_INPUTS; j++) + pedals[i].analogPedal[j] = nullptr; pedals[i].analogPad = nullptr; pedals[i].jogwheel = nullptr; pedals[i].buttonConfig = nullptr; @@ -1756,12 +1770,13 @@ void eeprom_read_profile(byte profile = currentProfile) } } } + create_banks(); preferences.end(); DPRINT("done\n"); #else - controller_delete(); delete_actions(); + delete_controller(); spiffs_load_profile(profile); create_banks(); #endif diff --git a/src/Controller.h b/src/Controller.h index 736ad2e..38bee10 100644 --- a/src/Controller.h +++ b/src/Controller.h @@ -118,7 +118,8 @@ void leds_update_single(byte e, action *act, byte value, byte bank = currentBank case PED_PROGRAM_CHANGE_DEC: if (e == PED_EVENT_NONE) { - set_last_led_color(bank, led_control(act->control, act->led), act->color0, ledsOffBrightness); + set_last_led_color(bank, led_control(act->control, act->led), act->color0, ledsOffBrightness); + set_last_led_color(currentBank, led_control(act->control, act->led), act->color0, ledsOffBrightness); leds_refresh(led_control(act->control, act->led)); return; } @@ -774,7 +775,6 @@ void midi_send(byte message, byte code, byte value, byte channel, bool on_off, b { code = constrain(code, 0, MIDI_RESOLUTION - 1); value = constrain(value, 0, MIDI_RESOLUTION - 1); - channel = constrain(channel, 0, 17); bool channelMessage = (message == PED_NOTE_ON ) || (message == PED_NOTE_OFF ) || @@ -786,6 +786,8 @@ void midi_send(byte message, byte code, byte value, byte channel, bool on_off, b (message == PED_PITCH_BEND ) || (message == PED_CHANNEL_PRESSURE ); + if (channelMessage) channel = constrain(channel, 0, SEQUENCES); + if (channel == 0 && channelMessage) { switch (message) { @@ -1027,20 +1029,21 @@ void midi_send(byte message, byte code, byte value, byte channel, bool on_off, b case PED_SEQUENCE: - channel = constrain(channel, 1, SEQUENCES); + channel = constrain(channel, 0, SEQUENCES - 1); + DPRINT("\n"); DPRINT("=======================================================\n"); - DPRINT("SEQUENCE.....Number %2d\n", channel); + DPRINT("SEQUENCE.....Number %2d\n", channel + 1); DPRINT("-------------------------------------------------------\n"); for (byte s = 0; s < STEPS; s++) { - if (sequences[channel-1][s].midiMessage == PED_EMPTY) continue; - if (sequences[channel-1][s].midiMessage != PED_ACTION_LED_COLOR) { - midi_send(sequences[channel-1][s].midiMessage, sequences[channel-1][s].midiCode, sequences[channel-1][s].midiValue, sequences[channel-1][s].midiChannel, on_off, 0, MIDI_RESOLUTION - 1, bank, pedal, button, led); + if (sequences[channel][s].midiMessage == PED_EMPTY) continue; + if (sequences[channel][s].midiMessage != PED_ACTION_LED_COLOR) { + midi_send(sequences[channel][s].midiMessage, sequences[channel][s].midiCode, sequences[channel][s].midiValue, sequences[channel][s].midiChannel, on_off, 0, MIDI_RESOLUTION - 1, bank, pedal, button, led); } - byte l = (sequences[channel-1][s].led == 255 ? led : sequences[channel-1][s].led); + byte l = (sequences[channel][s].led == 255 ? led : sequences[channel][s].led); l = constrain(l, 0, LEDS); - fastleds[l] = sequences[channel-1][s].color; + fastleds[l] = sequences[channel][s].color; fastleds[l].nscale8(ledsOnBrightness); - if (sequences[channel-1][s].led != LEDS) { DPRINT("LED COLOR.....Led %2d......RGB Color #%02x%02x%02x\n", l + 1, fastleds[l].red, fastleds[l].green, fastleds[l].blue); } + if (sequences[channel][s].led != LEDS) { DPRINT("LED COLOR.....Led %2d......RGB Color #%02x%02x%02x\n", l + 1, fastleds[l].red, fastleds[l].green, fastleds[l].blue); } fastleds[l] = swap_rgb_order(fastleds[l], rgbOrder); FastLED.show(); lastLedColor[currentBank][l] = fastleds[l]; @@ -1053,21 +1056,21 @@ void midi_send(byte message, byte code, byte value, byte channel, bool on_off, b case PED_SEQUENCE_STEP_BY_STEP_FWD: case PED_SEQUENCE_STEP_BY_STEP_REV: - channel = constrain(channel, 1, SEQUENCES); - byte step = constrain(code, 1, STEPS); - DPRINT("SEQUENCE.....Number %2d.....Step %2d\n", channel, step); - midi_send(sequences[channel-1][step-1].midiMessage, sequences[channel-1][step-1].midiCode, sequences[channel-1][step-1].midiValue, sequences[channel-1][step-1].midiChannel, on_off, 0, MIDI_RESOLUTION - 1, bank, pedal, button, led); - byte l = (sequences[channel-1][step-1].led == 255 ? led : sequences[channel-1][step-1].led); + channel = constrain(channel, 0, SEQUENCES - 1); + byte step = constrain(code, 0, STEPS - 1); + DPRINT("SEQUENCE.....Number %2d.....Step %2d\n", channel + 1, step + 1); + midi_send(sequences[channel][step].midiMessage, sequences[channel][step].midiCode, sequences[channel][step].midiValue, sequences[channel][step].midiChannel, on_off, 0, MIDI_RESOLUTION - 1, bank, pedal, button, led); + byte l = (sequences[channel][step].led == 255 ? led : sequences[channel][step].led); l = constrain(l, 0, LEDS); - fastleds[l] = sequences[channel-1][step-1].color; + fastleds[l] = sequences[channel][step].color; fastleds[l].nscale8(ledsOnBrightness); - if (sequences[channel-1][step-1].led != LEDS) { DPRINT("LED COLOR.....Led %2d......RGB Color #%02x%02x%02x\n", l + 1, fastleds[l].red, fastleds[l].green, fastleds[l].blue); } + if (sequences[channel][step].led != LEDS) { DPRINT("LED COLOR.....Led %2d......RGB Color #%02x%02x%02x\n", l + 1, fastleds[l].red, fastleds[l].green, fastleds[l].blue); } fastleds[l] = swap_rgb_order(fastleds[l], rgbOrder); FastLED.show(); lastLedColor[currentBank][l] = fastleds[l]; DPRINT("--------------------------------------------------\n"); - currentMIDIValue[bank][pedal][button] = channel; - lastMIDIMessage[currentBank] = {(byte)(message == PED_SEQUENCE_STEP_BY_STEP_FWD ? PED_SEQUENCE_STEP_BY_STEP_FWD : PED_SEQUENCE_STEP_BY_STEP_REV), code, value, channel}; + //currentMIDIValue[bank][pedal][button] = channel; + //lastMIDIMessage[currentBank] = {(byte)(message == PED_SEQUENCE_STEP_BY_STEP_FWD ? PED_SEQUENCE_STEP_BY_STEP_FWD : PED_SEQUENCE_STEP_BY_STEP_REV), code, value, channel}; break; } } @@ -1087,34 +1090,36 @@ void fire_action(action* act, byte p, byte i, byte e) case PED_MIDI_START: case PED_MIDI_STOP: case PED_MIDI_CONTINUE: - case PED_SEQUENCE: midi_send(act->midiMessage, act->midiCode, act->midiValue1, act->midiChannel, true, act->midiValue1, act->midiValue2, currentBank, p, i); break; + case PED_SEQUENCE: + midi_send(act->midiMessage, act->midiCode, act->midiValue1, act->midiChannel - 1, true, act->midiValue1, act->midiValue2, currentBank, p, i); + break; + case PED_SEQUENCE_STEP_BY_STEP_FWD: case PED_SEQUENCE_STEP_BY_STEP_REV: act->midiChannel = constrain(act->midiChannel, 1, SEQUENCES); - act->midiCode = constrain(act->midiCode, 0, STEPS); + act->midiCode = constrain(act->midiCode, 0, STEPS - 1); + act->midiCode = (sequences[act->midiChannel - 1][act->midiCode].midiMessage == PED_EMPTY) ? 0 : act->midiCode; + if (sequences[act->midiChannel - 1][0].midiMessage == PED_EMPTY) break; + midi_send(act->midiMessage, act->midiCode, act->midiValue1, act->midiChannel - 1, true, act->midiValue1, act->midiValue2, currentBank, p, i, led_control(act->control, act->led)); switch (act->midiMessage) { case PED_SEQUENCE_STEP_BY_STEP_FWD: - act->midiCode = act->midiCode % STEPS + 1; - act->midiCode = (sequences[act->midiChannel-1][act->midiCode-1].midiMessage == PED_EMPTY ? 1 : act->midiCode); + act->midiCode = (act->midiCode + 1 ) % STEPS; + act->midiCode = (sequences[act->midiChannel - 1][act->midiCode].midiMessage == PED_EMPTY ? 0 : act->midiCode); break; case PED_SEQUENCE_STEP_BY_STEP_REV: - if (act->midiCode <= 1) { - for (byte s = 0; s < STEPS; s++) { - if (sequences[act->midiChannel-1][s].midiMessage == PED_EMPTY) { - act->midiCode = s; - break; - } - if (s == (STEPS - 1)) act->midiCode = STEPS; + if (act->midiCode == 0) { + byte s; + for (s = 0; s < STEPS; s++) { + if (sequences[act->midiChannel - 1][s].midiMessage == PED_EMPTY) break; } + if (s > 0) act->midiCode = s - 1; } - else - act->midiCode = act->midiCode % (STEPS + 1) - 1; + else if (act->midiCode > 0) act->midiCode--; break; } - midi_send(act->midiMessage, act->midiCode, act->midiValue1, act->midiChannel, true, act->midiValue1, act->midiValue2, currentBank, p, i, led_control(act->control, act->led)); for (byte b = 0; b < BANKS; b++) { action *a = actions[b]; while ( a != nullptr) { @@ -1402,7 +1407,8 @@ void fire_action(action* act, byte p, byte i, byte e) #ifdef WIFI esp_wifi_stop(); #endif - adc_power_off(); + //adc_power_off(); + adc_power_release(); delay(200); rtc_gpio_pullup_en((gpio_num_t)PIN_D(p)); rtc_gpio_pulldown_dis((gpio_num_t)PIN_D(p)); @@ -1495,12 +1501,13 @@ void process_backlog() (controls[act->control].pedal2 == e->pedal) && (controls[act->control].button2 == e->button) ) ) && - (((act->event == e->event) || // Events match or - (act->event == PED_EVENT_PRESS_RELEASE) && ((e->event == PED_EVENT_PRESS) || (e->event == PED_EVENT_RELEASE)) // PRESS_RELEASE matches with PRESS or RELEASE - ) && - ((act->event == f->event) || // Events match or - (act->event == PED_EVENT_PRESS_RELEASE) && ((f->event == PED_EVENT_PRESS) || (f->event == PED_EVENT_RELEASE)) // PRESS_RELEASE matches with PRESS or RELEASE - ) + (((act->event == e->event) || // Events match or + (act->event == PED_EVENT_PRESS_RELEASE) && ((e->event == PED_EVENT_PRESS) || (e->event == PED_EVENT_RELEASE)) // PRESS_RELEASE matches with PRESS or RELEASE + ) && + ((act->event == f->event) || // Events match or + (act->event == PED_EVENT_PRESS_RELEASE) && ((f->event == PED_EVENT_PRESS) || (f->event == PED_EVENT_RELEASE)) // PRESS_RELEASE matches with PRESS or RELEASE + ) && + (e->event == f->event) ) ) { fire_action(act, e->pedal, e->button, e->event); @@ -1517,7 +1524,8 @@ void process_backlog() } } } - backlog.clear(); + for (std::list::iterator e = backlog.begin(); e != backlog.end(); ) + e->processed ? e = backlog.erase(e) : e++; } // @@ -1633,12 +1641,12 @@ void controller_event_handler_button(AceButton* button, uint8_t eventType, uint8 // // Trigger Actions on Analog Events // -void controller_event_handler_analog(byte pedal, int value) +void controller_event_handler_analog(byte pedal, byte button, int value) { bool global = actions[0] != nullptr; action *act = actions[0] == nullptr ? actions[currentBank] : actions[0]; while (act != nullptr) { - if (controls[act->control].pedal1 == pedal && (act->event == PED_EVENT_MOVE || act->event == PED_EVENT_SHOT)) { + if (controls[act->control].pedal1 == pedal && controls[act->control].button1 == button && (act->event == PED_EVENT_MOVE || act->event == PED_EVENT_SHOT)) { if (act->midiMessage == PED_ACTION_REPEAT) { value = map2(value, // map from [0, ADC_RESOLUTION-1] to [0, 127] MIDI value 0, @@ -1688,7 +1696,7 @@ void controller_event_handler_analog(byte pedal, int value) break; case PED_SEQUENCE: - midi_send(act->midiMessage, act->midiCode, value, act->midiChannel, true, act->midiValue1, act->midiValue2, currentBank, pedal); + midi_send(act->midiMessage, act->midiCode, value, act->midiChannel - 1, true, act->midiValue1, act->midiValue2, currentBank, pedal); set_led_color(led_control(act->control, act->led), act->color0, ledsOffBrightness, act->color1, ledsOnBrightness, value); FastLED.show(); lastLedColor[currentBank][led_control(act->control, act->led)] = fastleds[led_control(act->control, act->led)]; @@ -1767,29 +1775,67 @@ void refresh_analog(byte i, bool send) int input; int value; - static int direction = 0; - if (pedals[i].analogPedal == nullptr) return; // sanity check + if (pedals[i].analogPedal[0] == nullptr) return; // sanity check input = analogRead(PIN_A(i)); // read the raw analog input value if (pedals[i].autoSensing) { // continuos calibration if (pedals[i].expZero > (input + SAFE_ZONE)) { + pedals[i].expZero = constrain(input + SAFE_ZONE, SAFE_ZONE, ADC_RESOLUTION - 1 - SAFE_ZONE); + pedals[i].expMax = constrain(pedals[i].expMax, pedals[i].expZero, ADC_RESOLUTION - 1 - SAFE_ZONE); DPRINT("Pedal %2d calibration min %d\n", i + 1, input); } if (pedals[i].expMax < (input - SAFE_ZONE)) { + pedals[i].expMax = constrain(input - SAFE_ZONE, SAFE_ZONE, ADC_RESOLUTION - 1 - SAFE_ZONE); + pedals[i].expZero = constrain(pedals[i].expZero, SAFE_ZONE, pedals[i].expMax); DPRINT("Pedal %2d calibration max %d\n", i + 1, input); } - pedals[i].expZero = _min(pedals[i].expZero, input + SAFE_ZONE); - pedals[i].expMax = _max(pedals[i].expMax, input - SAFE_ZONE); - //DPRINT("%d -> [%d, %d]\n", input, pedals[i].expZero, pedals[i].expMax); } value = map_analog(i, input); // expand to [0, ADC_RESOLUTION-1] and apply the map function - pedals[i].analogPedal->update(value); // update the responsive analog average - if (pedals[i].analogPedal->hasChanged()) { // if the value changed since last time - value = pedals[i].analogPedal->getValue(); // get the responsive analog average value + pedals[i].analogPedal[0]->update(value); // update the responsive analog average + if (pedals[i].analogPedal[0]->hasChanged()) { // if the value changed since last time + value = pedals[i].analogPedal[0]->getValue(); // get the responsive analog average value double velocity = (1000.0 * (value - pedals[i].pedalValue[0])) / (micros() - pedals[i].lastUpdate[0]); DPRINT("Pedal %2d input %d output %d velocity %.2f\n", i + 1, input, value, velocity); - if (send) controller_event_handler_analog(i, value); + if (send) controller_event_handler_analog(i, 0, value); + pedals[i].pedalValue[0] = value; + pedals[i].lastUpdate[0] = micros(); + if (scannerActivated) { + scanPedal = i; + scanIndex = (scanIndex + 1) % POINTS; + scan[scanIndex] = input; + scanProcessed[scanIndex] = value; + } + } +} + +void refresh_analog4(int input, byte i, byte j, bool send) +{ + const int SAFE_ZONE = ADC_RESOLUTION / 20; // 5% of margin at both end of the scale + + int value; + + if (pedals[i].analogPedal[j] == nullptr) return; // sanity check + + if (pedals[i].autoSensing) { // continuos calibration + if (pedals[i].expZero > (input + SAFE_ZONE)) { + pedals[i].expZero = constrain(input + SAFE_ZONE, SAFE_ZONE, ADC_RESOLUTION - 1 - SAFE_ZONE); + pedals[i].expMax = constrain(pedals[i].expMax, pedals[i].expZero, ADC_RESOLUTION - 1 - SAFE_ZONE); + DPRINT("Pedal %2d/%2d calibration min %d\n", i + 1, j + 1, input); + } + if (pedals[i].expMax < (input - SAFE_ZONE)) { + pedals[i].expMax = constrain(input - SAFE_ZONE, SAFE_ZONE, ADC_RESOLUTION - 1 - SAFE_ZONE); + pedals[i].expZero = constrain(pedals[i].expZero, SAFE_ZONE, pedals[i].expMax); + DPRINT("Pedal %2d/%2d calibration max %d\n", i + 1, j + 1, input); + } + } + value = map_analog(i, input); // expand to [0, ADC_RESOLUTION-1] and apply the map function + pedals[i].analogPedal[j]->update(value); // update the responsive analog average + if (pedals[i].analogPedal[j]->hasChanged()) { // if the value changed since last time + value = pedals[i].analogPedal[j]->getValue(); // get the responsive analog average value + double velocity = (1000.0 * (value - pedals[i].pedalValue[j])) / (micros() - pedals[i].lastUpdate[j]); + DPRINT("Pedal %2d Button %2d input %d output %d velocity %.2f\n", i + 1, j + 1, input, value, velocity); + if (send) controller_event_handler_analog(i, j, value); pedals[i].pedalValue[0] = value; pedals[i].lastUpdate[0] = micros(); if (scannerActivated) { @@ -1831,12 +1877,12 @@ void refresh_ultrasonic(bool send) */ value = map_analog(i, input); // expand to [0, ADC_RESOLUTION-1] and apply the map function - pedals[i].analogPedal->update(value); // update the responsive analog average - if (pedals[i].analogPedal->hasChanged()) { // if the value changed since last time - value = pedals[i].analogPedal->getValue(); // get the responsive analog average value + pedals[i].analogPedal[0]->update(value); // update the responsive analog average + if (pedals[i].analogPedal[0]->hasChanged()) { // if the value changed since last time + value = pedals[i].analogPedal[0]->getValue(); // get the responsive analog average value double velocity = (1000.0 * (value - pedals[i].pedalValue[0])) / (micros() - pedals[i].lastUpdate[0]); DPRINT("Pedal %2d input %d output %d velocity %.2f\n", i + 1, input, value, velocity); - if (send) controller_event_handler_analog(i, value); + if (send) controller_event_handler_analog(i, 0, value); pedals[i].pedalValue[0] = value; pedals[i].lastUpdate[0] = micros(); if (scannerActivated) { @@ -1856,7 +1902,7 @@ void refresh_ultrasonic(bool send) void onAnalogPad(int id, int pressure) { pressure = map_analog(id, pressure); // expand to [0, ADC_RESOLUTION-1] and apply the map function - controller_event_handler_analog(id, pressure); + controller_event_handler_analog(id, 0, pressure); } @@ -1867,25 +1913,32 @@ void controller_setup(); // void controller_delete() { - for (byte i = 0; i < PEDALS; i++) { - if (pedals[i].analogPedal != nullptr) { - delete pedals[i].analogPedal; - pedals[i].analogPedal = nullptr; + for (byte i = 0; i < PEDALS; i++) + for (byte j = 0; j < ADC_INPUTS; j++) { + if (pedals[i].analogPedal[j] != nullptr) { + delete pedals[i].analogPedal[j]; + pedals[i].analogPedal[j] = nullptr; } - if (pedals[i].analogPad != nullptr) { + for (byte a = 0; a < 4; a++) { + if (pedals[i].ads[a] != nullptr) { + delete pedals[i].ads[a]; + pedals[i].ads[a] = nullptr; + } + } + if (pedals[i].analogPad != nullptr) { delete pedals[i].analogPad; pedals[i].analogPad = nullptr; } - if (pedals[i].jogwheel != nullptr) { + if (pedals[i].jogwheel != nullptr) { delete pedals[i].jogwheel; pedals[i].jogwheel = nullptr; } - if (pedals[i].buttonConfig != nullptr) { + if (pedals[i].buttonConfig != nullptr) { delete pedals[i].buttonConfig; pedals[i].buttonConfig = nullptr; } for (byte s = 0; s < LADDER_STEPS; s++) - if (pedals[i].button[s] != nullptr) { + if (pedals[i].button[s] != nullptr) { delete pedals[i].button[s]; pedals[i].button[s] = nullptr; } @@ -1899,10 +1952,16 @@ void controller_delete() // void controller_run(bool send = true) { + static byte adsChannel[ADC_BOARDS] = {0, 0, 0, 0}; + + while (controllerRunning) vTaskDelay(1/portTICK_PERIOD_MS); // wait for fist task to complete + controllerRunning = true; // block second tasks to run + if (saveProfile && send) { saveProfile = false; DPRINT("Saving profile ...\n"); eeprom_update_current_profile(currentProfile); + controllerRunning = false; return; } @@ -1939,6 +1998,7 @@ void controller_run(bool send = true) //OscControllerUpdate(); #endif DPRINT("... profile %d loaded.\n", currentProfile); + controllerRunning = false; return; } @@ -1952,6 +2012,7 @@ void controller_run(bool send = true) OscControllerUpdate(); #endif DPRINT("... configuration loaded.\n"); + controllerRunning = false; return; } @@ -1979,6 +2040,41 @@ void controller_run(bool send = true) refresh_analog(i, send); break; + case PED_ANALOG4: + for (byte a = 0; a < ADC_BOARDS; a++) { + + if (!ads1115Found[a]) continue; + + if (pedals[i].ads[a]->conversionComplete()) { // The ADS1115 provide 16 bits of data in binary two's complement format + int16_t result = pedals[i].ads[a]->getLastConversionResults(); // It returns value range from 0000h to 7FFFh when input is between 0V to positive Full Scale + // It returns value range from 8000h to FFFFh when input is between negative Full Scale to 0V + result = result < 0 ? 0 : result>>6; // The ADS1115 can still output negative values in case input is close to 0V + // Convert from 16 bits to 10 bits in case of positive values + refresh_analog4(result, i, adsChannel[a] * (a + 1), send); + // The ADS1115 contains an input multiplexer to connect signals to the internal ADC. + // Either four single-ended or two differential signals can be measured. + // When single-ended signals are measured, the negative input of the ADC is internally connected to GND by a switch within the multiplexer. + // Only one signal can be converted at time. + // Non-blocking start conversion function + adsChannel[a] = (adsChannel[a] + 1) % 4; + switch (adsChannel[a]) { + case 0: + pedals[i].ads[a]->startADCReading(ADS1X15_REG_CONFIG_MUX_SINGLE_0, false); + break; + case 1: + pedals[i].ads[a]->startADCReading(ADS1X15_REG_CONFIG_MUX_SINGLE_1, false); + break; + case 2: + pedals[i].ads[a]->startADCReading(ADS1X15_REG_CONFIG_MUX_SINGLE_2, false); + break; + case 3: + pedals[i].ads[a]->startADCReading(ADS1X15_REG_CONFIG_MUX_SINGLE_3, false); + break; + } + } + } + break; + case PED_ANALOG_PAD: if (pedals[i].analogPad != nullptr) { //int v = analogRead(PIN_A(i)); @@ -1986,7 +2082,7 @@ void controller_run(bool send = true) pedals[i].analogPad->singlePiezo(pedals[i].gain, pedals[i].expZero, pedals[i].scanCycles, pedals[i].holdCycles); //(sensitivity, threshold, scantime, masktime) if (pedals[i].analogPad->hit) { int pressure = map_analog(i, pedals[i].analogPad->velocity); // expand to [0, ADC_RESOLUTION-1] and apply the map function - controller_event_handler_analog(i, pressure); + controller_event_handler_analog(i, 0, pressure); } if (scannerActivated) { int v = analogRead(PIN_A(i)); @@ -2114,6 +2210,8 @@ void controller_run(bool send = true) if (backlog.size() > 0) process_backlog(); refresh_ultrasonic(send); + + controllerRunning = false; } @@ -2134,12 +2232,13 @@ void controller_setup() lastUsed = 0xFF; lastSlot = SLOTS; memset(lastPedalName, 0, MAXACTIONNAME+1); + controller_delete(); analogReadResolution(ADC_RESOLUTION_BITS); analogSetAttenuation(ADC_11db); - DPRINT("Bank %2d\n", currentBank + 1); + DPRINT("Bank %2d\n", currentBank); // Build new MIDI controllers setup for (byte i = 0; i < PEDALS; i++) { @@ -2151,6 +2250,7 @@ void controller_setup() case PED_LATCH1: DPRINT("LATCH1 "); break; case PED_LATCH2: DPRINT("LATCH2 "); break; case PED_ANALOG: DPRINT("ANALOG "); break; + case PED_ANALOG4: DPRINT("ANALOG4 "); break; case PED_ANALOG_PAD: DPRINT("ANALOG PAD "); break; case PED_JOG_WHEEL: DPRINT("JOG_WHEEL "); break; case PED_LADDER: DPRINT("LADDER "); break; @@ -2308,11 +2408,11 @@ void controller_setup() case PED_ANALOG: pinMode(PIN_D(i), OUTPUT); digitalWrite(PIN_D(i), HIGH); - pedals[i].analogPedal = new ResponsiveAnalogRead(PIN_A(i), true); - pedals[i].analogPedal->setAnalogResolution(ADC_RESOLUTION); - pedals[i].analogPedal->enableEdgeSnap(); - pedals[i].analogPedal->setSnapMultiplier(pedals[i].snapMultiplier); - pedals[i].analogPedal->setActivityThreshold(pedals[i].activityThreshold); + pedals[i].analogPedal[0] = new ResponsiveAnalogRead(PIN_A(i), true); + pedals[i].analogPedal[0]->setAnalogResolution(ADC_RESOLUTION); + pedals[i].analogPedal[0]->enableEdgeSnap(); + pedals[i].analogPedal[0]->setSnapMultiplier(pedals[i].snapMultiplier); + pedals[i].analogPedal[0]->setActivityThreshold(pedals[i].activityThreshold); if (lastUsedPedal == 0xFF) { lastUsedPedal = i; lastUsed = i; @@ -2322,6 +2422,45 @@ void controller_setup() DPRINT(" Pin A%d D%d", PIN_A(i), PIN_D(i)); break; + case PED_ANALOG4: + for (byte j = 0; j < ADC_INPUTS; j++) { + pedals[i].analogPedal[j] = new ResponsiveAnalogRead(PIN_A(i), true); + pedals[i].analogPedal[j]->setAnalogResolution(ADC_RESOLUTION); + pedals[i].analogPedal[j]->enableEdgeSnap(); + pedals[i].analogPedal[j]->setSnapMultiplier(pedals[i].snapMultiplier); + pedals[i].analogPedal[j]->setActivityThreshold(pedals[i].activityThreshold); + } + // The I2C bus operates at one of three speeds. Standard mode allows a clock frequency of up to 100 kHz; fast mode permits a clock frequency of up to 400 kHz; + // and high-speed mode (also called Hs mode) allows a clock frequency of up to 3.4 MHz. The ADS1115 are fully compatible with all three modes. + // ESP32 and ESP32-S3 supports only I2C standard and fast modes which can go up to 100kHz and 400kHz respectively. + // ESP32 and ESP32-S3 has 2 I2C controllers, responsible for handling communication on the I2C bus. A single I2C controller can be a master or a slave. + // Using 2nd I2C bus at 100kHz (default) as master + for (byte a = 0; a < ADC_BOARDS; a++) { + + pedals[i].ads[a] = new Adafruit_ADS1115(); + // Sets the gain to 1 for an input range of +/-4.096V + pedals[i].ads[a]->setGain(GAIN_ONE); + // Set data rate to 128 samples per second (default) + pedals[i].ads[a]->setDataRate(RATE_ADS1115_128SPS); + // Initialize the ADC for operation +#ifdef WIRE_HAS_END + Wire1.end(); +#endif + Wire1.setPins(PIN_D(i), PIN_A(i)); + ads1115Found[a] = pedals[i].ads[a]->begin(ADS1X15_ADDRESS + a, &Wire1); + // Non-blocking start conversion function + if (ads1115Found[a]) pedals[i].ads[a]->startADCReading(ADS1X15_REG_CONFIG_MUX_SINGLE_0, false); + } + if (lastUsedPedal == 0xFF) { + lastUsedPedal = i; + lastUsed = i; + lastSlot = SLOTS; + strlcpy(lastPedalName, banks[currentBank][i].pedalName, MAXACTIONNAME+1); + } + DPRINT(" I2C"); + for (byte a = 0; a < ADC_BOARDS; a++) ads1115Found[a] ? DPRINT(" %#04x", ADS1X15_ADDRESS + a) : DPRINT(" ----"); + break; + case PED_ANALOG_PAD: pinMode(PIN_A(i), INPUT); /* @@ -2376,22 +2515,22 @@ void controller_setup() case PED_ULTRASONIC: ultrasonicEcho.push_back(PIN_A(i)); if (ultrasonicTrigger == 0) ultrasonicTrigger = PIN_D(i); - pedals[i].analogPedal = new ResponsiveAnalogRead(); - pedals[i].analogPedal->setAnalogResolution(ADC_RESOLUTION); - pedals[i].analogPedal->enableSleep(); - pedals[i].analogPedal->enableEdgeSnap(); - pedals[i].analogPedal->setSnapMultiplier(pedals[i].snapMultiplier); - pedals[i].analogPedal->setActivityThreshold(pedals[i].activityThreshold); + pedals[i].analogPedal[0] = new ResponsiveAnalogRead(); + pedals[i].analogPedal[0]->setAnalogResolution(ADC_RESOLUTION); + pedals[i].analogPedal[0]->enableSleep(); + pedals[i].analogPedal[0]->enableEdgeSnap(); + pedals[i].analogPedal[0]->setSnapMultiplier(pedals[i].snapMultiplier); + pedals[i].analogPedal[0]->setActivityThreshold(pedals[i].activityThreshold); DPRINT(" Pin A%d (ECHO) D%d (TRIG)", PIN_A(i), PIN_D(i)); break; case PED_ANALOG_MOMENTARY: case PED_ANALOG_LATCH: - pedals[i].analogPedal = new ResponsiveAnalogRead(PIN_A(i), true); - pedals[i].analogPedal->setAnalogResolution(ADC_RESOLUTION); - pedals[i].analogPedal->enableEdgeSnap(); - pedals[i].analogPedal->setSnapMultiplier(pedals[i].snapMultiplier); - pedals[i].analogPedal->setActivityThreshold(pedals[i].activityThreshold); + pedals[i].analogPedal[0] = new ResponsiveAnalogRead(PIN_A(i), true); + pedals[i].analogPedal[0]->setAnalogResolution(ADC_RESOLUTION); + pedals[i].analogPedal[0]->enableEdgeSnap(); + pedals[i].analogPedal[0]->setSnapMultiplier(pedals[i].snapMultiplier); + pedals[i].analogPedal[0]->setActivityThreshold(pedals[i].activityThreshold); if (lastUsedPedal == 0xFF) { lastUsedPedal = i; lastUsed = i; @@ -2427,10 +2566,10 @@ void controller_setup() } if (ultrasonicTrigger) HCSR04.begin(ultrasonicTrigger, ultrasonicEcho.data(), ultrasonicEcho.size()); - +/* for (int i = 0; i < 100; i++) { controller_run(false); // to avoid spurious readings } - +*/ set_initial_led_color(); } \ No newline at end of file diff --git a/src/DisplayOLED.h b/src/DisplayOLED.h index 48e0083..2ecc923 100644 --- a/src/DisplayOLED.h +++ b/src/DisplayOLED.h @@ -1093,16 +1093,19 @@ int frameCount = sizeof(frames) / sizeof(FrameCallback); OverlayCallback overlays[] = { topOverlay, bottomOverlay }; int overlaysCount = sizeof(overlays) / sizeof(OverlayCallback); -void display_init() +void display_boot() { display.init(); display.setContrast(255); + if (flipScreen) display.flipScreenVertically(); + #ifdef WIFI if (wifiEnabled) { display.clear(); display.drawXbm((display.getWidth() - WIFI_LOGO_WIDTH) / 2, (display.getHeight() - WIFI_LOGO_HEIGHT) / 2, WIFI_LOGO_WIDTH, WIFI_LOGO_HEIGHT, WiFiLogo); display.display(); + delay(1000); } #endif @@ -1111,14 +1114,19 @@ void display_init() display.clear(); display.drawXbm((display.getWidth() - BLUETOOTH_LOGO_WIDTH) / 2, (display.getHeight() - BLUETOOTH_LOGO_HEIGHT) / 2, BLUETOOTH_LOGO_WIDTH, BLUETOOTH_LOGO_HEIGHT, BluetoothLogo); display.display(); - + delay(1000); } #endif + display.clear(); + display.display(); +} +void display_init() +{ // The ESP is capable of rendering 60fps in 80Mhz mode // but that won't give you much time for anything else // run it in 160Mhz mode or just set it to 30 fps - ui.setTargetFPS(60); + ui.setTargetFPS(30); // Customize the active and inactive symbol ui.setActiveSymbol(activeSymbol); diff --git a/src/DisplayTFT.h b/src/DisplayTFT.h index 726a7da..deaf0b0 100644 --- a/src/DisplayTFT.h +++ b/src/DisplayTFT.h @@ -1046,6 +1046,8 @@ void drawFrame1(int16_t x, int16_t y) for (uint16_t i = 0; i < POINTS; i++) { uint16_t h = (historyStart + i) % POINTS; uint16_t h1 = (h + 1) % POINTS; + if (scanLoopHistory[h] != 0 && scanLoopHistory[h1] != 0) sprite.drawLine(i, map2(scanLoopHistory[h], 100, 0, 3, sprite.height() - 3), i + 1, map2(scanLoopHistory[h1], 100, 0, 3, sprite.height() - 3), TFT_INDEX_MAGENTA); + if (serviceLoopHistory[h] != 0 && serviceLoopHistory[h1] != 0) sprite.drawLine(i, map2(serviceLoopHistory[h], 100, 0, 3, sprite.height() - 3), i + 1, map2(serviceLoopHistory[h1], 100, 0, 3, sprite.height() - 3), TFT_INDEX_CYAN); if (memoryHistory[h] != 0 && memoryHistory[h1] != 0) sprite.drawLine(i, map2(memoryHistory[h], 100, 0, 3, sprite.height() - 3), i + 1, map2(memoryHistory[h1], 100, 0, 3, sprite.height() - 3), TFT_INDEX_RED); if (fragmentationHistory[h] != 0 && fragmentationHistory[h1] != 0) sprite.drawLine(i, map2(fragmentationHistory[h], 100, 0, 3, sprite.height() - 3), i + 1, map2(fragmentationHistory[h1], 100, 0, 3, sprite.height() - 3), TFT_INDEX_YELLOW); if (wifiHistory[h] != 0 && wifiHistory[h1] != 0) sprite.drawLine(i, map2(wifiHistory[h], 100, 0, 3, sprite.height() - 3), i + 1, map2(wifiHistory[h1], 100, 0, 3, sprite.height() - 3), TFT_INDEX_BLUE); @@ -1060,13 +1062,31 @@ void drawFrame1(int16_t x, int16_t y) sprite.drawString("-50dB", 0, sprite.height() / 2); sprite.setTextDatum(ML_DATUM); sprite.drawString("-90dB", 0, sprite.height() / 2 + (sprite.height() - 8) / 2); + + sprite.setTextColor(TFT_INDEX_MAGENTA, TFT_INDEX_BLACK); + sprite.setTextDatum(MC_DATUM); + sprite.drawString("10ms", sprite.width() / 4, sprite.height() / 2 - (sprite.height() - 8) / 2); + sprite.setTextDatum(MC_DATUM); + sprite.drawString("5ms", sprite.width() / 4, sprite.height() / 2); + sprite.setTextDatum(MC_DATUM); + sprite.drawString("0ms", sprite.width() / 4, sprite.height() / 2 + (sprite.height() - 8) / 2); + sprite.setTextColor(TFT_INDEX_RED, TFT_INDEX_BLACK); sprite.setTextDatum(MC_DATUM); - sprite.drawString("200Kb", sprite.width() / 2, sprite.height() / 2 - (sprite.height() - 8) / 2); + sprite.drawString("120Kb", sprite.width() / 2, sprite.height() / 2 - (sprite.height() - 8) / 2); sprite.setTextDatum(MC_DATUM); - sprite.drawString("100Kb", sprite.width() / 2, sprite.height() / 2); + sprite.drawString("60Kb", sprite.width() / 2, sprite.height() / 2); sprite.setTextDatum(MC_DATUM); sprite.drawString("0Kb", sprite.width() / 2, sprite.height() / 2 + (sprite.height() - 8) / 2); + + sprite.setTextColor(TFT_INDEX_CYAN, TFT_INDEX_BLACK); + sprite.setTextDatum(MC_DATUM); + sprite.drawString("10ms", 3 * sprite.width() / 4, sprite.height() / 2 - (sprite.height() - 8) / 2); + sprite.setTextDatum(MC_DATUM); + sprite.drawString("5ms", 3 * sprite.width() / 4, sprite.height() / 2); + sprite.setTextDatum(MC_DATUM); + sprite.drawString("0ms", 3 * sprite.width() / 4, sprite.height() / 2 + (sprite.height() - 8) / 2); + sprite.setTextColor(TFT_INDEX_GREEN, TFT_INDEX_BLACK); sprite.setTextDatum(MR_DATUM); sprite.drawString("5.0V", sprite.width() - 1, sprite.height() / 2 - (sprite.height() - 8) / 2); @@ -1074,6 +1094,7 @@ void drawFrame1(int16_t x, int16_t y) sprite.drawString("4.0V", sprite.width() - 1, sprite.height() / 2); sprite.setTextDatum(MR_DATUM); sprite.drawString("3.0V", sprite.width() - 1, sprite.height() / 2 + (sprite.height() - 8) / 2); + sprite.pushSprite(0, 27); sprite.deleteSprite(); #endif @@ -1383,18 +1404,20 @@ void drawFrame3(int16_t x, int16_t y) } -void display_init() +void display_boot() { +#ifdef ARDUINO_LILYGO_T_DISPLAY_S3 + // When T-Display-S3 is powered by battery, GPIO15 must be set to HIGH to turn on the backlight. + pinMode(15, OUTPUT); + digitalWrite(15, HIGH); + if (TFT_BL > 0) { // TFT_BL has been set in the TFT_eSPI library in the User Setup file ARDUINO_LILYGO_T_DISPLAY.h + pinMode(TFT_BL, OUTPUT); // Set backlight pin GPIO38 to output mode + digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); // Turn backlight on. TFT_BACKLIGHT_ON has been set in the TFT_eSPI library in the User Setup file ARDUINO_LILYGO_T_DISPLAY.h + } +#endif display.init(); flipScreen ? display.setRotation(3) : display.setRotation(1); display.fillScreen(TFT_BLACK); - /* - if (TFT_BL > 0) { // TFT_BL has been set in the TFT_eSPI library in the User Setup file ARDUINO_LILYGO_T_DISPLAY.h - pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode - digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); // Turn backlight on. TFT_BACKLIGHT_ON has been set in the TFT_eSPI library in the User Setup file ARDUINO_LILYGO_T_DISPLAY.h - } - */ - display.fillScreen(TFT_WHITE); display.setSwapBytes(true); display.pushImage((display.width() - PEDALINO_LOGO_WIDTH) / 2, (display.height() - PEDALINO_LOGO_HEIGHT) / 2, PEDALINO_LOGO_WIDTH, PEDALINO_LOGO_HEIGHT, PedalinoLogo); @@ -1419,7 +1442,12 @@ void display_init() #endif display.fillScreen(TFT_BLACK); - displayInit = false; +} + +void display_init() +{ + flipScreen ? display.setRotation(3) : display.setRotation(1); + displayInit = false; } void display_ui_update_disable() diff --git a/src/Pedalino.h b/src/Pedalino.h index 65b613d..eb53bfa 100644 --- a/src/Pedalino.h +++ b/src/Pedalino.h @@ -24,9 +24,12 @@ __________ .___ .__ .__ _____ .__ .__ #define BANKS 21 // 20 banks + 1 bank for global actions #define PEDALS 6 // real number of pedals is board specific (see below) #define CONTROLS 100 -#define SEQUENCES 16 +#define SEQUENCES 20 #define STEPS 10 // number of steps for each sequence #define LADDER_STEPS 6 // max number of controls in a resistor ladder +#define ADC_BOARDS 4 // +#define ADC_INPUTS 4 // ADS1115 number of analog inputs +#define ADC_CHANNELS (ADC_BOARDS * ADC_INPUTS) #define LEDS 10 // number of WS2812B leds (254 max) #define LED_RGB_ORDER RGB // do not change it, RGB order is managed by program because FastLED library does not support changing RGB order at runtime #define SLOTS_ROWS 2 @@ -85,7 +88,7 @@ const byte pinA[] = {GPIO_NUM_36, GPIO_NUM_39, GPIO_NUM_34, GPIO_NUM_35, GPIO_NU #undef PEDALS #define PEDALS 9 // https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/gpio.html -// Strapping pins: 1, 3, 45, 46 +// Strapping pins: 0, 3, 45, 46 // ADC1: 1-10 // ADC2: 11-20 (19=D- 20=D+) (ADC2 module is also used by the Wi-Fi) // SPI0/1: 26-32 (usually used for SPI flash and PSRAM) @@ -105,18 +108,24 @@ const byte pinA[] = {GPIO_NUM_4, GPIO_NUM_5, GPIO_NUM_6, GPIO_NUM_7, GPIO_NU #undef PEDALS #define PEDALS 8 // https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/gpio.html -// Strapping pins: 1, 3, 45, 46 +// Strapping pins: 0, 3, 45, 46 // ADC1: 1-10 // ADC2: 11-20 (19=D- 20=D+) (ADC2 module is also used by the Wi-Fi) // SPI0/1: 26-32 (usually used for SPI flash and PSRAM) // SPI0/1: 33-37 (board with ESP32-S3R8 chip not recommended for other uses) -const byte pinD[] = {GPIO_NUM_10, GPIO_NUM_2, GPIO_NUM_43, GPIO_NUM_44, GPIO_NUM_21, GPIO_NUM_1, GPIO_NUM_14, GPIO_NUM_0}; -const byte pinA[] = {GPIO_NUM_11, GPIO_NUM_12, GPIO_NUM_13, GPIO_NUM_16, GPIO_NUM_17, GPIO_NUM_18, GPIO_NUM_14, GPIO_NUM_0}; +//const byte pinD[] = {GPIO_NUM_10, GPIO_NUM_2, GPIO_NUM_43, GPIO_NUM_44, GPIO_NUM_21, GPIO_NUM_1, GPIO_NUM_14, GPIO_NUM_0}; +//const byte pinA[] = {GPIO_NUM_11, GPIO_NUM_12, GPIO_NUM_13, GPIO_NUM_16, GPIO_NUM_17, GPIO_NUM_18, GPIO_NUM_14, GPIO_NUM_0}; +// Analog pedals are supported only on pedal 4, 5 and 6 because there are not enough available GPIO on ADC1 +//const byte pinD[] = {GPIO_NUM_11, GPIO_NUM_12, GPIO_NUM_13, GPIO_NUM_16, GPIO_NUM_17, GPIO_NUM_18, GPIO_NUM_14, GPIO_NUM_0}; +//const byte pinA[] = {GPIO_NUM_44, GPIO_NUM_43, GPIO_NUM_21, GPIO_NUM_10, GPIO_NUM_2, GPIO_NUM_1, GPIO_NUM_14, GPIO_NUM_0}; +// Analog pedals are not supported on pedal 1 and 2 because there are only 4 available GPIOs on ADC1 +const byte pinD[] = {GPIO_NUM_11, GPIO_NUM_12, GPIO_NUM_13, GPIO_NUM_16, GPIO_NUM_17, GPIO_NUM_18, GPIO_NUM_14, GPIO_NUM_0}; +const byte pinA[] = {GPIO_NUM_44, GPIO_NUM_43, GPIO_NUM_10, GPIO_NUM_3, GPIO_NUM_2, GPIO_NUM_1, GPIO_NUM_14, GPIO_NUM_0}; #define FACTORY_DEFAULT_PIN GPIO_NUM_0 // Button BOOT #define DIN_MIDI_IN_PIN GPIO_NUM_1 -#define DIN_MIDI_OUT_PIN GPIO_NUM_3 +#define DIN_MIDI_OUT_PIN GPIO_NUM_1 #define BATTERY_PIN GPIO_NUM_4 // Pin connected to BAT (BAT is not VBAT) -#define FASTLEDS_DATA_PIN GPIO_NUM_3 +#define FASTLEDS_DATA_PIN GPIO_NUM_21 #else #undef PEDALS #define PEDALS 7 @@ -134,6 +143,7 @@ const byte pinA[] = {GPIO_NUM_36, GPIO_NUM_39, GPIO_NUM_34, GPIO_NUM_35, GPIO_NU #define PIN_D(x) pinD[x] #define PIN_A(x) pinA[x] +#define FASTLED_RMT_MAX_TICKS_FOR_GTX_SEM (2000/portTICK_PERIOD_MS) // https://github.com/davidlmorris/FastLED_Hang_Fix_Demo #include // https://github.com/FastLED/FastLED CRGB fastleds[LEDS+1]; // fastleds[LEDS] not used EOrder rgbOrder = RGB; @@ -145,6 +155,7 @@ typedef uint8_t byte; #include // https://github.com/MajicDesigns/MD_REncoder #include // https://github.com/bxparks/AceButton #include // https://github.com/RyoKosaka/HelloDrum-arduino-Library +#include // https://github.com/adafruit/Adafruit_ADS1X15 //#include "AnalogPad.h" using namespace ace_button; @@ -230,8 +241,9 @@ using namespace ace_button; #define PED_ANALOG_LATCH 12 #define PED_ANALOG_PAD 13 // Piezo #define PED_ANALOG_PAD_MOMENTARY 14 // Piezo + switch +#define PED_ANALOG4 15 // ADS1115 -const char *pedalModeName[] = {"", "None", "Momentary 1", "Latch", "Analog", "Jog Wheel", "Momentary 2", "Momentary 3", "Latch 2", "Ladder", "Ultrasonic", "Analog+Momentary", "Analog+Latch", "Analog Pad", "Analog Pad+Momentary"}; +const char *pedalModeName[] = {"", "None", "Momentary 1", "Latch", "Analog", "Jog Wheel", "Momentary 2", "Momentary 3", "Latch 2", "Ladder", "Ultrasonic", "Analog+Momentary", "Analog+Latch", "Analog Pad", "Analog Pad+Momentary", "Analog 4"}; #define PED_PRESS_1 1 #define PED_PRESS_2 2 @@ -314,9 +326,9 @@ const char *pedalAnalogResponse[] = {"Linear", "Log", "Antilog"}; #define PED_TIMESIGNATURE_LAST 7 #define MIDI_RESOLUTION 128 // MIDI 7-bit CC resolution -#define ADC_RESOLUTION 1024 -#define ADC_RESOLUTION_BITS 10 // hardware 9 to 12-bit ADC converter resolution +#define ADC_RESOLUTION_BITS 9 // hardware 9 to 12-bit ADC converter resolution // software 1 to 16-bit resolution +#define ADC_RESOLUTION (1 << ADC_RESOLUTION_BITS) struct action { char tag0[MAXACTIONNAME+1]; @@ -330,7 +342,7 @@ struct action { uint32_t color1; byte event; byte midiMessage; - byte midiChannel; /* MIDI channel 1-16 */ + byte midiChannel; /* MIDI channel 1-16, 0 = None, 17 = All or sequence 1-20 */ byte midiCode; /* Program Change, Control Code, Note or Pitch Bend value to send */ byte midiValue1; byte midiValue2; @@ -394,7 +406,8 @@ struct pedal { AceButton *button[LADDER_STEPS]; ButtonConfig *buttonConfig; MD_REncoder *jogwheel; - ResponsiveAnalogRead *analogPedal; + ResponsiveAnalogRead *analogPedal[ADC_CHANNELS]; + Adafruit_ADS1115 *ads[ADC_BOARDS]; //AnalogPad *analogPad; HelloDrum *analogPad; }; @@ -452,6 +465,8 @@ AceButton bootButton; ButtonConfig bootButtonConfig; uint16_t ladderLevels[LADDER_STEPS+1] = {497, 660, 752, 816, 876, 945, ADC_RESOLUTION - 1}; // TC-Helicon Switch 6 +bool ads1115Found[ADC_BOARDS]; + char slots[SLOTS_ROWS][SLOTS_COLS][MAXBANKNAME+1]; bool tapDanceMode = false; @@ -465,12 +480,15 @@ unsigned long displayOffCountdownStart = 0; unsigned long screenSaverTimeout = 1000*60*60; // 1 hour volatile byte currentProfile = 0; +volatile bool controllerRunning = false; volatile bool reloadProfile = true; volatile bool saveProfile = false; volatile bool loadConfig = false; volatile bool scrollingMode = false; // Display scrolling mode -volatile bool displayInit = false; +volatile bool displayInit = true; volatile bool startWebServer = false; +volatile unsigned long scanLoop = 0; +volatile unsigned long serviceLoop = 0; byte currentBank = 1; byte currentPedal = 0; @@ -537,10 +555,13 @@ uint16_t batteryVoltage = 4200; // mV #define GRAPH_DURATION_QUARTER_MIN GRAPH_DURATION_QUARTER_SEC / 60 #define GRAPH_DURATION_QUARTER_HOUR GRAPH_DURATION_QUARTER_MIN / 60 RTC_DATA_ATTR uint16_t historyStart = 0; -RTC_DATA_ATTR byte memoryHistory[POINTS]; // 0% = 0Kb 100% = 200Kb -RTC_DATA_ATTR byte fragmentationHistory[POINTS]; // 0% = 0Kb 100% = 200Kb -RTC_DATA_ATTR byte wifiHistory[POINTS]; // 0% = -90dB 100% = -10dB -RTC_DATA_ATTR byte batteryHistory[POINTS]; // 0% = 3.0V 100% = 5.0V +RTC_DATA_ATTR byte memoryHistory[POINTS]; // 0% = 0Kb 100% = 120Kb +RTC_DATA_ATTR byte fragmentationHistory[POINTS]; // 0% = 0Kb 100% = 120Kb +RTC_DATA_ATTR byte wifiHistory[POINTS]; // 0% = -90dB 100% = -10dB +RTC_DATA_ATTR byte batteryHistory[POINTS]; // 0% = 3.0V 100% = 5.0V +RTC_DATA_ATTR byte scanLoopHistory[POINTS]; // 0% = 0us 100% = 10ms +RTC_DATA_ATTR byte serviceLoopHistory[POINTS]; // 0% = 0ms 100% = 10ms + #endif // DIAGNOSTIC uint16_t scan[POINTS]; diff --git a/src/PedalinoMini.cpp b/src/PedalinoMini.cpp index 7579d2a..4d00451 100644 --- a/src/PedalinoMini.cpp +++ b/src/PedalinoMini.cpp @@ -84,9 +84,10 @@ __________ .___ .__ .__ _____ .__ .__ #include #endif -TaskHandle_t loopCore0; // loop() on core 0 +TaskHandle_t loopCore0; // loop0() on core 0 +TaskHandle_t loopCore1; // loop1() on core 1 void loop0(void * pvParameters); - +void loop1(void * pvParameters); void verbose_print_reset_reason(int reason) { @@ -135,15 +136,13 @@ void wifi_and_battery_level() { digitalWrite(BATTERY_ADC_EN, HIGH); delay(10); #endif // BATTERY_ADC_EN - uint16_t v = analogRead(BATTERY_PIN); + //analogReadResolution(12); + uint16_t voltage = analogReadMilliVolts(BATTERY_PIN) * 2; // Read the ADC voltage using the built in factory calibration, no conversion needed. + // Battery voltage is measured using a voltage divider + //analogReadResolution(ADC_RESOLUTION_BITS); #ifdef BATTERY_ADC_EN digitalWrite(BATTERY_ADC_EN, LOW); #endif // BATTERY_ADC_EN -#ifdef ARDUINO_BPI_LEAF_S3 - uint16_t voltage = ((uint32_t)v * 2 * 37 * vref) / 10240; // float voltage = ((float)v / 1024.0) * 2.0 * 3.3 * (vref / 1000.0); -#else - uint16_t voltage = ((uint32_t)v * 2 * 33 * vref) / 10240; // float voltage = ((float)v / 1024.0) * 2.0 * 3.3 * (vref / 1000.0); -#endif // ARDUINO_BPI_LEAF_S3 uint16_t difference = abs(voltage - batteryVoltage); //DPRINT("%d %d %d %d\n", voltage, batteryVoltage, difference, map2(constrain(batteryVoltage, 3000, 5000), 3000, 5000, 0, 100)); if (difference > 100) @@ -156,10 +155,12 @@ void wifi_and_battery_level() { static byte sec = 0; if (sec == 0) { - memoryHistory[historyStart] = map2(freeMemory, 0, 200*1024, 0, 100); - fragmentationHistory[historyStart] = map2(maxAllocation, 0, 200*1024, 0, 100); - wifiHistory[historyStart] = map2(constrain(wifiLevel, -90, -10), -90, -10, 0, 100); - batteryHistory[historyStart] = map2(constrain(batteryVoltage, 3000, 5000), 3000, 5000, 0, 100); + memoryHistory[historyStart] = map2(freeMemory, 0, 120*1024, 0, 100); + fragmentationHistory[historyStart] = map2(maxAllocation, 0, 120*1024, 0, 100); + wifiHistory[historyStart] = map2(constrain(wifiLevel, -90, -10), -90, -10, 0, 100); + batteryHistory[historyStart] = map2(constrain(batteryVoltage, 3000, 5000), 3000, 5000, 0, 100); + scanLoopHistory[historyStart] = map2(constrain(scanLoop, 0, 10000), 0, 10000, 0, 100); + serviceLoopHistory[historyStart] = map2(constrain(serviceLoop, 0, 10000), 0, 10000, 0, 100); historyStart = (historyStart + 1) % POINTS; } sec = (sec + 1) % SECONDS_BETWEEN_SAMPLES; @@ -203,6 +204,8 @@ void setup() DPRINT("Internal Total Heap %d, Internal Free Heap %d\n", ESP.getHeapSize(), ESP.getFreeHeap()); DPRINT("PSRAM Total Heap %d, PSRAM Free Heap %d\n", ESP.getPsramSize(), ESP.getFreePsram()); + adc_power_acquire(); + // Reset the pin used for power off // If the specified GPIO is a valid RTC GPIO, init as digital GPIO for (byte p = 0; p < PEDALS; p++) { @@ -211,7 +214,7 @@ void setup() #ifdef BATTERY_PIN //Check type of calibration value used to characterize ADC for BATTERY_PIN - esp_adc_cal_characteristics_t adc_chars; + esp_adc_cal_characteristics_t adc_chars = {}; #if defined ARDUINO_LILYGO_T_DISPLAY // GPIO34 esp_adc_cal_value_t val_type = esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &adc_chars); @@ -265,11 +268,6 @@ void setup() DPRINT("Internal Total Heap %d, Internal Free Heap %d\n", ESP.getHeapSize(), ESP.getFreeHeap()); DPRINT("PSRAM Total Heap %d, PSRAM Free Heap %d\n", ESP.getPsramSize(), ESP.getFreePsram()); - sketchSize = ESP.getSketchSize(); - sketchMD5 = ESP.getSketchMD5(); - - DPRINT("Sketch Size %d bytes, Firmware Hash %s\n", sketchSize, sketchMD5.c_str()); - if (!SPIFFS.begin()) { DPRINT("SPIFFS mount FAILED\n"); } @@ -280,6 +278,13 @@ void setup() eeprom_init_or_erase(); eeprom_read_global(); + display_boot(); + + sketchSize = ESP.getSketchSize(); + sketchMD5 = ESP.getSketchMD5(); + + DPRINT("Sketch Size %d bytes, Firmware Hash %s\n", sketchSize, sketchMD5.c_str()); + FastLED.addLeds(fastleds, LEDS); fill_solid(fastleds, LEDS, CRGB::Black); FastLED.show(); @@ -289,8 +294,6 @@ void setup() for (byte l = 0; l < LEDS; l++) lastLedColor[b][l] = CRGB::Black; - display_init(); - // Reset to factory default if BOOT key is pressed and hold for alt least 15 seconds at power on pinMode(FACTORY_DEFAULT_PIN, INPUT_PULLUP); @@ -504,9 +507,18 @@ void setup() set_initial_led_color(); + xTaskCreatePinnedToCore( + loop1, /* Task function. */ + "loopTask1", /* name of task. */ + 8192, /* Stack size of task */ + NULL, /* parameter of the task */ + 1, /* priority of the task */ + &loopCore1, /* Task handle to keep track of created task */ + 1); /* pin task to core 1 */ + xTaskCreatePinnedToCore( loop0, /* Task function. */ - "loopTask", /* name of task. */ + "loopTask0", /* name of task. */ 8192, /* Stack size of task */ NULL, /* parameter of the task */ 1, /* priority of the task */ @@ -521,17 +533,44 @@ void loop() { // High priority activities run on Core 1 + unsigned long startClock = micros(); + // Check whether the input has changed since last time, if so, send the new value over MIDI controller_run(); // Send MTC or MIDI CLock MTC.loop(); + + // It is not a priority task but it only works on the same core where FastLED init run + // https://github.com/davidlmorris/FastLED_Hang_Fix_Demo + // It has no effect when not in diagnostic screen + + if (scrollingMode && !displayOff) { + switch (currentProfile) { + case 0: + //blendwave(); + ease2(); + break; + case 1: + pacifica_loop(); + break; + case 2: + pride(); + break; + } + FastLED.show(); + } + + scanLoop = micros() - startClock; } -void loop0(void * pvParameters) +void loop1(void * pvParameters) { - // Low priority activities run on Core 0 within WiFi and Bluetooth + // High priority activities run on Core 1 + + unsigned long startClock = micros(); + unsigned long endClock; for(;;) { @@ -562,6 +601,26 @@ void loop0(void * pvParameters) if (interfaces[PED_IPMIDI].midiIn && IP_MIDI.read()) DPRINTMIDI("IP MIDI", IP_MIDI.getType(), IP_MIDI.getChannel(), IP_MIDI.getData1(), IP_MIDI.getData2()); } + } +#endif // WIFI + + endClock = micros(); + serviceLoop = endClock - startClock; + startClock = endClock; + } +} + +void loop0(void * pvParameters) +{ + // Low priority activities run on Core 0 within WiFi and Bluetooth + + for(;;) { + + // Feed the watchdog of FreeRTOS + vTaskDelay(10); + +#ifdef WIFI + if (wifiEnabled) { http_run(); @@ -586,22 +645,6 @@ void loop0(void * pvParameters) // Update display display_update(); - if (scrollingMode && !displayOff) { - switch (currentProfile) { - case 0: - //blendwave(); - ease2(); - break; - case 1: - pacifica_loop(); - break; - case 2: - pride(); - break; - } - FastLED.show(); - } - switch (firmwareUpdate) { case PED_UPDATE_ARDUINO_OTA: case PED_UPDATE_HTTP: diff --git a/src/USBMidiIn.h b/src/USBMidiIn.h index 15248e8..7db3ea4 100644 --- a/src/USBMidiIn.h +++ b/src/USBMidiIn.h @@ -252,12 +252,20 @@ void usb_midi_connect() #if defined(ARDUINO_BPI_LEAF_S3) || defined(ARDUINO_LILYGO_T_DISPLAY_S3) //usb_midi.setStringDescriptor("PedalinoMini USB MIDI"); TinyUSBDevice.setManufacturerDescriptor("Pedalino"); - TinyUSBDevice.setProductDescriptor("PedalinoMini USB MIDI"); - usb_midi.setCableName(1, "PedalinoMini"); + TinyUSBDevice.setProductDescriptor("PedalinoMiniā„¢"); + usb_midi.setCableName(1, "USB MIDI"); #endif // Initiate USB MIDI communications, listen to all channels USB_MIDI.begin(MIDI_CHANNEL_OMNI); +#if defined(ARDUINO_BPI_LEAF_S3) || defined(ARDUINO_LILYGO_T_DISPLAY_S3) + // If already enumerated, additional class driverr begin() e.g msc, hid, midi won't take effect until re-enumeration + if (TinyUSBDevice.mounted()) { + TinyUSBDevice.detach(); + delay(10); + TinyUSBDevice.attach(); + } +#endif // Enable/disable MIDI Thru interfaces[PED_USBMIDI].midiThru ? USB_MIDI.turnThruOn() : USB_MIDI.turnThruOff(); diff --git a/src/Version.h b/src/Version.h index 66c41e1..e3f15d8 100644 --- a/src/Version.h +++ b/src/Version.h @@ -18,9 +18,9 @@ extern "C" { /** Major version number (X.x.x) */ #define PEDALINO_VERSION_MAJOR 3 /** Minor version number (x.X.x) */ -#define PEDALINO_VERSION_MINOR 2 +#define PEDALINO_VERSION_MINOR 5 /** Patch version number (x.x.X) */ -#define PEDALINO_VERSION_PATCH 2 +#define PEDALINO_VERSION_PATCH 0 #define xstr(s) sstr(s) // stringize the result of expansion of a macro argument #define sstr(s) #s diff --git a/src/WebConfigAsync.h b/src/WebConfigAsync.h index ab7920e..5e53fc1 100644 --- a/src/WebConfigAsync.h +++ b/src/WebConfigAsync.h @@ -10,8 +10,8 @@ __________ .___ .__ .__ _____ .__ .__ */ String theme = "bootstrap"; -String httpUsername = "admin"; -String httpPassword = getChipId(); +String httpUsername = ""; +String httpPassword = ""; bool authenticated = false; #ifdef NOWIFI @@ -116,7 +116,7 @@ bool get_top_page(int p, unsigned int start, unsigned int len) { page += F(" "); if ( theme == "bootstrap" ) { #ifdef BOOTSTRAP_LOCAL - page += F(""); + page += F(""); #else page += F(""); #endif @@ -125,7 +125,7 @@ bool get_top_page(int p, unsigned int start, unsigned int len) { page += theme; page += F("/bootstrap.min.css' rel='stylesheet' crossorigin='anonymous'>"); } - if (p == 2) page += F(""); + if (p == 2) page += F(""); page += F(""); page += F(""); @@ -363,7 +363,7 @@ void get_footer_page() { page += F(""); #ifdef BOOTSTRAP_LOCAL - page += F(""); + page += F(""); #else page += F(""); #endif @@ -462,6 +462,9 @@ void get_root_page(unsigned int start, unsigned int len) { break; } page += F(""); + page += F("
PlatformIO ESP32 Platform
"); + page += xstr(ESP32_PLATFORM_VERSION); + page += F("
"); page += F("
IDF Version
"); page += ESP_IDF_VERSION_MAJOR; page += F("."); @@ -484,6 +487,18 @@ void get_root_page(unsigned int start, unsigned int len) { page += F("
PlatformIO Build Env
"); page += xstr(PLATFORMIO_ENV); page += F("
"); + + page += F("
Bootstrap Version
"); + page += F(""); + page += F("
Firmware
"); page += PEDALINO_VERSION_MAJOR; page += F("."); @@ -491,7 +506,6 @@ void get_root_page(unsigned int start, unsigned int len) { page += F("."); page += PEDALINO_VERSION_PATCH; page += F("
"); - page += F("
Firmware Size
"); page += sketchSize; page += F(" bytes
"); @@ -499,7 +513,7 @@ void get_root_page(unsigned int start, unsigned int len) { page += sketchMD5; page += F(""); page += F(""); - + if (trim_page(start, len)) return; page += F("
"); @@ -1355,6 +1369,7 @@ void get_actions_page(unsigned int start, unsigned int len) { break; case PED_ANALOG: + case PED_ANALOG4: case PED_ULTRASONIC: page += F(""); + page += F(""); } page += F(""); @@ -2846,6 +2896,7 @@ void get_pedals_page(unsigned int start, unsigned int len) { " document.getElementById('threshold_' + i).style.display = 'block';" " break;" " case 'Analog':" + " case 'Analog 4':" " document.getElementById('polarityCheck_' + i).style.display = 'block';" " document.getElementById('mapSelect_' + i).style.display = 'block';" " document.getElementById('minInput_' + i).style.display = 'block';" @@ -3448,7 +3499,9 @@ void get_sequences_page(unsigned int start, unsigned int len) { if (trim_page(start, len)) return; page += F("
"); - page += F("
"); + page += F(""); page += F("
"); if (trim_page(start, len)) return; @@ -3648,6 +3726,8 @@ void get_sequences_page(unsigned int start, unsigned int len) { page += F("function init_line(i) {" " document.getElementById('channelLabel' + i).textContent = 'Channel';" + " document.getElementById('channelDiv' + i).removeAttribute('hidden');" + " document.getElementById('sequenceDiv' + i).setAttribute('hidden', 'hidden');" " document.getElementById('codeLabel' + i).textContent = 'Code';" " document.getElementById('valueLabel' + i).textContent = 'Value';" " document.getElementById('channelSelect' + i).disabled = false;" @@ -3675,7 +3755,6 @@ void get_sequences_page(unsigned int start, unsigned int len) { page += F(" case 'Bank Select+':" " case 'Bank Select-':" - " document.getElementById('channelLabel' + i).textContent = 'Channel';" " document.getElementById('codeLabel' + i).textContent = 'MSB';" " document.getElementById('valueLabel' + i).textContent = 'LSB';" " break;" @@ -3684,7 +3763,8 @@ void get_sequences_page(unsigned int start, unsigned int len) { " document.getElementById('codeInput' + i).disabled = true;" " break;" " case 'Sequence':" - " document.getElementById('channelLabel' + i).textContent = 'Sequence';" + " document.getElementById('channelDiv' + i).setAttribute('hidden', 'hidden');" + " document.getElementById('sequenceDiv' + i).removeAttribute('hidden');" " document.getElementById('codeInput' + i).disabled = true;" " document.getElementById('valueInput' + i).disabled = true;" " document.getElementById('ledSelect' + i).disabled = true;" @@ -5319,7 +5399,7 @@ void http_handle_login(AsyncWebServerRequest *request) { } else { authenticated = false; get_login_page(); - request->send(200, "text/html", page); + request->send(200, "text/html", page.c_str()); } } @@ -5333,7 +5413,7 @@ void http_handle_post_login(AsyncWebServerRequest *request) { } } get_login_page(); - request->send(200, "text/html", page); + request->send(200, "text/html", page.c_str()); } void http_handle_globals(AsyncWebServerRequest *request) { @@ -5375,9 +5455,9 @@ void http_handle_actions(AsyncWebServerRequest *request) { if (!httpUsername.isEmpty() && !request->authenticate(httpUsername.c_str(), httpPassword.c_str())) return request->requestAuthentication(); http_handle_globals(request); - if (request->hasArg("bank")) uibank = request->arg("bank"); - if (request->hasArg("control")) uicontrol = request->arg("control"); - if (request->hasArg("banksorder")) list = request->arg("banksorder"); + if (request->hasArg("bank")) uibank = request->arg("bank"); + if (request->hasArg("control")) uicontrol = request->arg("control"); + if (request->hasArg("banksorder")) list = request->arg("banksorder"); for (byte b = 0; b < BANKS; b++) { a[b] = actions[b]; @@ -5637,6 +5717,7 @@ void http_handle_post_actions(AsyncWebServerRequest *request) { case PED_SEQUENCE: case PED_SEQUENCE_STEP_BY_STEP_FWD: case PED_SEQUENCE_STEP_BY_STEP_REV: + act->midiChannel = constrain(request->arg(String("sequence") + String(i)).toInt(), 1, SEQUENCES); act->color0 = CRGB::Black; act->color1 = CRGB::Black; break; @@ -5853,7 +5934,7 @@ void http_handle_post_interfaces(AsyncWebServerRequest *request) { void http_handle_post_sequences(AsyncWebServerRequest *request) { String a; - const byte s = constrain(uisequence.toInt() - 1, 0, SEQUENCES); + const byte s = constrain(uisequence.toInt() - 1, 0, SEQUENCES - 1); unsigned int red, green, blue; for (unsigned int i = 0; i < STEPS; i++) { @@ -5864,6 +5945,13 @@ void http_handle_post_sequences(AsyncWebServerRequest *request) { a = request->arg(String("channel") + String(i+1)); sequences[s][i].midiChannel = constrain(a.toInt(), 0, 17); + switch (sequences[s][i].midiMessage) { + case PED_SEQUENCE: + a = request->arg(String("sequence") + String(i+1)); + sequences[s][i].midiChannel = constrain(a.toInt() - 1, 0, SEQUENCES - 1); + break; + } + a = request->arg(String("code") + String(i+1)); sequences[s][i].midiCode = constrain(a.toInt(), 0, MIDI_RESOLUTION - 1); @@ -6098,7 +6186,8 @@ void http_handle_post_options(AsyncWebServerRequest *request) { esp_bt_controller_disable(); #endif esp_wifi_stop(); - adc_power_off(); + //adc_power_off(); + adc_power_release(); delay(200); for (byte b = 0; b < BANKS; b++) { action *act = actions[b]; @@ -6156,7 +6245,6 @@ void http_handle_post_configurations(AsyncWebServerRequest *request) { } else if (request->arg("action").equals("apply") || request->arg("action").equals("append")) { String config = request->arg("filename"); - controller_delete(); spiffs_load_config(config, request->arg("actions2") == checked, request->arg("pedals2") == checked, @@ -6174,7 +6262,6 @@ void http_handle_post_configurations(AsyncWebServerRequest *request) { } else if (request->arg("action").equals("save") || request->arg("action").equals("appendsave")) { String config = request->arg("filename"); - controller_delete(); spiffs_load_config(config, request->arg("actions2") == checked, request->arg("pedals2") == checked, @@ -6556,12 +6643,12 @@ void http_setup() { httpServer.serveStatic("/schema.json", SPIFFS, "/schema.json").setDefaultFile("/schema.json").setCacheControl("max-age=600"); httpServer.serveStatic("/files", SPIFFS, "/").setDefaultFile("").setAuthentication(httpUsername.c_str(), httpPassword.c_str()); */ - httpServer.serveStatic("/favicon.ico", SPIFFS, "/favicon.ico"); - httpServer.serveStatic("/logo.png", SPIFFS, "/logo.png"); - httpServer.serveStatic("/css/bootstrap.min.css", SPIFFS, "/css/bootstrap.min.css"); - httpServer.serveStatic("/js/bootstrap.bundle.min.js", SPIFFS, "/js/bootstrap.bundle.min.js"); - httpServer.serveStatic("/js/Sortable.min.js", SPIFFS, "/js/Sortable.min.js"); - httpServer.serveStatic("/schema.json", SPIFFS, "/schema.json"); + httpServer.serveStatic("/favicon.ico", SPIFFS, "/favicon.ico").setCacheControl("max-age=600"); + httpServer.serveStatic("/logo.png", SPIFFS, "/logo.png").setCacheControl("max-age=600"); + httpServer.serveStatic("/css/bootstrap.min.css", SPIFFS, "/css/bootstrap.min.css").setCacheControl("max-age=600"); + httpServer.serveStatic("/js/bootstrap.bundle.min.js", SPIFFS, "/js/bootstrap.bundle.min.js").setCacheControl("max-age=600"); + httpServer.serveStatic("/js/Sortable.min.js", SPIFFS, "/js/Sortable.min.js").setCacheControl("max-age=600"); + httpServer.serveStatic("/schema.json", SPIFFS, "/schema.json").setCacheControl("max-age=600"); httpServer.serveStatic("/files", SPIFFS, "/").setDefaultFile("").setAuthentication(httpUsername.c_str(), httpPassword.c_str()); httpServer.on("/", http_handle_root);