From a25f1bd66b2ce5743a59d0cdc4b3e8e5cebfdb31 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 23 Feb 2023 23:54:07 +0100 Subject: [PATCH 001/102] fixed tests --- .github/workflows/ci.yml | 2 +- src/DistributionController.cpp | 13 ----- src/DistributionController.h | 47 ---------------- src/EffectsController.h | 4 +- src/PPUC.h | 5 +- test/DistributionController/platformio.ini | 23 -------- test/DistributionController/src/main.cpp | 33 ----------- test/DistributionController/test/README | 11 ---- test/EffectController/src/main.cpp | 4 +- test/EffectControllerPico/platformio.ini | 4 +- test/EffectControllerPico/src/main.cpp | 4 +- test/IOBoardController/platformio.ini | 2 +- test/IOBoardController/src/main.cpp | 17 +----- test/InputController/src/main.cpp | 5 +- .../platformio.ini | 4 +- test/NanoController/src/main.cpp | 56 +++++++++++++++++++ .../test/README | 0 test/NanoGIController/src/main.cpp | 19 ------- 18 files changed, 76 insertions(+), 177 deletions(-) delete mode 100644 src/DistributionController.cpp delete mode 100644 src/DistributionController.h delete mode 100644 test/DistributionController/platformio.ini delete mode 100644 test/DistributionController/src/main.cpp delete mode 100644 test/DistributionController/test/README rename test/{NanoGIController => NanoController}/platformio.ini (92%) create mode 100644 test/NanoController/src/main.cpp rename test/{NanoGIController => NanoController}/test/README (100%) delete mode 100644 test/NanoGIController/src/main.cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6684ce1..e4f6815 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - controller: ['DistributionController', 'EffectController', 'InputController', 'IOBoardController'] + controller: ['EffectController', 'EffectControllerPico', 'InputController', 'IOBoardController', 'NanoCOntroller'] name: PPUC ${{ matrix.controller }} diff --git a/src/DistributionController.cpp b/src/DistributionController.cpp deleted file mode 100644 index c0c9a38..0000000 --- a/src/DistributionController.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "DistributionController.h" - -VPXComLink* DistributionController::vpxComLink() { - return _vpxComLink; -} - -DistributionControllerTestButtons* DistributionController::testButtons() { - return _testButtons; -} - -EventDispatcher* DistributionController::eventDispatcher() { - return _eventDispatcher; -} diff --git a/src/DistributionController.h b/src/DistributionController.h deleted file mode 100644 index 7a728e6..0000000 --- a/src/DistributionController.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - DistributionController.h - Created by Markus Kalkbrenner. -*/ - -#ifndef DISTRIBUTIONCONTROLLER_h -#define DISTRIBUTIONCONTROLLER_h - -#include "PPUC.h" - -#include "EventDispatcher/EventDispatcher.h" -#include "EventDispatcher/EventListener.h" -#include "InputDevices/DistributionControllerTestButtons.h" -#include "VisualPinball/VPXComLink.h" - -class DistributionController { -public: - DistributionController(int controllerType, byte pf) { - platform = pf; - _eventDispatcher = new EventDispatcher(); - - if (controllerType == CONTROLLER_MEGA_ALL_INPUT) { - _vpxComLink = new VPXComLink(_eventDispatcher, platform); - _testButtons = new DistributionControllerTestButtons(_eventDispatcher); - - _eventDispatcher->addListener(_vpxComLink, EVENT_SOURCE_SWITCH); - } else { - Serial.print("Unsupported Distribution Controller: "); - Serial.println(controllerType); - } - } - - VPXComLink* vpxComLink(); - - DistributionControllerTestButtons* testButtons(); - - EventDispatcher* eventDispatcher(); - - byte platform; - -private: - VPXComLink* _vpxComLink; - DistributionControllerTestButtons* _testButtons; - EventDispatcher* _eventDispatcher; -}; - -#endif diff --git a/src/EffectsController.h b/src/EffectsController.h index aac4396..f1ab9d9 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -48,7 +48,7 @@ #define UPDATE_INTERVAL_WS2812FX_AFTERGLOW 3 #define UPDATE_INTERVAL_WS2812FX_BRIGHTNESS 10 -#if PPUC_CONTROLLER == CONTROLLER_TEENSY_OUTPUT +#if PPUC_CONTROLLER == CONTROLLER_TEENSY_OUTPUT || PPUC_CONTROLLER == CONTROLLER_TEENSY_OUTPUT_2 || PPUC_CONTROLLER == CONTROLLER_PICO_OUTPUT #define PPUC_MAX_WS2812FX_DEVICES 7 #define PPUC_MAX_BRIGHTNESS_CONTROLS 4 #else @@ -95,7 +95,7 @@ class EffectsController : public EventListener { _eventDispatcher = new EventDispatcher(); _eventDispatcher->addListener(this); - if (controllerType == CONTROLLER_TEENSY_OUTPUT) { + if (controllerType == CONTROLLER_TEENSY_OUTPUT || controllerType == CONTROLLER_TEENSY_OUTPUT_2 || controllerType == CONTROLLER_PICO_OUTPUT) { _ledBuiltInDevice = new LedBuiltInDevice(); _ledBuiltInDevice->on(); _nullDevice = new NullDevice(); diff --git a/src/PPUC.h b/src/PPUC.h index 8848472..574d799 100644 --- a/src/PPUC.h +++ b/src/PPUC.h @@ -11,8 +11,9 @@ #define CONTROLLER_MEGA_ALL_INPUT 1 #define CONTROLLER_TEENSY_OUTPUT 10 #define CONTROLLER_TEENSY_OUTPUT_2 11 -#define CONTROLLER_NANO_PIN2DMD_OUTPUT 20 -#define CONTROLLER_16_8_1 30 +#define CONTROLLER_PICO_OUTPUT 20 +#define CONTROLLER_NANO_PIN2DMD_OUTPUT 30 +#define CONTROLLER_16_8_1 40 #define PLATFORM_WPC 1 #define PLATFORM_DATA_EAST 2 diff --git a/test/DistributionController/platformio.ini b/test/DistributionController/platformio.ini deleted file mode 100644 index 2034bc3..0000000 --- a/test/DistributionController/platformio.ini +++ /dev/null @@ -1,23 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html - -[env:teensy41] -platform = teensy -board = teensy41 -framework = arduino -lib_extra_dirs = - ../.. -lib_deps = - mkalkbrenner/WavePWM - mkalkbrenner/WS2812Serial - kitesurfer1404/WS2812FX - thomasfredericks/Bounce2 - https://github.com/PaulStoffregen/TimerOne.git#master -build_flags = -D USB_SERIAL_HID diff --git a/test/DistributionController/src/main.cpp b/test/DistributionController/src/main.cpp deleted file mode 100644 index 4440379..0000000 --- a/test/DistributionController/src/main.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// Markus Kalkbrenner 2022 -// Note to self: Play more pinball! - -#include - -#include "DistributionController.h" -#include - -DistributionController distributionController("0.1.0", PLATFORM_SYS11); - -void setup() { - Serial.begin(9600); // USB is always 12 Mbit/sec - - distributionController.eventDispatcher()->addCrossLinkSerial(Serial1); - distributionController.eventDispatcher()->addCrossLinkSerial(Serial2); - distributionController.eventDispatcher()->addCrossLinkSerial(Serial3); - distributionController.eventDispatcher()->addCrossLinkSerial(Serial4); - distributionController.eventDispatcher()->addCrossLinkSerial(Serial5); - distributionController.eventDispatcher()->addCrossLinkSerial(Serial6); - distributionController.eventDispatcher()->addCrossLinkSerial(Serial7); - distributionController.eventDispatcher()->addCrossLinkSerial(Serial8); - - //distributionController.eventDispatcher()->addListener(new PPUCCrossLinkDebugger()); -} - -void loop() { - // read data - distributionController.vpxComLink()->update(); - distributionController.testButtons()->update(); - - // handle data - distributionController.eventDispatcher()->update(); -} diff --git a/test/DistributionController/test/README b/test/DistributionController/test/README deleted file mode 100644 index b94d089..0000000 --- a/test/DistributionController/test/README +++ /dev/null @@ -1,11 +0,0 @@ - -This directory is intended for PlatformIO Unit Testing and project tests. - -Unit Testing is a software testing method by which individual units of -source code, sets of one or more MCU program modules together with associated -control data, usage procedures, and operating procedures, are tested to -determine whether they are fit for use. Unit testing finds problems early -in the development cycle. - -More information about PlatformIO Unit Testing: -- https://docs.platformio.org/page/plus/unit-testing.html diff --git a/test/EffectController/src/main.cpp b/test/EffectController/src/main.cpp index 49644b1..f87a1f5 100644 --- a/test/EffectController/src/main.cpp +++ b/test/EffectController/src/main.cpp @@ -1,6 +1,6 @@ // Markus Kalkbrenner 2022 -// Note to self: Play more pinball! +#include #include #define PPUC_NUM_LEDS_1 60 @@ -20,7 +20,7 @@ #include -EffectsController effectsController("0.1.0", PLATFORM_SYS11); +EffectsController effectsController(CONTROLLER_TEENSY_OUTPUT, PLATFORM_SYS11); void setup() { // Debug diff --git a/test/EffectControllerPico/platformio.ini b/test/EffectControllerPico/platformio.ini index 0f457a4..0f288f4 100644 --- a/test/EffectControllerPico/platformio.ini +++ b/test/EffectControllerPico/platformio.ini @@ -9,9 +9,11 @@ ; https://docs.platformio.org/page/projectconf.html [env:pico] -platform = raspberrypi +platform = https://github.com/maxgerhardt/platform-raspberrypi.git board = pico framework = arduino +board_build.core = earlephilhower +board_build.filesystem_size = 0.5m lib_extra_dirs = ../.. lib_deps = diff --git a/test/EffectControllerPico/src/main.cpp b/test/EffectControllerPico/src/main.cpp index 2b0ea36..d8cec8a 100644 --- a/test/EffectControllerPico/src/main.cpp +++ b/test/EffectControllerPico/src/main.cpp @@ -1,6 +1,6 @@ // Markus Kalkbrenner 2022 -// Note to self: Play more pinball! +#include #include #define PPUC_NUM_LEDS_1 60 @@ -20,7 +20,7 @@ #include -EffectsController effectsController("0.1.0", PLATFORM_LIBPINMAME); +EffectsController effectsController(CONTROLLER_PICO_OUTPUT, PLATFORM_LIBPINMAME); void setup() { // Setup diff --git a/test/IOBoardController/platformio.ini b/test/IOBoardController/platformio.ini index 788c5f3..42823b2 100644 --- a/test/IOBoardController/platformio.ini +++ b/test/IOBoardController/platformio.ini @@ -19,4 +19,4 @@ lib_extra_dirs = lib_deps = mkalkbrenner/WavePWM kitesurfer1404/WS2812FX - thomasfredericks/Bounce2 + Bounce2 diff --git a/test/IOBoardController/src/main.cpp b/test/IOBoardController/src/main.cpp index a8407b6..bdd9657 100644 --- a/test/IOBoardController/src/main.cpp +++ b/test/IOBoardController/src/main.cpp @@ -1,27 +1,14 @@ -// Markus Kalkbrenner 2022-2023 -// Note to self: Play more pinball! +// Markus Kalkbrenner 2022 -#include +#include -#include "EffectsController.h" #include "IOBoardController.h" IOBoardController ioBoardController(CONTROLLER_16_8_1); -EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_WPC); -MultiCoreCrossLink* multiCoreCrossLink = new MultiCoreCrossLink(); void setup() { - ioBoardController.eventDispatcher()->setMultiCoreCrossLink(multiCoreCrossLink); -} - -void setup1() { - effectsController.eventDispatcher()->setMultiCoreCrossLink(multiCoreCrossLink); } void loop() { ioBoardController.update(); } - -void loop1() { - effectsController.update(); -} diff --git a/test/InputController/src/main.cpp b/test/InputController/src/main.cpp index d50eeb2..e66a237 100644 --- a/test/InputController/src/main.cpp +++ b/test/InputController/src/main.cpp @@ -1,11 +1,10 @@ // Markus Kalkbrenner 2022 -// Note to self: Play more pinball! -#include +#include #include #include -InputController inputController("0.1.0", PLATFORM_WPC); +InputController inputController(CONTROLLER_MEGA_ALL_INPUT, PLATFORM_WPC); void setup() { inputController.pupComLink()->setSerial(Serial); diff --git a/test/NanoGIController/platformio.ini b/test/NanoController/platformio.ini similarity index 92% rename from test/NanoGIController/platformio.ini rename to test/NanoController/platformio.ini index 8478e66..30888cd 100644 --- a/test/NanoGIController/platformio.ini +++ b/test/NanoController/platformio.ini @@ -8,10 +8,10 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html -[env:nanoatmega328] +[env:megaatmega2560] platform = atmelavr -board = nanoatmega328 framework = arduino +board = megaatmega2560 lib_extra_dirs = ../.. lib_deps = diff --git a/test/NanoController/src/main.cpp b/test/NanoController/src/main.cpp new file mode 100644 index 0000000..3294ffd --- /dev/null +++ b/test/NanoController/src/main.cpp @@ -0,0 +1,56 @@ +/* + Created by Markus Kalkbrenner. +*/ + +#include + +#define PPUC_CONTROLLER CONTROLLER_NANO_PIN2DMD_OUTPUT +#define PPUC_NUM_LEDS_1 40 +#define PPUC_LED_TYPE_1 WS2812_GRB + +#include +#include + +EffectsController effectsController(PPUC_CONTROLLER, PLATFORM_DATA_EAST); +InputController inputController(PPUC_CONTROLLER, PLATFORM_DATA_EAST, effectsController.eventDispatcher()); + +void setup() { + inputController.pin2Dmd()->setSerial(Serial); + + effectsController.createCombinedGiAndLightMatrixWs2812FXDevice(1); + //effectsController.setBrightness(1, 128); + + effectsController.attachBrightnessControl(1, 1); + + effectsController.giAndLightMatrix(1)->setHeatUp(40); + effectsController.giAndLightMatrix(1)->setAfterGlow(280); + + effectsController.giAndLightMatrix(1)->assignLedRangeToGiString(1, 0, 39); + + effectsController.addEffect( + new WS2812FXEffect(FX_MODE_STATIC, WHITE, 0, 0), + effectsController.giAndLightMatrix(1), + new Event(EVENT_SOURCE_EFFECT, 1, 255), + 1, // priority + 0, // repeat + -1 // mode + ); + + effectsController.addEffect( + new LedBlinkEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_SOURCE_EFFECT, 1, 255), + 1, // priority + 50, // repeat + -1 // mode + ); + + effectsController.start(); +} + +void loop() { + inputController.pin2Dmd()->update(); + + // The effectController also calls update() on the eventDispatcher. + effectsController.update(); +} diff --git a/test/NanoGIController/test/README b/test/NanoController/test/README similarity index 100% rename from test/NanoGIController/test/README rename to test/NanoController/test/README diff --git a/test/NanoGIController/src/main.cpp b/test/NanoGIController/src/main.cpp deleted file mode 100644 index da87fb6..0000000 --- a/test/NanoGIController/src/main.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// Markus Kalkbrenner 2022 -// Note to self: Play more pinball! - -#include -#include "InputController.h" -#include "EffectsController.h" - -EffectsController effectsController(CONTROLLER_NANO_PIN2DMD_GI, PLATFORM_DATA_EAST); -InputController inputController(CONTROLLER_NANO_PIN2DMD_GI, PLATFORM_DATA_EAST, effectsController.eventDispatcher()); - -void setup() { - inputController.pin2Dmd()->setSerial(Serial); -} - -void loop() { - inputController.pin2Dmd()->update(); - inputController.eventDispatcher()->update(); - effectsController.update(); -} From c533a69832228ff73737d667750ee8720cecc152 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 23 Feb 2023 23:55:14 +0100 Subject: [PATCH 002/102] fixed NanoController --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e4f6815..de3b905 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - controller: ['EffectController', 'EffectControllerPico', 'InputController', 'IOBoardController', 'NanoCOntroller'] + controller: ['EffectController', 'EffectControllerPico', 'InputController', 'IOBoardController', 'NanoController'] name: PPUC ${{ matrix.controller }} From 7aa009b5aa01177b261f9700ad20982745b6a614 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Tue, 22 Aug 2023 19:29:13 +0200 Subject: [PATCH 003/102] added Flashers, multi core crosslink --- ...CombinedGiAndLightMatrixWS2812FXDevice.cpp | 387 ++++++++++++------ .../CombinedGiAndLightMatrixWS2812FXDevice.h | 44 +- src/EffectsController.cpp | 312 +++++++++----- src/EffectsController.h | 9 +- src/EventDispatcher/Event.h | 12 + src/EventDispatcher/EventDispatcher.cpp | 11 +- src/EventDispatcher/EventDispatcher.h | 2 + src/EventDispatcher/MultiCoreCrossLink.h | 2 + src/IOBoardController.cpp | 26 +- src/IOBoardController.h | 4 + src/IODevices/PwmDevices.cpp | 159 ++++--- src/IODevices/PwmDevices.h | 16 +- src/InputDevices/Matrix.cpp | 4 +- test/IOBoardController/platformio.ini | 2 + test/IOBoardController/src/main.cpp | 11 + 15 files changed, 679 insertions(+), 322 deletions(-) diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp index 3d44266..b29e353 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp @@ -1,67 +1,84 @@ #include "CombinedGiAndLightMatrixWS2812FXDevice.h" -void CombinedGiAndLightMatrixWS2812FXDevice::on() { +void CombinedGiAndLightMatrixWS2812FXDevice::on() +{ WS2812FXDevice::on(); effectRunning = true; } -void CombinedGiAndLightMatrixWS2812FXDevice::off() { +void CombinedGiAndLightMatrixWS2812FXDevice::off() +{ effectRunning = false; // No stop. Just reset to quit effects and return to standard GI and Light Matrix operation. reset(); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToGiString(uint8_t giString, int16_t led) { +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToGiString(uint8_t giString, int16_t led) +{ assignLedToGiString(giString, led, ULTRAWHITE); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToGiString(uint8_t giString, int16_t led, uint32_t color) { - if (numLEDsGI[--giString] < _MAX_LEDS_GI_STRING) { +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToGiString(uint8_t giString, int16_t led, uint32_t color) +{ + if (numLEDsGI[--giString] < _MAX_LEDS_GI_STRING) + { ledGIPositions[giString][numLEDsGI[giString]] = led; ledGIColors[giString][numLEDsGI[giString]++] = color; } } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedRangeToGiString(uint8_t giString, int16_t first, int16_t last) { - for (int16_t i = first; i <= last; i++) { +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedRangeToGiString(uint8_t giString, int16_t first, int16_t last) +{ + for (int16_t i = first; i <= last; i++) + { assignLedToGiString(giString, i); } } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrix(uint8_t column, uint8_t row, int16_t led) { +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrix(uint8_t column, uint8_t row, int16_t led) +{ assignLedToLightMatrix(column, row, led, ULTRAWHITE); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrix(uint8_t column, uint8_t row, int16_t led, uint32_t color) { - assignLedToLightMatrixDE(((column - 1) * 8) + row , led, color); +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrix(uint8_t column, uint8_t row, int16_t led, uint32_t color) +{ + assignLedToLightMatrixDE(((column - 1) * 8) + row, led, color); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixWPC(uint8_t number, int16_t led) { +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixWPC(uint8_t number, int16_t led) +{ assignLedToLightMatrixWPC(number, led, ULTRAWHITE); wpc = true; } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixWPC(uint8_t number, int16_t led, uint32_t color) { +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixWPC(uint8_t number, int16_t led, uint32_t color) +{ assignLedToLightMatrix(number / 10 % 10, number % 10, led, color); wpc = true; } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixSYS11(uint8_t number, int16_t led) { +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixSYS11(uint8_t number, int16_t led) +{ assignLedToLightMatrixDE(number, led, ULTRAWHITE); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixSYS11(uint8_t number, int16_t led, uint32_t color) { +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixSYS11(uint8_t number, int16_t led, uint32_t color) +{ assignLedToLightMatrixDE(number, led, color); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE(uint8_t number, int16_t led) { +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE(uint8_t number, int16_t led) +{ assignLedToLightMatrixDE(number, led, ULTRAWHITE); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE(uint8_t number, int16_t led, uint32_t color) { +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE(uint8_t number, int16_t led, uint32_t color) +{ --number; - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { - if (ledLightMatrixPositions[number][i] == -1) { + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) + { + if (ledLightMatrixPositions[number][i] == -1) + { ledLightMatrixPositions[number][i] = led; ledLightMatrixColors[number][i] = color; break; @@ -69,80 +86,136 @@ void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE(uint8_t nu } } -void CombinedGiAndLightMatrixWS2812FXDevice::handleEvent(Event* event) { - if (!effectRunning) { - if (event->sourceId == EVENT_SOURCE_GI) { +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToFlasher(uint8_t number, int16_t led, uint32_t color) +{ + for (int offset = 0; offset < _MAX_FLASHERS; offset++) + { + if (flasherNumber[offset] == number) + { + // Flasher already registered, add another LED to it. + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) + { + if (ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + offset][i] == -1) + { + ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + offset][i] = led; + ledLightMatrixColors[_LIGHT_MATRIX_SIZE + offset][i] = color; + break; + } + } + + return; + } + } + + // Flasher not yet registered, find a free slot. + for (int f = _MAX_LEDS_PER_LIGHT; f < _MAX_LEDS_PER_LIGHT + _MAX_FLASHERS; f++) + { + if (ledLightMatrixPositions[f][0] == -1) + { + ledLightMatrixPositions[f][0] = led; + ledLightMatrixColors[f][0] = color; + flasherNumber[_MAX_LEDS_PER_LIGHT - f] = number; + return; + } + } +} + +void CombinedGiAndLightMatrixWS2812FXDevice::handleEvent(Event *event) +{ + if (!effectRunning) + { + if (event->sourceId == EVENT_SOURCE_GI) + { uint8_t giString = event->eventId - 1; // Brightness is a value between 0 and 8. Convert it into a value from 0 to 255. uint8_t giBrightness = 0; - switch (event->value) { - case 1: - giBrightness = 35; - break; - case 2: - giBrightness = 60; - break; - case 3: - giBrightness = 85; - break; - case 4: - giBrightness = 115; - break; - case 5: - giBrightness = 155; - break; - case 6: - giBrightness = 205; - break; - case 7: - case 8: - giBrightness = 255; - break; + switch (event->value) + { + case 1: + giBrightness = 35; + break; + case 2: + giBrightness = 60; + break; + case 3: + giBrightness = 85; + break; + case 4: + giBrightness = 115; + break; + case 5: + giBrightness = 155; + break; + case 6: + giBrightness = 205; + break; + case 7: + case 8: + giBrightness = 255; + break; } - if (targetGIBrightness[giString] != giBrightness) { + if (targetGIBrightness[giString] != giBrightness) + { if ( - (targetGIBrightness[giString] < giBrightness && msHeatUp == 0) || - (targetGIBrightness[giString] > giBrightness && msAfterGlow == 0) - ) { - for (int i = 0; i <= numLEDsGI[giString]; i++) { + (targetGIBrightness[giString] < giBrightness && msHeatUp == 0) || + (targetGIBrightness[giString] > giBrightness && msAfterGlow == 0)) + { + for (int i = 0; i <= numLEDsGI[giString]; i++) + { setDimmedPixelColor(ledGIPositions[giString][i], ledGIColors[giString][i], giBrightness); } } - else { - if (targetGIBrightness[giString] < giBrightness) { - if (heatUpGI[giString] == 0 && afterGlowGI[giString] == 0) { + else + { + if (targetGIBrightness[giString] < giBrightness) + { + if (heatUpGI[giString] == 0 && afterGlowGI[giString] == 0) + { heatUpGI[giString] = millis(); - } else if (afterGlowGI[giString] > 0) { + } + else if (afterGlowGI[giString] > 0) + { // There's still an after glow effect running. Start heat up from current value. byte value = wavePWMAfterGlow->getExponentialValue(millis() - afterGlowGI[giString] + msAfterGlow); afterGlowGI[giString] = 0; - for (int ms = 1; ms <= msHeatUp; ms++) { - if (wavePWMHeatUp->getExponentialValue(ms) >= value) { + for (int ms = 1; ms <= msHeatUp; ms++) + { + if (wavePWMHeatUp->getExponentialValue(ms) >= value) + { heatUpGI[giString] = millis() - ms; break; } } // safety net - if (heatUpGI[giString] == 0) { + if (heatUpGI[giString] == 0) + { heatUpGI[giString] = millis() - msHeatUp + 1; } } - } else { - if (afterGlowGI[giString] == 0 && heatUpGI[giString] == 0) { + } + else + { + if (afterGlowGI[giString] == 0 && heatUpGI[giString] == 0) + { afterGlowGI[giString] = millis(); - } else if (heatUpGI[giString] > 0) { + } + else if (heatUpGI[giString] > 0) + { // There's still a heat up effect running. Start after glow from current value. byte value = wavePWMHeatUp->getExponentialValue(millis() - heatUp[giString]); heatUpGI[giString] = 0; - for (int ms = msAfterGlow; ms <= (msAfterGlow * 2); ms++) { - if (wavePWMAfterGlow->getExponentialValue(ms) <= value) { + for (int ms = msAfterGlow; ms <= (msAfterGlow * 2); ms++) + { + if (wavePWMAfterGlow->getExponentialValue(ms) <= value) + { afterGlowGI[giString] = millis() - ms; break; } } // safety net - if (afterGlowGI[giString] == 0) { + if (afterGlowGI[giString] == 0) + { afterGlowGI[giString] = millis() - (2 * msAfterGlow) + 1; } } @@ -153,64 +226,108 @@ void CombinedGiAndLightMatrixWS2812FXDevice::handleEvent(Event* event) { targetGIBrightness[giString] = giBrightness; } } - else if (event->sourceId == EVENT_SOURCE_LIGHT) { - //char system = (event->eventId & 0xFF00) >> 8; - //uint8_t number = event->eventId & 0x00FF; + else if (event->sourceId == EVENT_SOURCE_LIGHT || event->sourceId == EVENT_SOURCE_SOLENOID) + { + // char system = (event->eventId & 0xFF00) >> 8; + // uint8_t number = event->eventId & 0x00FF; uint8_t number = event->eventId; - if (wpc) { - // WPC - uint8_t column = number / 10 % 10; - uint8_t row = number % 10; - number = ((column - 1) * 8) + row; + if (event->sourceId == EVENT_SOURCE_LIGHT) + { + if (wpc) + { + // WPC + uint8_t column = number / 10 % 10; + uint8_t row = number % 10; + number = ((column - 1) * 8) + row; + } + + --number; + } + else + { + number = 255; + for (int offset = 0; offset < _MAX_FLASHERS; offset++) + { + if (flasherNumber[offset] == number) + { + number = _LIGHT_MATRIX_SIZE + offset; + break; + } + } + + if (number == 255) + { + // The solenoid isn't a registered falsher. + return; + } } - --number; - bool on = (bool) event->value; + bool on = (bool)event->value; - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { - if (ledLightMatrixPositions[number][i] >= 0) { - if (on && msHeatUp == 0) { + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) + { + if (ledLightMatrixPositions[number][i] >= 0) + { + if (on && msHeatUp == 0) + { ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], ledLightMatrixColors[number][i]); } - else if (!on && msAfterGlow == 0) { + else if (!on && msAfterGlow == 0) + { ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], RGBW_BLACK); } - else if (i == 0) { - if (on) { - if (heatUp[number] == 0 && afterGlow[number] == 0) { + else if (i == 0) + { + if (on) + { + if (heatUp[number] == 0 && afterGlow[number] == 0) + { heatUp[number] = millis(); - } else if (afterGlow[number] > 0) { + } + else if (afterGlow[number] > 0) + { // There's still an after glow effect running. Start heat up from current value. byte value = wavePWMAfterGlow->getExponentialValue(millis() - afterGlow[number] + msAfterGlow); afterGlow[number] = 0; - for (int ms = 1; ms <= msHeatUp; ms++) { - if (wavePWMHeatUp->getExponentialValue(ms) >= value) { + for (int ms = 1; ms <= msHeatUp; ms++) + { + if (wavePWMHeatUp->getExponentialValue(ms) >= value) + { heatUp[number] = millis() - ms; break; } } // safety net - if (heatUp[number] == 0) { + if (heatUp[number] == 0) + { heatUp[number] = millis() - msHeatUp + 1; } } - } else { - if (afterGlow[number] == 0 && heatUp[number] == 0) { + } + else + { + if (afterGlow[number] == 0 && heatUp[number] == 0) + { afterGlow[number] = millis(); - } else if (heatUp[number] > 0) { + } + else if (heatUp[number] > 0) + { // There's still a heat up effect running. Start after glow from current value. byte value = wavePWMHeatUp->getExponentialValue(millis() - heatUp[number]); heatUp[number] = 0; - for (int ms = msAfterGlow; ms <= (msAfterGlow * 2); ms++) { - if (wavePWMAfterGlow->getExponentialValue(ms) <= value) { + for (int ms = msAfterGlow; ms <= (msAfterGlow * 2); ms++) + { + if (wavePWMAfterGlow->getExponentialValue(ms) <= value) + { afterGlow[number] = millis() - ms; break; } } // safety net - if (afterGlow[number] == 0) { + if (afterGlow[number] == 0) + { afterGlow[number] = millis() - (2 * msAfterGlow) + 1; } } @@ -225,72 +342,97 @@ void CombinedGiAndLightMatrixWS2812FXDevice::handleEvent(Event* event) { } } -void CombinedGiAndLightMatrixWS2812FXDevice::updateAfterGlow() { - for (uint8_t giString = 0; giString < NUM_GI_STRINGS; giString++) { +void CombinedGiAndLightMatrixWS2812FXDevice::updateAfterGlow() +{ + for (uint8_t giString = 0; giString < NUM_GI_STRINGS; giString++) + { uint8_t glowBrightness = targetGIBrightness[giString]; - if (heatUpGI[giString] > 0) { - if ((millis() - heatUpGI[giString]) >= msHeatUp) { + if (heatUpGI[giString] > 0) + { + if ((millis() - heatUpGI[giString]) >= msHeatUp) + { heatUpGI[giString] = 0; } - else { + else + { float diff = targetGIBrightness[giString] - sourceGIBrightness[giString]; float mult = diff / 255; glowBrightness = sourceGIBrightness[giString] + (wavePWMHeatUp->getExponentialValue(millis() - heatUpGI[giString]) * mult); } } - else if (afterGlowGI[giString] > 0) { - if ((millis() - afterGlowGI[giString]) >= msAfterGlow) { + else if (afterGlowGI[giString] > 0) + { + if ((millis() - afterGlowGI[giString]) >= msAfterGlow) + { afterGlowGI[giString] = 0; } - else { + else + { float diff = sourceGIBrightness[giString] - targetGIBrightness[giString]; float mult = diff / 255; glowBrightness = targetGIBrightness[giString] + (wavePWMAfterGlow->getExponentialValue(millis() - afterGlowGI[giString] + msAfterGlow) * mult); - } + } } - else { + else + { continue; } - for (int i = 0; i < numLEDsGI[giString]; i++) { - if (ledGIPositions[giString][i] != -1) { + for (int i = 0; i < numLEDsGI[giString]; i++) + { + if (ledGIPositions[giString][i] != -1) + { setDimmedPixelColor(ledGIPositions[giString][i], ledGIColors[giString][i], glowBrightness); } } } - for (uint8_t number = 0; number < _LIGHT_MATRIX_SIZE; number++) { + for (uint8_t number = 0; number < _LIGHT_MATRIX_SIZE + _MAX_FLASHERS; number++) + { uint8_t glowBrightness; - if (heatUp[number] > 0) { - if ((millis() - heatUp[number]) >= msHeatUp) { + if (heatUp[number] > 0) + { + if ((millis() - heatUp[number]) >= msHeatUp) + { heatUp[number] = 0; - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { - if (ledLightMatrixPositions[number][i] != -1) { + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) + { + if (ledLightMatrixPositions[number][i] != -1) + { ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], ledLightMatrixColors[number][i]); } } } - else { + else + { glowBrightness = wavePWMHeatUp->getExponentialValue(millis() - heatUp[number]); } } - else if (afterGlow[number] > 0) { - if ((millis() - afterGlow[number]) >= msAfterGlow) { + else if (afterGlow[number] > 0) + { + if ((millis() - afterGlow[number]) >= msAfterGlow) + { afterGlow[number] = 0; - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { - if (ledLightMatrixPositions[number][i] != -1) { + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) + { + if (ledLightMatrixPositions[number][i] != -1) + { ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], RGBW_BLACK); } } } - else { + else + { glowBrightness = wavePWMAfterGlow->getExponentialValue(millis() - afterGlow[number] + msAfterGlow); } } - if (heatUp[number] > 0 || afterGlow[number] > 0) { - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { - if (ledLightMatrixPositions[number][i] != -1) { + if (heatUp[number] > 0 || afterGlow[number] > 0) + { + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) + { + if (ledLightMatrixPositions[number][i] != -1) + { setDimmedPixelColor(ledLightMatrixPositions[number][i], ledLightMatrixColors[number][i], glowBrightness); } } @@ -298,7 +440,8 @@ void CombinedGiAndLightMatrixWS2812FXDevice::updateAfterGlow() { } } -void CombinedGiAndLightMatrixWS2812FXDevice::setDimmedPixelColor(int16_t led, uint32_t color, uint8_t brightness) { +void CombinedGiAndLightMatrixWS2812FXDevice::setDimmedPixelColor(int16_t led, uint32_t color, uint8_t brightness) +{ uint8_t w = (color >> 24) & 0xFF; uint8_t r = (color >> 16) & 0xFF; uint8_t g = (color >> 8) & 0xFF; @@ -314,20 +457,24 @@ void CombinedGiAndLightMatrixWS2812FXDevice::setDimmedPixelColor(int16_t led, ui ws2812FX->setPixelColor(led, r, g, b, w); } -void CombinedGiAndLightMatrixWS2812FXDevice::setHeatUp() { +void CombinedGiAndLightMatrixWS2812FXDevice::setHeatUp() +{ setHeatUp(30); } -void CombinedGiAndLightMatrixWS2812FXDevice::setAfterGlow() { +void CombinedGiAndLightMatrixWS2812FXDevice::setAfterGlow() +{ setAfterGlow(400); } -void CombinedGiAndLightMatrixWS2812FXDevice::setHeatUp(int ms) { +void CombinedGiAndLightMatrixWS2812FXDevice::setHeatUp(int ms) +{ wavePWMHeatUp->setup(ms * 2); msHeatUp = ms; } -void CombinedGiAndLightMatrixWS2812FXDevice::setAfterGlow(int ms) { +void CombinedGiAndLightMatrixWS2812FXDevice::setAfterGlow(int ms) +{ wavePWMAfterGlow->setup(ms * 2); msAfterGlow = ms; } diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h index c439a3a..755407f 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h @@ -1,8 +1,6 @@ /* CombinedGiAndLightMatrixWS2812FXDevice.h - Created by Markus Kalkbrenner, 2021. - - Play more pinball! + Created by Markus Kalkbrenner, 2021 - 2023. */ // WPC matrix numbering: @@ -59,21 +57,27 @@ #define _MAX_LEDS_GI_STRING 50 #define _LIGHT_MATRIX_SIZE 64 #define _MAX_LEDS_PER_LIGHT 3 +#define _MAX_FLASHERS 12 -class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, public EventListener { +class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, public EventListener +{ public: - - CombinedGiAndLightMatrixWS2812FXDevice(WS2812FX* ws2812FX, int firstLED, int lastLED, int firstSegment, int lastSegment) : WS2812FXDevice(ws2812FX, firstLED, lastLED, firstSegment, lastSegment) { + CombinedGiAndLightMatrixWS2812FXDevice(WS2812FX *ws2812FX, int firstLED, int lastLED, int firstSegment, int lastSegment) : WS2812FXDevice(ws2812FX, firstLED, lastLED, firstSegment, lastSegment) + { wavePWMHeatUp = new WavePWM(); wavePWMAfterGlow = new WavePWM(); afterGlowSupport = true; - for (int number = 0; number < NUM_GI_STRINGS; number++) { - for (int i = 0; i < _MAX_LEDS_GI_STRING; i++) { + for (int number = 0; number < NUM_GI_STRINGS; number++) + { + for (int i = 0; i < _MAX_LEDS_GI_STRING; i++) + { ledGIPositions[number][i] = -1; } } - for (int number = 0; number < _LIGHT_MATRIX_SIZE; number++) { - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { + for (int number = 0; number < _LIGHT_MATRIX_SIZE + _MAX_FLASHERS; number++) + { + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) + { ledLightMatrixPositions[number][i] = -1; } } @@ -99,6 +103,8 @@ class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, public Eve void assignLedToLightMatrixSYS11(uint8_t number, int16_t led); void assignLedToLightMatrixSYS11(uint8_t number, int16_t led, uint32_t color); + void assignLedToFlasher(uint8_t number, int16_t led, uint32_t color); + void setDimmedPixelColor(int16_t led, uint32_t color, uint8_t brightness); void setHeatUp(); @@ -107,8 +113,8 @@ class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, public Eve void setHeatUp(int ms); void setAfterGlow(int ms); - void handleEvent(Event* event); - void handleEvent(ConfigEvent* event) {} + void handleEvent(Event *event); + void handleEvent(ConfigEvent *event) {} void updateAfterGlow(); protected: @@ -121,11 +127,13 @@ class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, public Eve // Internally we store the positions in Data East numbering from 1 to 64. // The WPC-specific functions convert the WPC-specific numbering. - int16_t ledLightMatrixPositions[_LIGHT_MATRIX_SIZE][_MAX_LEDS_PER_LIGHT] = {{0}}; - uint32_t ledLightMatrixColors[_LIGHT_MATRIX_SIZE][_MAX_LEDS_PER_LIGHT] = {{0}}; + int16_t ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS][_MAX_LEDS_PER_LIGHT] = {{0}}; + uint32_t ledLightMatrixColors[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS][_MAX_LEDS_PER_LIGHT] = {{0}}; + + uint8_t flasherNumber[_MAX_FLASHERS] = {0}; - WavePWM* wavePWMHeatUp; - WavePWM* wavePWMAfterGlow; + WavePWM *wavePWMHeatUp; + WavePWM *wavePWMAfterGlow; // When no effects are running, we're in normal GI and Light Matrix mode. bool stopped = false; // Never stop the updates. @@ -136,8 +144,8 @@ class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, public Eve int16_t msAfterGlow = 0; uint32_t heatUpGI[NUM_GI_STRINGS] = {0}; uint32_t afterGlowGI[NUM_GI_STRINGS] = {0}; - uint32_t heatUp[_LIGHT_MATRIX_SIZE] = {0}; - uint32_t afterGlow[_LIGHT_MATRIX_SIZE] = {0}; + uint32_t heatUp[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS] = {0}; + uint32_t afterGlow[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS] = {0}; }; #endif diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 4c5db4d..342b130 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -1,50 +1,58 @@ #include "EffectsController.h" // see https://forum.arduino.cc/index.php?topic=398610.0 -EffectsController* EffectsController::effectsControllerInstance = NULL; +EffectsController *EffectsController::effectsControllerInstance = NULL; -EventDispatcher* EffectsController::eventDispatcher() { +EventDispatcher *EffectsController::eventDispatcher() +{ return _eventDispatcher; } -LedBuiltInDevice* EffectsController::ledBuiltInDevice() { +LedBuiltInDevice *EffectsController::ledBuiltInDevice() +{ return _ledBuiltInDevice; } -NullDevice* EffectsController::nullDevice() { +NullDevice *EffectsController::nullDevice() +{ return _nullDevice; } -WavePWMDevice* EffectsController::shakerPWMDevice() { +WavePWMDevice *EffectsController::shakerPWMDevice() +{ return _shakerPWMDevice; } -WavePWMDevice* EffectsController::ledPWMDevice() { +WavePWMDevice *EffectsController::ledPWMDevice() +{ return _ledPWMDevice; } -RgbStripDevice* EffectsController::rgbStripDevice() { +RgbStripDevice *EffectsController::rgbStripDevice() +{ return _rgbStripeDevice; } -WS2812FXDevice* EffectsController::ws2812FXDevice(int port) { +WS2812FXDevice *EffectsController::ws2812FXDevice(int port) +{ return ws2812FXDevices[--port][0]; } -CombinedGiAndLightMatrixWS2812FXDevice* EffectsController::giAndLightMatrix(int port) { - return (CombinedGiAndLightMatrixWS2812FXDevice*) ws2812FXDevice(port); +CombinedGiAndLightMatrixWS2812FXDevice *EffectsController::giAndLightMatrix(int port) +{ + return (CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevice(port); } -CombinedGiAndLightMatrixWS2812FXDevice* EffectsController::createCombinedGiAndLightMatrixWs2812FXDevice(int port) { - WS2812FXDevice* ws2812FXDevice = ws2812FXDevices[--port][0]; +CombinedGiAndLightMatrixWS2812FXDevice *EffectsController::createCombinedGiAndLightMatrixWs2812FXDevice(int port) +{ + WS2812FXDevice *ws2812FXDevice = ws2812FXDevices[--port][0]; - CombinedGiAndLightMatrixWS2812FXDevice* giAndLightMatrix = new CombinedGiAndLightMatrixWS2812FXDevice( + CombinedGiAndLightMatrixWS2812FXDevice *giAndLightMatrix = new CombinedGiAndLightMatrixWS2812FXDevice( ws2812FXDevice->getWS2812FX(), ws2812FXDevice->getFirstLED(), ws2812FXDevice->getlastLED(), ws2812FXDevice->getFirstSegment(), - ws2812FXDevice->getLastSegment() - ); + ws2812FXDevice->getLastSegment()); giAndLightMatrix->off(); @@ -57,13 +65,16 @@ CombinedGiAndLightMatrixWS2812FXDevice* EffectsController::createCombinedGiAndLi return giAndLightMatrix; } -WS2812FXDevice* EffectsController::createWS2812FXDevice(int port, int number, int segments, int firstLED, int lastLED) { +WS2812FXDevice *EffectsController::createWS2812FXDevice(int port, int number, int segments, int firstLED, int lastLED) +{ --port; - if (number == 0) { + if (number == 0) + { ws2812FXDevices[port][0]->_reduceLEDs(lastLED, segments - 1); } - else { + else + { int firstSegment = ws2812FXDevices[port][number - 1]->getLastSegment() + 1; ws2812FXDevices[port][number] = new WS2812FXDevice( @@ -71,8 +82,7 @@ WS2812FXDevice* EffectsController::createWS2812FXDevice(int port, int number, in firstLED, lastLED, firstSegment, - firstSegment + segments - 1 - ); + firstSegment + segments - 1); ++ws2812FXDeviceCounters[port]; } @@ -80,56 +90,66 @@ WS2812FXDevice* EffectsController::createWS2812FXDevice(int port, int number, in return ws2812FXDevices[port][number]; } -WS2812FXDevice* EffectsController::ws2812FXDevice(int port, int number) { +WS2812FXDevice *EffectsController::ws2812FXDevice(int port, int number) +{ return ws2812FXDevices[--port][number]; } -GeneralIlluminationWPC* EffectsController::generalIllumintationWPC() { +GeneralIlluminationWPC *EffectsController::generalIllumintationWPC() +{ return _generalIllumintationWPC; } -void EffectsController::addEffect(Effect* effect, EffectDevice* device, Event* event, int priority, int repeat, int mode) { +void EffectsController::addEffect(Effect *effect, EffectDevice *device, Event *event, int priority, int repeat, int mode) +{ addEffect(new EffectContainer(effect, device, event, priority, repeat, mode)); } -void EffectsController::addEffect(EffectContainer* container) { +void EffectsController::addEffect(EffectContainer *container) +{ container->effect->setEventDispatcher(this->eventDispatcher()); container->effect->setDevice(container->device); stackEffectContainers[++stackCounter] = container; } -void EffectsController::attachBrightnessControl(byte port, byte poti) { +void EffectsController::attachBrightnessControl(byte port, byte poti) +{ brightnessControl[--port] = poti; } -void EffectsController::setBrightness(byte port, byte brightness) { +void EffectsController::setBrightness(byte port, byte brightness) +{ ws2812FXDevices[--port][0]->setBrightness(brightness); ws2812FXbrightness[port] = brightness; } -void EffectsController::handleEvent(Event* event) { - for (int i = 0; i <= stackCounter; i++) { +void EffectsController::handleEvent(Event *event) +{ + for (int i = 0; i <= stackCounter; i++) + { if ( event->sourceId == stackEffectContainers[i]->event->sourceId && event->eventId == stackEffectContainers[i]->event->eventId && event->value == stackEffectContainers[i]->event->value && - ( - mode == stackEffectContainers[i]->mode || - -1 == stackEffectContainers[i]->mode // -1 means any mode - ) - ) { - for (int k = 0; k <= stackCounter; k++) { + (mode == stackEffectContainers[i]->mode || + -1 == stackEffectContainers[i]->mode // -1 means any mode + )) + { + for (int k = 0; k <= stackCounter; k++) + { if ( stackEffectContainers[i]->device == stackEffectContainers[k]->device && - stackEffectContainers[k]->effect->isRunning() - ) { - if (stackEffectContainers[i]->priority > stackEffectContainers[k]->priority) { + stackEffectContainers[k]->effect->isRunning()) + { + if (stackEffectContainers[i]->priority > stackEffectContainers[k]->priority) + { stackEffectContainers[k]->effect->terminate(); stackEffectContainers[i]->effect->start(stackEffectContainers[i]->repeat); } break; } - if (k == stackCounter) { + if (k == stackCounter) + { stackEffectContainers[i]->effect->start(stackEffectContainers[i]->repeat); } } @@ -137,92 +157,174 @@ void EffectsController::handleEvent(Event* event) { } } -void EffectsController::handleEvent(ConfigEvent* event) { - if (event->boardId == boardId) { - switch (event->topic) { - case CONFIG_TOPIC_LED_STRING: - switch (event->key) { - case CONFIG_TOPIC_PORT: - config_port = event->value; - config_type = 0; - config_amount = 0; - config_afterGlow = 0; - break; - case CONFIG_TOPIC_TYPE: - config_type = event->value; - break; - case CONFIG_TOPIC_AMOUNT_LEDS: - config_amount = event->value; +void EffectsController::handleEvent(ConfigEvent *event) +{ + if (event->boardId == boardId) + { + switch (event->topic) + { + case CONFIG_TOPIC_PLATFORM: + platform = event->value; + break; + + case CONFIG_TOPIC_LED_STRING: + switch (event->key) + { + case CONFIG_TOPIC_PORT: + config_port = event->value; + config_type = 0; + config_amount = 0; + config_afterGlow = 0; + break; + case CONFIG_TOPIC_TYPE: + config_type = event->value; + break; + case CONFIG_TOPIC_AMOUNT_LEDS: + config_amount = event->value; + break; + case CONFIG_TOPIC_AFTER_GLOW: + config_afterGlow = event->value; + break; + case CONFIG_TOPIC_LIGHT_UP: + config_heatUp = event->value; + + if (!ws2812FXDevices[0][0]) + { + ws2812FXDevices[0][0] = new CombinedGiAndLightMatrixWS2812FXDevice( + new WS2812FX(config_amount, config_port, config_type), + 0, + config_amount - 1, + 0, + 0); + ws2812FXDevices[0][0]->getWS2812FX()->init(); + ws2812FXDeviceCounters[0] = 1; + + // Brightness might be overwritten later. + // ws2812FXDevices[0][0]->setBrightness(WS2812FX_BRIGHTNESS); + ws2812FXDevices[0][0]->off(); + ws2812FXstates[0] = true; + + _eventDispatcher->addListener((EventListener *)ws2812FXDevices[0][0], EVENT_SOURCE_GI); + _eventDispatcher->addListener((EventListener *)ws2812FXDevices[0][0], EVENT_SOURCE_SOLENOID); + _eventDispatcher->addListener((EventListener *)ws2812FXDevices[0][0], EVENT_SOURCE_LIGHT); + } + + break; + } + break; + + case CONFIG_TOPIC_LAMPS: + if (ws2812FXDevices[0][0]) + { + switch (event->key) + { + case CONFIG_TOPIC_PORT: + config_port = event->value; + config_type = 0; + config_number = 0; + config_ledNumber = 0; + config_brightness = 0; + config_color = 0; + break; + case CONFIG_TOPIC_TYPE: + config_type = event->value; + break; + case CONFIG_TOPIC_NUMBER: + config_number = event->value; + break; + case CONFIG_TOPIC_LED_NUMBER: + config_ledNumber = event->value; + break; + case CONFIG_TOPIC_BRIGHTNESS: + config_brightness = event->value; + break; + case CONFIG_TOPIC_COLOR: + config_color = event->value; + switch (config_type) + { + case LED_TYPE_GI: + ((CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevices[0][0])->assignLedToGiString(config_number, config_ledNumber, config_color); break; - case CONFIG_TOPIC_AFTER_GLOW: - config_afterGlow = event->value; + case LED_TYPE_LAMP: + if (platform == PLATFORM_WPC) + { + ((CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevices[0][0])->assignLedToLightMatrixWPC(config_number, config_ledNumber, config_color); + } + else + { + ((CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevices[0][0])->assignLedToLightMatrix(config_number, config_ledNumber, config_color); + } break; - case CONFIG_TOPIC_LIGHT_UP: - config_heatUp = event->value; - ws2812FXDevices[0][0] = new WS2812FXDevice( - new WS2812FX(config_amount, config_port, config_type), - 0, - config_amount - 1, - 0, - 0 - ); - ws2812FXDevices[0][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[0] = 1; - - // Brightness might be overwritten later. - //ws2812FXDevices[0][0]->setBrightness(WS2812FX_BRIGHTNESS); - ws2812FXDevices[0][0]->off(); - ws2812FXstates[0] = true; + case LED_TYPE_FLASHER: + ((CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevices[0][0])->assignLedToFlasher(config_number, config_ledNumber, config_color); break; + } + break; } break; + } } } } -void EffectsController::update() { - if (controllerType == CONTROLLER_MEGA_ALL_INPUT) { +void EffectsController::update() +{ + if (controllerType == CONTROLLER_MEGA_ALL_INPUT) + { _testButtons->update(); } - if (platform == PLATFORM_WPC) { + if (platform == PLATFORM_WPC && controllerType != CONTROLLER_16_8_1) + { _generalIllumintationWPC->update(); } _eventDispatcher->update(); - for (int i = 0; i <= stackCounter; i++) { - if (stackEffectContainers[i]->effect->isRunning()) { + for (int i = 0; i <= stackCounter; i++) + { + if (stackEffectContainers[i]->effect->isRunning()) + { stackEffectContainers[i]->effect->updateMillis(); stackEffectContainers[i]->effect->update(); } } - if (millis() - ws2812UpdateInterval > UPDATE_INTERVAL_WS2812FX_EFFECTS) { + if (millis() - ws2812UpdateInterval > UPDATE_INTERVAL_WS2812FX_EFFECTS) + { // Updating the LEDs too fast leads to undefined behavior. Just update effects every 3ms. ws2812UpdateInterval = millis(); - for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) { - if (ws2812FXstates[i]) { - if (ws2812FXrunning[i]) { + for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) + { + if (ws2812FXstates[i]) + { + if (ws2812FXrunning[i]) + { ws2812FXDevices[i][0]->getWS2812FX()->service(); bool stop = true; - for (int k = 0; k < ws2812FXDeviceCounters[i]; k++) { + for (int k = 0; k < ws2812FXDeviceCounters[i]; k++) + { stop &= ws2812FXDevices[i][k]->isStopped(); } - if (stop) { + if (stop) + { ws2812FXDevices[i][0]->getWS2812FX()->stop(); ws2812FXrunning[i] = false; } - } else { + } + else + { bool start = false; - for (int k = 0; k < ws2812FXDeviceCounters[i]; k++) { + for (int k = 0; k < ws2812FXDeviceCounters[i]; k++) + { start |= !ws2812FXDevices[i][k]->isStopped(); } - if (start) { + if (start) + { ws2812FXDevices[i][0]->getWS2812FX()->start(); ws2812FXrunning[i] = true; ws2812FXDevices[i][0]->getWS2812FX()->service(); @@ -232,27 +334,35 @@ void EffectsController::update() { } } - if (millis() - ws2812AfterGlowUpdateInterval > UPDATE_INTERVAL_WS2812FX_AFTERGLOW) { + if (millis() - ws2812AfterGlowUpdateInterval > UPDATE_INTERVAL_WS2812FX_AFTERGLOW) + { // Updating the LEDs too fast leads to undefined behavior. Just update every 3ms. ws2812AfterGlowUpdateInterval = millis(); - for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) { - if (ws2812FXstates[i] && ws2812FXDevices[i][0]->hasAfterGlowSupport() && !ws2812FXrunning[i]) { + for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) + { + if (ws2812FXstates[i] && ws2812FXDevices[i][0]->hasAfterGlowSupport() && !ws2812FXrunning[i]) + { // No other effect is running, handle after glow effect. - ((CombinedGiAndLightMatrixWS2812FXDevice *) ws2812FXDevices[i][0])->updateAfterGlow(); + ((CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevices[i][0])->updateAfterGlow(); ws2812FXDevices[i][0]->getWS2812FX()->show(); } } } - if (brightnessControlBasePin > 0) { - if (millis() - brightnessUpdateInterval > UPDATE_INTERVAL_WS2812FX_BRIGHTNESS) { + if (brightnessControlBasePin > 0) + { + if (millis() - brightnessUpdateInterval > UPDATE_INTERVAL_WS2812FX_BRIGHTNESS) + { // Don't update the brightness too often. brightnessUpdateInterval = millis(); - for (byte i = 0; i < PPUC_MAX_BRIGHTNESS_CONTROLS; i++) { + for (byte i = 0; i < PPUC_MAX_BRIGHTNESS_CONTROLS; i++) + { brightnessControlReads[i] = analogRead(brightnessControlBasePin + i) / 4; } - for (byte i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) { - if (brightnessControl[i] > 0) { + for (byte i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) + { + if (brightnessControl[i] > 0) + { setBrightness(i + 1, brightnessControlReads[brightnessControl[i - 1]]); } } @@ -260,14 +370,16 @@ void EffectsController::update() { } } -void EffectsController::start() { - for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) { - if (ws2812FXbrightness[i] == 0) { +void EffectsController::start() +{ + for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) + { + if (ws2812FXbrightness[i] == 0) + { setBrightness(i + 1, WS2812FX_BRIGHTNESS); } } _eventDispatcher->dispatch( - new Event(EVENT_SOURCE_EFFECT, 1, 255) - ); + new Event(EVENT_SOURCE_EFFECT, 1, 255)); } diff --git a/src/EffectsController.h b/src/EffectsController.h index f1ab9d9..a101ac4 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -289,9 +289,8 @@ class EffectsController : public EventListener { #endif } else if (controllerType == CONTROLLER_16_8_1) { - // Read bordID. - // @todo draft! - boardId = (analogRead(28) - 100) / 16 ; + // Read bordID. The read value is between 60 and 940. + boardId = 16 - ((int) ((analogRead(28) + 20) / 60)); } else { Serial.print("Unsupported Effects Controller: "); Serial.println(controllerType); @@ -395,6 +394,10 @@ class EffectsController : public EventListener { byte config_amount = 0; byte config_afterGlow = 0; byte config_heatUp = 0; + byte config_number = 0; + byte config_ledNumber = 0; + byte config_brightness = 0; + UINT32 config_color = 0; unsigned long ws2812UpdateInterval = 0; unsigned long ws2812AfterGlowUpdateInterval = 0; diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 4760520..a8b91bb 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -23,6 +23,7 @@ #define EVENT_SOURCE_SOLENOID 83 // "S" VPX/DOF/PUP includes flashers #define EVENT_SOURCE_SWITCH 87 // "W" VPX/DOF/PUP +#define CONFIG_TOPIC_PLATFORM 102 // "f" #define CONFIG_TOPIC_LED_STRING 103 // "g" #define CONFIG_TOPIC_LAMPS 108 // "l" #define CONFIG_TOPIC_MECHS 109 // "m" @@ -30,9 +31,12 @@ #define CONFIG_TOPIC_SWITCHES 115 // "s" #define CONFIG_TOPIC_HOLD_POWER_ACTIVATION_TIME 65 // "A" +#define CONFIG_TOPIC_BRIGHTNESS 66 // "B" +#define CONFIG_TOPIC_COLOR 67 // "C" #define CONFIG_TOPIC_FAST_SWITCH 70 // "F" #define CONFIG_TOPIC_AFTER_GLOW 71 // "G" #define CONFIG_TOPIC_HOLD_POWER 72 // "H" +#define CONFIG_TOPIC_LED_NUMBER 76 // "L" #define CONFIG_TOPIC_MAX_PULSE_TIME 77 // "M" #define CONFIG_TOPIC_NUMBER 78 // "N" #define CONFIG_TOPIC_AMOUNT_LEDS 79 // "O" @@ -42,6 +46,14 @@ #define CONFIG_TOPIC_POWER 87 // "W" #define CONFIG_TOPIC_TYPE 89 // "Y" +#define PWM_TYPE_SOLENOID 1 // Coil +#define PWM_TYPE_FLASHER 2 // Flasher +#define PWM_TYPE_LAMP 3 // Lamp + +#define LED_TYPE_GI 1 // GI +#define LED_TYPE_FLASHER 2 // Flasher +#define LED_TYPE_LAMP 3 // Lamp + typedef unsigned char UINT8; typedef unsigned short UINT16; typedef unsigned int UINT32; diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index 239d8db..3f428e4 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -23,10 +23,13 @@ void EventDispatcher::setMultiCoreCrossLink(MultiCoreCrossLink* mccl) { #endif } -// Backward Compatibility, use addCrossLinkSerial(). +MultiCoreCrossLink* EventDispatcher::getMultiCoreCrossLink() { + return multiCoreCrossLink; +} + void EventDispatcher::setCrossLinkSerial(HardwareSerial &reference) { - crossLink = -1; - addCrossLinkSerial(reference); + hwSerial[0] = (HardwareSerial*) &reference; + crossLink = 0; } void EventDispatcher::addCrossLinkSerial(HardwareSerial &reference) { @@ -151,7 +154,9 @@ void EventDispatcher::update() { } for (int i = 0; i <= crossLink; i++) { + //Serial.println(hwSerial[i]->available()); if (hwSerial[i]->available() >= 6) { + //digitalWrite(25, LOW); // Write. byte startByte = hwSerial[i]->read(); if (startByte == 255) { byte sourceId = hwSerial[i]->read(); diff --git a/src/EventDispatcher/EventDispatcher.h b/src/EventDispatcher/EventDispatcher.h index 4b629f2..0a930c2 100644 --- a/src/EventDispatcher/EventDispatcher.h +++ b/src/EventDispatcher/EventDispatcher.h @@ -35,6 +35,8 @@ class EventDispatcher { void setMultiCoreCrossLink(MultiCoreCrossLink* mccl); + MultiCoreCrossLink* getMultiCoreCrossLink(); + void setCrossLinkSerial(HardwareSerial &reference); void addCrossLinkSerial(HardwareSerial &reference); diff --git a/src/EventDispatcher/MultiCoreCrossLink.h b/src/EventDispatcher/MultiCoreCrossLink.h index fa2f1c7..d86b87d 100644 --- a/src/EventDispatcher/MultiCoreCrossLink.h +++ b/src/EventDispatcher/MultiCoreCrossLink.h @@ -27,6 +27,7 @@ class MultiCoreCrossLink { } bool pushEventNonBlocking(Event* event) { + // Clone the event so that Eventdispatcher::callListeners() can delete the event. return queue_try_add(&_eventQueue[get_core_num() ^ 1], new Event(event)); } @@ -52,6 +53,7 @@ class MultiCoreCrossLink { bool pushConfigEventNonBlocking(ConfigEvent* event) { if (get_core_num() == 0) { + // Clone the event so that Eventdispatcher::callListeners() can delete the event. return queue_try_add(&_configEventQueue, new ConfigEvent(event)); } diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 37e61c6..600a741 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -5,16 +5,22 @@ IOBoardController::IOBoardController(int controllerType) { _eventDispatcher->addListener(this, EVENT_CONFIGURATION); if (controllerType == CONTROLLER_16_8_1) { - // Read bordID. - // @todo draft! - boardId = (analogRead(28) - 100) / 16 ; + // Turn on the LED + pinMode(25, OUTPUT); + digitalWrite(25, HIGH); + + // Read bordID. The read value is between 60 and 940. + boardId = 16 - ((int) ((analogRead(28) + 20) / 60)); #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - Serial1.setTX(16); - Serial1.setRX(17); - _eventDispatcher->setRS485ModePin(18); + Serial1.setTX(0); + Serial1.setRX(1); Serial1.setFIFOSize(128); // @todo find the right size. - _eventDispatcher->addCrossLinkSerial(Serial1); + Serial1.begin(115200); + _eventDispatcher->setRS485ModePin(2); + _eventDispatcher->setCrossLinkSerial(Serial1); + _multiCoreCrossLink = new MultiCoreCrossLink(); + _eventDispatcher->setMultiCoreCrossLink(_multiCoreCrossLink); #endif _pwmDevices = new PwmDevices(_eventDispatcher); @@ -80,13 +86,13 @@ void IOBoardController::handleEvent(ConfigEvent* event) { break; case CONFIG_TOPIC_TYPE: switch (event->value) { - case 1: // Coil + case PWM_TYPE_SOLENOID: // Coil _pwmDevices->registerSolenoid((byte) port, number, power, minPulseTime, maxPulseTime, holdPower, holdPowerActivationTime, fastSwitch); break; - case 2: // Flasher + case PWM_TYPE_FLASHER: // Flasher _pwmDevices->registerFlasher((byte) port, number, power); break; - case 3: // Lamp + case PWM_TYPE_LAMP: // Lamp _pwmDevices->registerLamp((byte) port, number, power); break; } diff --git a/src/IOBoardController.h b/src/IOBoardController.h index 85bb745..d2e0de6 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -18,6 +18,7 @@ #include "EventDispatcher/Event.h" #include "EventDispatcher/EventDispatcher.h" +#include "EventDispatcher/MultiCoreCrossLink.h" #include "IODevices/PwmDevices.h" #include "IODevices/Switches.h" @@ -52,6 +53,9 @@ class IOBoardController : public EventListener { byte fastSwitch = 0; EventDispatcher* _eventDispatcher; +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) + MultiCoreCrossLink* _multiCoreCrossLink; +#endif }; #endif diff --git a/src/IODevices/PwmDevices.cpp b/src/IODevices/PwmDevices.cpp index f47f6a1..0675063 100644 --- a/src/IODevices/PwmDevices.cpp +++ b/src/IODevices/PwmDevices.cpp @@ -1,7 +1,9 @@ #include "PwmDevices.h" -void PwmDevices::registerSolenoid(byte p, byte n, byte pow, byte minPT, byte maxPT, byte hP, byte hPAT, byte fS) { - if (last < MAX_PWM_OUTPUTS) { +void PwmDevices::registerSolenoid(byte p, byte n, byte pow, byte minPT, byte maxPT, byte hP, byte hPAT, byte fS) +{ + if (last < MAX_PWM_OUTPUTS) + { port[last] = p; number[last] = n; power[last] = pow; @@ -13,105 +15,142 @@ void PwmDevices::registerSolenoid(byte p, byte n, byte pow, byte minPT, byte max pinMode(p, OUTPUT); analogWrite(p, 0); - type[last++] = 1; + type[last++] = PWM_TYPE_SOLENOID; } } -void PwmDevices::registerFlasher(byte p, byte n, byte pow) { - if (last < MAX_PWM_OUTPUTS) { +void PwmDevices::registerFlasher(byte p, byte n, byte pow) +{ + if (last < MAX_PWM_OUTPUTS) + { port[last] = p; number[last] = n; power[last] = pow; pinMode(p, OUTPUT); analogWrite(p, 0); - type[last++] = 2; + type[last++] = PWM_TYPE_FLASHER; } } -void PwmDevices::registerLamp(byte p, byte n, byte pow) { - if (last < MAX_PWM_OUTPUTS) { +void PwmDevices::registerLamp(byte p, byte n, byte pow) +{ + if (last < MAX_PWM_OUTPUTS) + { port[last] = p; number[last] = n; power[last] = pow; pinMode(p, OUTPUT); analogWrite(p, 0); - type[last++] = 3; + type[last++] = PWM_TYPE_LAMP; } } -void PwmDevices::update() { +void PwmDevices::update() +{ _ms = millis(); - for (byte i = 0; i < last; i++) { - if (activated[i] > 0) { + // Iterate over all outputs. + for (byte i = 0; i < last; i++) + { + if (activated[i] > 0) + { + // The output is active. if ( - (scheduled[i] && ((_ms - activated[i]) > minPulseTime[i])) || - ((maxPulseTime[i] > 0) && ((_ms - activated[i]) > maxPulseTime[i])) - ) { + (scheduled[i] && ((_ms - activated[i]) > minPulseTime[i])) || + ((maxPulseTime[i] > 0) && ((_ms - activated[i]) > maxPulseTime[i]))) + { + // Deactivate the output if it is scheduled for delayed deactivation and the minimum pulse time is reached. + // Deactivate the output if the maximum pulse time is reached. analogWrite(port[i], 0); activated[i] = 0; scheduled[i] = false; } - else if ((holdPowerActivationTime[i] > 0) && ((_ms - activated[i]) > holdPowerActivationTime[i])) { + else if ((holdPowerActivationTime[i] > 0) && ((_ms - activated[i]) > holdPowerActivationTime[i])) + { + // Reduce the power of the activated output if the hold power activation time pased since the activation. analogWrite(port[i], holdPower[i]); } } } } -void PwmDevices::handleEvent(Event* event) { +void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) +{ _ms = millis(); - switch (event->eventId) { - case EVENT_SOURCE_SOLENOID: - for (byte i = 0; i < last; i++) { - if ((type[i] == 1 || type[i] == 2) && number[i] == (byte) event->eventId) { - if (event->value && !activated[i]) { - analogWrite(port[i], power[i]); - activated[i] = _ms; - } - else if (!event->value && activated[i]) { - if (minPulseTime[i] > 0 && (_ms - activated[i]) < minPulseTime[i]) { - scheduled[i] = true; - } - else { - analogWrite(port[i], 0); - activated[i] = 0; - } - } - } + if (targetState && !activated[i]) + { + // Event received to activate the output and output isn't activated already. + // Activate it! + analogWrite(port[i], power[i]); + // Rememebr whin it got activated. + activated[i] = _ms; + } + else if (!targetState && activated[i]) + { + // Event received to deactivate the output. + // Check if a minimum pulse time is configured for this output. + if (minPulseTime[i] > 0 && (_ms - activated[i]) < minPulseTime[i]) + { + // A minimum pulse time is configured for this output. + // Don't deactivate it immediately but schedule its later deactivation. + scheduled[i] = true; + } + else + { + // Deactivate the output. + analogWrite(port[i], 0); + // Mark the output as deactivated. + activated[i] = 0; + } + } +} + +void PwmDevices::handleEvent(Event *event) +{ + _ms = millis(); + + switch (event->eventId) + { + case EVENT_SOURCE_SOLENOID: + for (byte i = 0; i < last; i++) + { + if ((type[i] == PWM_TYPE_SOLENOID || type[i] == PWM_TYPE_FLASHER) && number[i] == (byte)event->eventId) + { + updateSolenoidOrFlasher((bool)event->value, i); } - break; + } + break; - case EVENT_SOURCE_SWITCH: - for (byte i = 0; i < last; i++) { - if (type[i] == 1 && fastSwitch[i] == (byte) event->eventId) { - if (event->value) { - analogWrite(port[i], power[i]); - activated[i] = _ms; - } - else if (activated[i]) { - analogWrite(port[i], 0); - activated[i] = 0; - scheduled[i] = false; - } - } + case EVENT_SOURCE_SWITCH: + // A switch event was triggered or received. Activate or deactivate any output + // that is configured as "fastSwitch" for that switch. + for (byte i = 0; i < last; i++) + { + if (type[i] == PWM_TYPE_SOLENOID && fastSwitch[i] == (byte)event->eventId) + { + updateSolenoidOrFlasher((bool)event->value, i); } - break; + } + break; - case EVENT_SOURCE_LIGHT: - for (byte i = 0; i < last; i++) { - if (type[i] == 3 && number[i] == (byte) event->eventId) { - if (event->value) { - analogWrite(port[i], power[i]); - } - else if (activated[i]) { - analogWrite(port[i], 0); - } + case EVENT_SOURCE_LIGHT: + for (byte i = 0; i < last; i++) + { + if (type[i] == PWM_TYPE_LAMP && number[i] == (byte)event->eventId) + { + if (event->value) + { + analogWrite(port[i], power[i]); + } + else if (activated[i]) + { + analogWrite(port[i], 0); } } - break; + } + break; } } \ No newline at end of file diff --git a/src/IODevices/PwmDevices.h b/src/IODevices/PwmDevices.h index 345bc72..89334f3 100644 --- a/src/IODevices/PwmDevices.h +++ b/src/IODevices/PwmDevices.h @@ -16,10 +16,12 @@ #define MAX_PWM_OUTPUTS 16 #endif -class PwmDevices : public EventListener { +class PwmDevices : public EventListener +{ public: - //Constructor - PwmDevices(EventDispatcher* eD) { + // Constructor + PwmDevices(EventDispatcher *eD) + { _eventDispatcher = eD; _eventDispatcher->addListener(this, EVENT_SOURCE_LIGHT); _eventDispatcher->addListener(this, EVENT_SOURCE_SOLENOID); @@ -32,9 +34,9 @@ class PwmDevices : public EventListener { void update(); - void handleEvent(Event* event); + void handleEvent(Event *event); - void handleEvent(ConfigEvent* event) {} + void handleEvent(ConfigEvent *event) {} private: unsigned long _ms; @@ -52,7 +54,9 @@ class PwmDevices : public EventListener { bool scheduled[MAX_PWM_OUTPUTS] = {0}; byte last = 0; - EventDispatcher* _eventDispatcher; + EventDispatcher *_eventDispatcher; + + void updateSolenoidOrFlasher(bool targetState, byte i); }; #endif diff --git a/src/InputDevices/Matrix.cpp b/src/InputDevices/Matrix.cpp index e4aaeb7..09b3c0b 100644 --- a/src/InputDevices/Matrix.cpp +++ b/src/InputDevices/Matrix.cpp @@ -7,8 +7,8 @@ Matrix::Matrix(EventDispatcher* eD, byte pf) { setLastColToRead(8); for (int i = 0; i < lastColToRead; i++) { - rows[i] = B00000000; - previousRows[i] = B00000000; + rows[i] = 0b00000000; + previousRows[i] = 0b00000000; } } diff --git a/test/IOBoardController/platformio.ini b/test/IOBoardController/platformio.ini index 42823b2..bb55bef 100644 --- a/test/IOBoardController/platformio.ini +++ b/test/IOBoardController/platformio.ini @@ -14,6 +14,8 @@ board = pico framework = arduino board_build.core = earlephilhower board_build.filesystem_size = 0.5m +build_flags = + -D PICO_STDIO_USB ; enable stdio over USB lib_extra_dirs = ../.. lib_deps = diff --git a/test/IOBoardController/src/main.cpp b/test/IOBoardController/src/main.cpp index bdd9657..81e1fb5 100644 --- a/test/IOBoardController/src/main.cpp +++ b/test/IOBoardController/src/main.cpp @@ -3,12 +3,23 @@ #include #include "IOBoardController.h" +#include "EffectsController.h" IOBoardController ioBoardController(CONTROLLER_16_8_1); +EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_LIBPINMAME); void setup() { + ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); +} + +void setup1() { } void loop() { ioBoardController.update(); + //Serial.println(16 - ((int) (analogRead(28) + 20) / 60)); +} + +void loop1() { + effectsController.update(); } From bf4aeafc763b5d8ee009473348a6808d2b554b10 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Tue, 22 Aug 2023 19:30:11 +0200 Subject: [PATCH 004/102] added HW_16_8_1 --- test/HW_16_8_1/platformio.ini | 14 ++++++++++++++ test/HW_16_8_1/src/main.cpp | 35 +++++++++++++++++++++++++++++++++++ test/HW_16_8_1/test/README | 11 +++++++++++ 3 files changed, 60 insertions(+) create mode 100644 test/HW_16_8_1/platformio.ini create mode 100644 test/HW_16_8_1/src/main.cpp create mode 100644 test/HW_16_8_1/test/README diff --git a/test/HW_16_8_1/platformio.ini b/test/HW_16_8_1/platformio.ini new file mode 100644 index 0000000..4035b4d --- /dev/null +++ b/test/HW_16_8_1/platformio.ini @@ -0,0 +1,14 @@ +[env:pico] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +board = pico +framework = arduino +board_build.core = earlephilhower +board_build.filesystem_size = 0.5m +build_flags = + -D PICO_STDIO_USB ; enable stdio over USB +lib_extra_dirs = + ../.. +lib_deps = + mkalkbrenner/WavePWM + kitesurfer1404/WS2812FX + Bounce2 diff --git a/test/HW_16_8_1/src/main.cpp b/test/HW_16_8_1/src/main.cpp new file mode 100644 index 0000000..53c5ef7 --- /dev/null +++ b/test/HW_16_8_1/src/main.cpp @@ -0,0 +1,35 @@ +// Markus Kalkbrenner 2023 + +#include + +#include "IOBoardController.h" +#include "EffectsController.h" + +IOBoardController ioBoardController(CONTROLLER_16_8_1); +// Platform will be adjusted by ConfigEvent. +EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_LIBPINMAME); + +// Each controller will be bound to its own core and has it's own +// EventDispatcher. Only the EventDispatcher of IOBoardController +// is attached to RS485. But both EventDispatchers must share the +// same MultiCoreCrosslink to send and receive events between +// both cores. + +void setup() { + //ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); +} + +void setup1() { + effectsController.eventDispatcher()->setMultiCoreCrossLink( + ioBoardController.eventDispatcher()->getMultiCoreCrossLink() + ); +} + +void loop() { + ioBoardController.update(); + //Serial.println(16 - ((int) (analogRead(28) + 20) / 60)); +} + +void loop1() { + effectsController.update(); +} diff --git a/test/HW_16_8_1/test/README b/test/HW_16_8_1/test/README new file mode 100644 index 0000000..b94d089 --- /dev/null +++ b/test/HW_16_8_1/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html From 43293f2ebc0d28fa9e1f88298ab11188211ed13d Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 23 Aug 2023 11:46:34 +0200 Subject: [PATCH 005/102] use unified int types --- src/EffectsController.h | 2 +- src/EventDispatcher/Event.h | 6 ++---- src/PPUC.h | 4 ---- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/EffectsController.h b/src/EffectsController.h index a101ac4..603de12 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -397,7 +397,7 @@ class EffectsController : public EventListener { byte config_number = 0; byte config_ledNumber = 0; byte config_brightness = 0; - UINT32 config_color = 0; + uint32_t config_color = 0; unsigned long ws2812UpdateInterval = 0; unsigned long ws2812AfterGlowUpdateInterval = 0; diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index a8b91bb..dc0d117 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -54,10 +54,6 @@ #define LED_TYPE_FLASHER 2 // Flasher #define LED_TYPE_LAMP 3 // Lamp -typedef unsigned char UINT8; -typedef unsigned short UINT16; -typedef unsigned int UINT32; - struct Event { byte sourceId; word eventId; @@ -85,6 +81,7 @@ struct Event { localFast = lf; } + // Clone the event. Event(const Event* other) { sourceId = other->sourceId; eventId = other->eventId; @@ -120,6 +117,7 @@ struct ConfigEvent { value = v; } + // Clone the event. ConfigEvent(const ConfigEvent* other) { sourceId = other->sourceId; boardId = other->boardId; diff --git a/src/PPUC.h b/src/PPUC.h index 574d799..0bf102a 100644 --- a/src/PPUC.h +++ b/src/PPUC.h @@ -20,10 +20,6 @@ #define PLATFORM_SYS11 3 #define PLATFORM_LIBPINMAME 100 -typedef unsigned char UINT8; -typedef unsigned short UINT16; -typedef unsigned int UINT32; - #include #endif From 48995aba3fff810e599eeff895a7918da87eeabd Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 30 Aug 2023 17:35:10 +0200 Subject: [PATCH 006/102] added matrix types --- src/EventDispatcher/Event.h | 82 ++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index dc0d117..24b38c2 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -8,51 +8,57 @@ #ifndef EVENT_h #define EVENT_h -#define EVENT_SOURCE_ANY 42 // "*" -#define EVENT_SOURCE_DEBUG 66 // "B" Debug -#define EVENT_CONFIGURATION 67 // "C" Configure I/O -#define EVENT_SOURCE_DMD 68 // "D" VPX/DOF/PUP -#define EVENT_SOURCE_EVENT 69 // "E" VPX/DOF/PUP common event from different system, like -#define EVENT_SOURCE_EFFECT 70 // "F" custom event from running Effect -#define EVENT_SOURCE_GI 71 // "G" WPC GI -#define EVENT_SOURCE_LIGHT 76 // "L" VPX/DOF/PUP lights, mainly playfield inserts -#define EVENT_NULL 78 // "N" NULL event -#define EVENT_SOURCE_SOUND 79 // "O" sound command -#define EVENT_POLL_EVENTS 80 // "P" Poll events command, mainly read switches -#define EVENT_READ_SWITCHES 82 // "R" Read current state of all switches on i/o boards +#define EVENT_SOURCE_ANY 42 // "*" +#define EVENT_SOURCE_DEBUG 66 // "B" Debug +#define EVENT_CONFIGURATION 67 // "C" Configure I/O +#define EVENT_SOURCE_DMD 68 // "D" VPX/DOF/PUP +#define EVENT_SOURCE_EVENT 69 // "E" VPX/DOF/PUP common event from different system, like +#define EVENT_SOURCE_EFFECT 70 // "F" custom event from running Effect +#define EVENT_SOURCE_GI 71 // "G" WPC GI +#define EVENT_SOURCE_LIGHT 76 // "L" VPX/DOF/PUP lights, mainly playfield inserts +#define EVENT_NULL 78 // "N" NULL event +#define EVENT_SOURCE_SOUND 79 // "O" sound command +#define EVENT_POLL_EVENTS 80 // "P" Poll events command, mainly read switches +#define EVENT_READ_SWITCHES 82 // "R" Read current state of all switches on i/o boards #define EVENT_SOURCE_SOLENOID 83 // "S" VPX/DOF/PUP includes flashers -#define EVENT_SOURCE_SWITCH 87 // "W" VPX/DOF/PUP +#define EVENT_SOURCE_SWITCH 87 // "W" VPX/DOF/PUP -#define CONFIG_TOPIC_PLATFORM 102 // "f" -#define CONFIG_TOPIC_LED_STRING 103 // "g" -#define CONFIG_TOPIC_LAMPS 108 // "l" -#define CONFIG_TOPIC_MECHS 109 // "m" -#define CONFIG_TOPIC_PWM 112 // "p" -#define CONFIG_TOPIC_SWITCHES 115 // "s" +#define CONFIG_TOPIC_PLATFORM 102 // "f" +#define CONFIG_TOPIC_LED_STRING 103 // "g" +#define CONFIG_TOPIC_LAMPS 108 // "l" +#define CONFIG_TOPIC_MECHS 109 // "m" +#define CONFIG_TOPIC_PWM 112 // "p" +#define CONFIG_TOPIC_SWITCHES 115 // "s" +#define CONFIG_TOPIC_SWITCH_MATRIX 120 // "x" #define CONFIG_TOPIC_HOLD_POWER_ACTIVATION_TIME 65 // "A" -#define CONFIG_TOPIC_BRIGHTNESS 66 // "B" -#define CONFIG_TOPIC_COLOR 67 // "C" -#define CONFIG_TOPIC_FAST_SWITCH 70 // "F" -#define CONFIG_TOPIC_AFTER_GLOW 71 // "G" -#define CONFIG_TOPIC_HOLD_POWER 72 // "H" -#define CONFIG_TOPIC_LED_NUMBER 76 // "L" -#define CONFIG_TOPIC_MAX_PULSE_TIME 77 // "M" -#define CONFIG_TOPIC_NUMBER 78 // "N" -#define CONFIG_TOPIC_AMOUNT_LEDS 79 // "O" -#define CONFIG_TOPIC_PORT 80 // "P" -#define CONFIG_TOPIC_MIN_PULSE_TIME 84 // "T" -#define CONFIG_TOPIC_LIGHT_UP 85 // "U" -#define CONFIG_TOPIC_POWER 87 // "W" -#define CONFIG_TOPIC_TYPE 89 // "Y" +#define CONFIG_TOPIC_BRIGHTNESS 66 // "B" +#define CONFIG_TOPIC_COLOR 67 // "C" +#define CONFIG_TOPIC_FAST_SWITCH 70 // "F" +#define CONFIG_TOPIC_AFTER_GLOW 71 // "G" +#define CONFIG_TOPIC_HOLD_POWER 72 // "H" +#define CONFIG_TOPIC_LED_NUMBER 76 // "L" +#define CONFIG_TOPIC_MAX_PULSE_TIME 77 // "M" +#define CONFIG_TOPIC_NUMBER 78 // "N" +#define CONFIG_TOPIC_AMOUNT_LEDS 79 // "O" +#define CONFIG_TOPIC_PORT 80 // "P" +#define CONFIG_TOPIC_MAX_PULSE_TIME 77 // "M" +#define CONFIG_TOPIC_MIN_PULSE_TIME 84 // "T" +#define CONFIG_TOPIC_LIGHT_UP 85 // "U" +#define CONFIG_TOPIC_ACTIVE_LOW 86 // "V" +#define CONFIG_TOPIC_POWER 87 // "W" +#define CONFIG_TOPIC_TYPE 89 // "Y" #define PWM_TYPE_SOLENOID 1 // Coil -#define PWM_TYPE_FLASHER 2 // Flasher -#define PWM_TYPE_LAMP 3 // Lamp +#define PWM_TYPE_FLASHER 2 // Flasher +#define PWM_TYPE_LAMP 3 // Lamp -#define LED_TYPE_GI 1 // GI -#define LED_TYPE_FLASHER 2 // Flasher -#define LED_TYPE_LAMP 3 // Lamp +#define LED_TYPE_GI 1 // GI +#define LED_TYPE_FLASHER 2 // Flasher +#define LED_TYPE_LAMP 3 // Lamp + +#define MATRIX_TYPE_COLUMN 1 // Column +#define MATRIX_TYPE_ROW 2 // Row struct Event { byte sourceId; From c5f2671c97676fa027ca994d43ef094ff9af4d83 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Fri, 1 Sep 2023 18:10:51 +0200 Subject: [PATCH 007/102] handle ping event --- src/EventDispatcher/Event.h | 4 +++- src/IOBoardController.cpp | 8 ++++++++ src/IOBoardController.h | 2 +- src/IODevices/Switches.cpp | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 24b38c2..1ab3e37 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -22,6 +22,8 @@ #define EVENT_READ_SWITCHES 82 // "R" Read current state of all switches on i/o boards #define EVENT_SOURCE_SOLENOID 83 // "S" VPX/DOF/PUP includes flashers #define EVENT_SOURCE_SWITCH 87 // "W" VPX/DOF/PUP +#define EVENT_PING 88 // "X" +#define EVENT_PONG 89 // "Y" #define CONFIG_TOPIC_PLATFORM 102 // "f" #define CONFIG_TOPIC_LED_STRING 103 // "g" @@ -58,7 +60,7 @@ #define LED_TYPE_LAMP 3 // Lamp #define MATRIX_TYPE_COLUMN 1 // Column -#define MATRIX_TYPE_ROW 2 // Row +#define MATRIX_TYPE_ROW 2 // Row struct Event { byte sourceId; diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 600a741..ce7d824 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -37,6 +37,14 @@ void IOBoardController::update() { eventDispatcher()->update(); } +void IOBoardController::handleEvent(Event* event) { + switch (event->sourceId) { + case EVENT_PING: + _eventDispatcher->dispatch(new Event(EVENT_PONG, 0, boardId)); + break; + } +} + void IOBoardController::handleEvent(ConfigEvent* event) { if (event->boardId == boardId) { switch (event->topic) { diff --git a/src/IOBoardController.h b/src/IOBoardController.h index d2e0de6..10f88c3 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -32,7 +32,7 @@ class IOBoardController : public EventListener { EventDispatcher* eventDispatcher(); - void handleEvent(Event* event) {} + void handleEvent(Event* event); void handleEvent(ConfigEvent* event); diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index af88984..658a6a2 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -32,7 +32,7 @@ void Switches::update() { } void Switches::handleEvent(Event* event) { - switch (event->eventId) { + switch (event->sourceId) { case EVENT_POLL_EVENTS: if (boardId == (byte) event->value) { // This I/O board has been polled for events, so all current switch states are transmitted. Reset switch From cef39bf65f5086c506904aa52d0d73f5acf636a0 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 3 Sep 2023 23:27:47 +0200 Subject: [PATCH 008/102] fixed HW_16_8_1 configEvents --- src/EventDispatcher/CrossLinkDebugger.cpp | 11 +- src/EventDispatcher/CrossLinkDebugger.h | 2 +- src/EventDispatcher/Event.h | 9 + src/EventDispatcher/EventDispatcher.cpp | 232 ++++++++++++++-------- src/EventDispatcher/EventDispatcher.h | 6 +- src/EventDispatcher/MultiCoreCrossLink.h | 2 +- src/IOBoardController.cpp | 17 +- test/HW_16_8_1/src/main.cpp | 36 +++- 8 files changed, 208 insertions(+), 107 deletions(-) diff --git a/src/EventDispatcher/CrossLinkDebugger.cpp b/src/EventDispatcher/CrossLinkDebugger.cpp index 812d054..74ccad2 100644 --- a/src/EventDispatcher/CrossLinkDebugger.cpp +++ b/src/EventDispatcher/CrossLinkDebugger.cpp @@ -1,7 +1,11 @@ #include "CrossLinkDebugger.h" +CrossLinkDebugger::CrossLinkDebugger() { + Serial.println("PPUC CrossLinkDebugger"); + Serial.println("----------------------"); +} + void CrossLinkDebugger::handleEvent(Event* event) { - // On Teensy Serial is the USB Serial. Serial.print("handleEvent: sourceId "); Serial.print(event->sourceId); Serial.print(", eventId "); @@ -11,8 +15,7 @@ void CrossLinkDebugger::handleEvent(Event* event) { } void CrossLinkDebugger::handleEvent(ConfigEvent* event) { - // On Teensy Serial is the USB Serial. - Serial.print("handleEvent: ConfigEvent, boardId "); + Serial.print("handleConfigEvent: boardId "); Serial.print(event->boardId, DEC); Serial.print(", topic "); Serial.print(event->topic, DEC); @@ -20,6 +23,6 @@ void CrossLinkDebugger::handleEvent(ConfigEvent* event) { Serial.print(event->index, DEC); Serial.print(", key "); Serial.print(event->key, DEC); - Serial.print(", value "); + Serial.print(", value(HEX) "); Serial.println(event->value, HEX); } diff --git a/src/EventDispatcher/CrossLinkDebugger.h b/src/EventDispatcher/CrossLinkDebugger.h index 512cd64..664f4ad 100644 --- a/src/EventDispatcher/CrossLinkDebugger.h +++ b/src/EventDispatcher/CrossLinkDebugger.h @@ -15,7 +15,7 @@ class CrossLinkDebugger : public EventListener { public: - CrossLinkDebugger() {} + CrossLinkDebugger(); void handleEvent(Event* event); void handleEvent(ConfigEvent* event); diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 1ab3e37..7c76ca9 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -24,6 +24,7 @@ #define EVENT_SOURCE_SWITCH 87 // "W" VPX/DOF/PUP #define EVENT_PING 88 // "X" #define EVENT_PONG 89 // "Y" +#define EVENT_RESET 90 // "Z" #define CONFIG_TOPIC_PLATFORM 102 // "f" #define CONFIG_TOPIC_LED_STRING 103 // "g" @@ -68,6 +69,14 @@ struct Event { byte value; bool localFast; + Event(byte sId) + { + sourceId = sId; + eventId = 1; + value = 1; + localFast = false; + } + Event(byte sId, word eId) { sourceId = sId; eventId = eId; diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index 3f428e4..b5ce273 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -1,102 +1,125 @@ #include "EventDispatcher.h" -EventDispatcher::EventDispatcher() { - msg[0] = (byte) 255; - msg[5] = (byte) 255; - - cmsg[0] = (byte) 255; - cmsg[1] = (byte) EVENT_CONFIGURATION; - cmsg[10] = (byte) 255; +EventDispatcher::EventDispatcher() +{ } -void EventDispatcher::setRS485ModePin(int pin) { +void EventDispatcher::setRS485ModePin(int pin) +{ rs485 = true; rs485Pin = pin; pinMode(rs485Pin, OUTPUT); digitalWrite(rs485Pin, LOW); // Read. } -void EventDispatcher::setMultiCoreCrossLink(MultiCoreCrossLink* mccl) { +void EventDispatcher::setBoard(byte b) +{ + board = b; +} + +void EventDispatcher::setMultiCoreCrossLink(MultiCoreCrossLink *mccl) +{ #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) multiCoreCrossLink = mccl; multiCore = true; #endif } -MultiCoreCrossLink* EventDispatcher::getMultiCoreCrossLink() { +MultiCoreCrossLink *EventDispatcher::getMultiCoreCrossLink() +{ return multiCoreCrossLink; } -void EventDispatcher::setCrossLinkSerial(HardwareSerial &reference) { - hwSerial[0] = (HardwareSerial*) &reference; +void EventDispatcher::setCrossLinkSerial(HardwareSerial &reference) +{ + hwSerial[0] = (HardwareSerial *)&reference; crossLink = 0; } -void EventDispatcher::addCrossLinkSerial(HardwareSerial &reference) { - hwSerial[++crossLink] = (HardwareSerial*) &reference; +void EventDispatcher::addCrossLinkSerial(HardwareSerial &reference) +{ + hwSerial[++crossLink] = (HardwareSerial *)&reference; hwSerial[crossLink]->begin(115200); } -void EventDispatcher::addListener(EventListener* eventListener) { +void EventDispatcher::addListener(EventListener *eventListener) +{ addListener(eventListener, EVENT_SOURCE_ANY); } -void EventDispatcher::addListener(EventListener* eventListener, char sourceId) { - if (numListeners < (MAX_EVENT_LISTENERS - 1)) { +void EventDispatcher::addListener(EventListener *eventListener, char sourceId) +{ + if (numListeners < (MAX_EVENT_LISTENERS - 1)) + { eventListeners[++numListeners] = eventListener; eventListenerFilters[numListeners] = sourceId; } } -void EventDispatcher::dispatch(Event* event) { - if (stackCounter < (EVENT_STACK_SIZE - 1)) { +void EventDispatcher::dispatch(Event *event) +{ + if (stackCounter < (EVENT_STACK_SIZE - 1)) + { stackEvents[++stackCounter] = event; - if (event->localFast) { - for (byte i = 0; i <= numListeners; i++) { - if (event->sourceId == eventListenerFilters[i] || EVENT_SOURCE_ANY == eventListenerFilters[i]) { + if (event->localFast) + { + for (byte i = 0; i <= numListeners; i++) + { + if (event->sourceId == eventListenerFilters[i] || EVENT_SOURCE_ANY == eventListenerFilters[i]) + { eventListeners[i]->handleEvent(event); } } } } - else { + else + { // Too many events stacked, delete the event and free the memory. delete event; } } -void EventDispatcher::callListeners(Event* event, int sender, bool flush) { - if (!event->localFast) { - for (byte i = 0; i <= numListeners; i++) { - if (event->sourceId == eventListenerFilters[i] || EVENT_SOURCE_ANY == eventListenerFilters[i]) { +void EventDispatcher::callListeners(Event *event, int sender, bool flush) +{ + if (!event->localFast) + { + for (byte i = 0; i <= numListeners; i++) + { + if (event->sourceId == eventListenerFilters[i] || EVENT_SOURCE_ANY == eventListenerFilters[i]) + { eventListeners[i]->handleEvent(event); } } } - if (!rs485 || flush) { + if (!rs485 || flush) + { // Send to other micro controller. But only if there's room left in write buffer. Otherwise the program will be // blocked. The buffer gets full if the data is not fetched by the other controller for any reason. // @todo Possible optimization to check hwSerial->availableForWrite() >= 6 failed on Arduino for unknown reason. - if (crossLink != -1 /* && hwSerial->availableForWrite() >= 6 */) { - // = (byte) 255; - msg[1] = (byte) event->sourceId; + if (crossLink != -1 /* && hwSerial->availableForWrite() >= 6 */) + { + msg[0] = (byte) 255; + msg[1] = event->sourceId; msg[2] = highByte(event->eventId); msg[3] = lowByte(event->eventId); msg[4] = event->value; - // = (byte) 255; + msg[5] = (byte) 255; - for (int i = 0; i <= crossLink; i++) { - if (i != sender) { + for (int i = 0; i <= crossLink; i++) + { + if (i != sender) + { hwSerial[i]->write(msg, 6); } } } #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - if (multiCore && sender != -1) { + if (multiCore && sender != -1 && event->sourceId != EVENT_NULL) + { multiCoreCrossLink->pushEventNonBlocking(event); } #endif @@ -106,17 +129,23 @@ void EventDispatcher::callListeners(Event* event, int sender, bool flush) { delete event; } -void EventDispatcher::callListeners(ConfigEvent* event, int sender) { - for (byte i = 0; i <= numListeners; i++) { - if (event->sourceId == eventListenerFilters[i]) { +void EventDispatcher::callListeners(ConfigEvent *event, int sender) +{ + for (byte i = 0; i <= numListeners; i++) + { + if (EVENT_CONFIGURATION == eventListenerFilters[i] || EVENT_SOURCE_ANY == eventListenerFilters[i]) + { eventListeners[i]->handleEvent(event); } } - if (sender != -1) { - if (crossLink != -1 /* && hwSerial->availableForWrite() >= 6 */) { - // = (byte) 255; - cmsg[2] = (byte) event->boardId; + if (sender != -1) + { + if (crossLink != -1 /* && hwSerial->availableForWrite() >= 6 */) + { + cmsg[0] = (byte) 255; + cmsg[1] = event->sourceId; + cmsg[2] = event->boardId; cmsg[3] = event->topic; cmsg[4] = event->index; cmsg[5] = event->key; @@ -124,17 +153,20 @@ void EventDispatcher::callListeners(ConfigEvent* event, int sender) { cmsg[7] = (event->value >> 16) & 0xff; cmsg[8] = (event->value >> 8) & 0xff; cmsg[9] = event->value & 0xff; - // = (byte) 255; + cmsg[10] = (byte) 255; - for (int i = 0; i <= crossLink; i++) { - if (i != sender) { + for (int i = 0; i <= crossLink; i++) + { + if (i != sender) + { hwSerial[i]->write(cmsg, 11); } } } #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - if (multiCoreCrossLink) { + if (multiCoreCrossLink) + { multiCoreCrossLink->pushConfigEvent(event); } #endif @@ -144,25 +176,35 @@ void EventDispatcher::callListeners(ConfigEvent* event, int sender) { delete event; } -void EventDispatcher::update() { - if (!rs485) { - while (stackCounter >= 0) { +void EventDispatcher::update() +{ + if (!rs485) + { + while (stackCounter >= 0) + { Event *event = stackEvents[stackCounter--]; // Integer MAX_CROSS_LINKS is always higher than crossLinks, so this parameters means "no sender, send to all". callListeners(event, MAX_CROSS_LINKS, false); } } - for (int i = 0; i <= crossLink; i++) { - //Serial.println(hwSerial[i]->available()); - if (hwSerial[i]->available() >= 6) { - //digitalWrite(25, LOW); // Write. + for (int i = 0; i <= crossLink; i++) + { + if (hwSerial[i]->available() >= 6) + { + // digitalWrite(25, LOW); // Write. byte startByte = hwSerial[i]->read(); - if (startByte == 255) { + if (startByte == 255) + { byte sourceId = hwSerial[i]->read(); - if (sourceId != 0) { - if (sourceId == EVENT_CONFIGURATION) { - while (hwSerial[i]->available() < 9) {} + if (sourceId != 0) + { + if (sourceId == EVENT_CONFIGURATION) + { + // Config Event has 11 bytes, 2 bytes are already parsed above. + while (hwSerial[i]->available() < 9) + { + } // We have a ConfigEvent. byte boardId = hwSerial[i]->read(); @@ -170,29 +212,51 @@ void EventDispatcher::update() { byte index = hwSerial[i]->read(); byte key = hwSerial[i]->read(); int value = - (hwSerial[i]->read() << 24) + - (hwSerial[i]->read() << 16) + - (hwSerial[i]->read() << 8) + - hwSerial[i]->read(); - callListeners(new ConfigEvent(boardId, topic, index, key, value), i); - } - else { - if (sourceId == EVENT_POLL_EVENTS && rs485) { - digitalWrite(rs485Pin, HIGH); // Write. - while (stackCounter >= 0) { - Event *event = stackEvents[stackCounter--]; - // Integer MAX_CROSS_LINKS is always higher than crossLinks, so this parameters means "no sender, send to all". - callListeners(event, MAX_CROSS_LINKS, true); - } - digitalWrite(rs485Pin, LOW); // Read. + (hwSerial[i]->read() << 24) + + (hwSerial[i]->read() << 16) + + (hwSerial[i]->read() << 8) + + hwSerial[i]->read(); + byte stopByte = hwSerial[i]->read(); + if (stopByte == 255) + { + callListeners(new ConfigEvent(boardId, topic, index, key, value), i); } - + } + else + { word eventId = word(hwSerial[i]->read(), hwSerial[i]->read()); - if (eventId != 0) { + if (eventId != 0) + { byte value = hwSerial[i]->read(); byte stopByte = hwSerial[i]->read(); - if (stopByte == 255) { - callListeners(new Event((char) sourceId, eventId, value), i, false); + if (stopByte == 255) + { + if (sourceId == EVENT_POLL_EVENTS) + { + if (board == value) + { + if (rs485) + { + digitalWrite(rs485Pin, HIGH); // Write. + } + while (stackCounter >= 0) + { + Event *event = stackEvents[stackCounter--]; + // Integer MAX_CROSS_LINKS is always higher than crossLinks, so this parameters means "no sender, send to all". + callListeners(event, MAX_CROSS_LINKS, true); + } + // Send NULL event to indicate that transmission is complete. + callListeners(new Event(EVENT_NULL), MAX_CROSS_LINKS, true); + if (rs485) + { + digitalWrite(rs485Pin, LOW); // Read. + } + } + } + else + { + callListeners(new Event((char)sourceId, eventId, value), i, false); + } } } } @@ -202,21 +266,25 @@ void EventDispatcher::update() { } #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - if (multiCoreCrossLink) { - if (multiCoreCrossLink->eventAvailable()) { + if (multiCoreCrossLink) + { + if (multiCoreCrossLink->eventAvailable()) + { Event *event; - if (multiCoreCrossLink->popEventNonBlocking(event)) { + if (multiCoreCrossLink->popEventNonBlocking(event)) + { callListeners(event, -1, false); } } - if (multiCoreCrossLink->configEventAvailable()) { + if (multiCoreCrossLink->configEventAvailable()) + { ConfigEvent *configEvent; - if (multiCoreCrossLink->popConfigEventNonBlocking(configEvent)) { + if (multiCoreCrossLink->popConfigEventNonBlocking(configEvent)) + { callListeners(configEvent, -1); } } } #endif - } diff --git a/src/EventDispatcher/EventDispatcher.h b/src/EventDispatcher/EventDispatcher.h index 0a930c2..941b686 100644 --- a/src/EventDispatcher/EventDispatcher.h +++ b/src/EventDispatcher/EventDispatcher.h @@ -16,7 +16,7 @@ #include "EventListener.h" #ifndef MAX_EVENT_LISTENERS -#define MAX_EVENT_LISTENERS 5 +#define MAX_EVENT_LISTENERS 16 #endif #ifndef MAX_CROSS_LINKS @@ -33,6 +33,8 @@ class EventDispatcher { void setRS485ModePin(int pin); + void setBoard(byte b); + void setMultiCoreCrossLink(MultiCoreCrossLink* mccl); MultiCoreCrossLink* getMultiCoreCrossLink(); @@ -66,6 +68,8 @@ class EventDispatcher { bool rs485 = false; int rs485Pin = 0; + byte board = 255; + bool multiCore = false; int crossLink = -1; HardwareSerial* hwSerial[MAX_CROSS_LINKS]; diff --git a/src/EventDispatcher/MultiCoreCrossLink.h b/src/EventDispatcher/MultiCoreCrossLink.h index d86b87d..6b35670 100644 --- a/src/EventDispatcher/MultiCoreCrossLink.h +++ b/src/EventDispatcher/MultiCoreCrossLink.h @@ -8,7 +8,7 @@ #include "Event.h" #ifndef EVENT_STACK_SIZE -#define EVENT_STACK_SIZE 100 +#define EVENT_STACK_SIZE 128 #endif class MultiCoreCrossLink { diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index ce7d824..746d92c 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -3,6 +3,8 @@ IOBoardController::IOBoardController(int controllerType) { _eventDispatcher = new EventDispatcher(); _eventDispatcher->addListener(this, EVENT_CONFIGURATION); + _eventDispatcher->addListener(this, EVENT_PING); + _eventDispatcher->addListener(this, EVENT_RESET); if (controllerType == CONTROLLER_16_8_1) { // Turn on the LED @@ -12,22 +14,13 @@ IOBoardController::IOBoardController(int controllerType) { // Read bordID. The read value is between 60 and 940. boardId = 16 - ((int) ((analogRead(28) + 20) / 60)); - #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - Serial1.setTX(0); - Serial1.setRX(1); - Serial1.setFIFOSize(128); // @todo find the right size. - Serial1.begin(115200); _eventDispatcher->setRS485ModePin(2); _eventDispatcher->setCrossLinkSerial(Serial1); _multiCoreCrossLink = new MultiCoreCrossLink(); _eventDispatcher->setMultiCoreCrossLink(_multiCoreCrossLink); - #endif _pwmDevices = new PwmDevices(_eventDispatcher); _switches = new Switches(boardId, _eventDispatcher); - } else { - Serial.print("Unsupported Input Controller: "); - Serial.println(controllerType); } } @@ -40,7 +33,11 @@ void IOBoardController::update() { void IOBoardController::handleEvent(Event* event) { switch (event->sourceId) { case EVENT_PING: - _eventDispatcher->dispatch(new Event(EVENT_PONG, 0, boardId)); + _eventDispatcher->dispatch(new Event(EVENT_PONG, 1, boardId)); + break; + + case EVENT_RESET: + // @todo clear all configurations or reboot the device. break; } } diff --git a/test/HW_16_8_1/src/main.cpp b/test/HW_16_8_1/src/main.cpp index 53c5ef7..bbffd8a 100644 --- a/test/HW_16_8_1/src/main.cpp +++ b/test/HW_16_8_1/src/main.cpp @@ -4,6 +4,7 @@ #include "IOBoardController.h" #include "EffectsController.h" +#include "EventDispatcher/CrossLinkDebugger.h" IOBoardController ioBoardController(CONTROLLER_16_8_1); // Platform will be adjusted by ConfigEvent. @@ -15,21 +16,40 @@ EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_LIBPINMAME); // same MultiCoreCrosslink to send and receive events between // both cores. -void setup() { - //ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); +void setup() +{ + Serial.begin(115200); + // The Pico implements USB itself so special care must be taken. Use while(!Serial){} in the setup() code before printing anything so that it waits for the USB connection to be established. + // https://community.platformio.org/t/serial-monitor-not-working/1512/25 + while (!Serial) + { + } + + Serial1.setTX(0); + Serial1.setRX(1); + Serial1.setFIFOSize(128); // @todo find the right size. + Serial1.begin(115200); + // The Pico implements USB itself so special care must be taken. Use while(!Serial){} in the setup() code before printing anything so that it waits for the USB connection to be established. + // https://community.platformio.org/t/serial-monitor-not-working/1512/25 + while (!Serial1) + { + } + + ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); } -void setup1() { +void setup1() +{ effectsController.eventDispatcher()->setMultiCoreCrossLink( - ioBoardController.eventDispatcher()->getMultiCoreCrossLink() - ); + ioBoardController.eventDispatcher()->getMultiCoreCrossLink()); } -void loop() { +void loop() +{ ioBoardController.update(); - //Serial.println(16 - ((int) (analogRead(28) + 20) / 60)); } -void loop1() { +void loop1() +{ effectsController.update(); } From 62f25ba16a7f5fb583e81dcf24f0630a26a3654b Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 4 Sep 2023 15:20:58 +0200 Subject: [PATCH 009/102] fixed RS485 event polling --- src/EventDispatcher/EventDispatcher.cpp | 2 ++ src/IOBoardController.cpp | 1 + 2 files changed, 3 insertions(+) diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index b5ce273..eba2882 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -238,6 +238,7 @@ void EventDispatcher::update() if (rs485) { digitalWrite(rs485Pin, HIGH); // Write. + delayMicroseconds(500); } while (stackCounter >= 0) { @@ -249,6 +250,7 @@ void EventDispatcher::update() callListeners(new Event(EVENT_NULL), MAX_CROSS_LINKS, true); if (rs485) { + delayMicroseconds(500); digitalWrite(rs485Pin, LOW); // Read. } } diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 746d92c..f22fb57 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -15,6 +15,7 @@ IOBoardController::IOBoardController(int controllerType) { boardId = 16 - ((int) ((analogRead(28) + 20) / 60)); _eventDispatcher->setRS485ModePin(2); + _eventDispatcher->setBoard(boardId); _eventDispatcher->setCrossLinkSerial(Serial1); _multiCoreCrossLink = new MultiCoreCrossLink(); _eventDispatcher->setMultiCoreCrossLink(_multiCoreCrossLink); From 9891819e939366235f83ba140db1ec9a247c5cf3 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 6 Sep 2023 18:05:58 +0200 Subject: [PATCH 010/102] improved RS485 communication --- src/EventDispatcher/Event.h | 5 +- src/EventDispatcher/EventDispatcher.cpp | 94 +++++++++++++------ src/EventDispatcher/EventDispatcher.h | 3 +- src/IODevices/Switches.cpp | 10 +- src/IODevices/Switches.h | 4 +- test/{HW_16_8_1 => IO_16_8_1}/platformio.ini | 0 test/IO_16_8_1/src/main.cpp | 45 +++++++++ test/{HW_16_8_1 => IO_16_8_1}/test/README | 0 test/IO_16_8_1_USB_DEBUG/platformio.ini | 14 +++ .../src/main.cpp | 5 +- test/IO_16_8_1_USB_DEBUG/test/README | 11 +++ 11 files changed, 149 insertions(+), 42 deletions(-) rename test/{HW_16_8_1 => IO_16_8_1}/platformio.ini (100%) create mode 100644 test/IO_16_8_1/src/main.cpp rename test/{HW_16_8_1 => IO_16_8_1}/test/README (100%) create mode 100644 test/IO_16_8_1_USB_DEBUG/platformio.ini rename test/{HW_16_8_1 => IO_16_8_1_USB_DEBUG}/src/main.cpp (94%) create mode 100644 test/IO_16_8_1_USB_DEBUG/test/README diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 7c76ca9..6250bb3 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -51,6 +51,7 @@ #define CONFIG_TOPIC_ACTIVE_LOW 86 // "V" #define CONFIG_TOPIC_POWER 87 // "W" #define CONFIG_TOPIC_TYPE 89 // "Y" +#define CONFIG_TOPIC_NULL 99 // NULL #define PWM_TYPE_SOLENOID 1 // Coil #define PWM_TYPE_FLASHER 2 // Flasher @@ -84,14 +85,14 @@ struct Event { localFast = false; } - Event(char sId, word eId, byte v) { + Event(byte sId, word eId, byte v) { sourceId = sId; eventId = eId; value = v; localFast = false; } - Event(char sId, word eId, byte v, bool lf) { + Event(byte sId, word eId, byte v, bool lf) { sourceId = sId; eventId = eId; value = v; diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index eba2882..b4d86e8 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -40,6 +40,9 @@ void EventDispatcher::addCrossLinkSerial(HardwareSerial &reference) { hwSerial[++crossLink] = (HardwareSerial *)&reference; hwSerial[crossLink]->begin(115200); + while (!hwSerial[crossLink]) + { + } } void EventDispatcher::addListener(EventListener *eventListener) @@ -101,18 +104,19 @@ void EventDispatcher::callListeners(Event *event, int sender, bool flush) if (crossLink != -1 /* && hwSerial->availableForWrite() >= 6 */) { - msg[0] = (byte) 255; + msg[0] = 0b11111111; msg[1] = event->sourceId; msg[2] = highByte(event->eventId); msg[3] = lowByte(event->eventId); msg[4] = event->value; - msg[5] = (byte) 255; + msg[5] = 0b10101010; + msg[6] = 0b01010101; for (int i = 0; i <= crossLink; i++) { if (i != sender) { - hwSerial[i]->write(msg, 6); + hwSerial[i]->write(msg, 7); } } } @@ -143,23 +147,24 @@ void EventDispatcher::callListeners(ConfigEvent *event, int sender) { if (crossLink != -1 /* && hwSerial->availableForWrite() >= 6 */) { - cmsg[0] = (byte) 255; - cmsg[1] = event->sourceId; - cmsg[2] = event->boardId; - cmsg[3] = event->topic; - cmsg[4] = event->index; - cmsg[5] = event->key; - cmsg[6] = event->value >> 24; - cmsg[7] = (event->value >> 16) & 0xff; - cmsg[8] = (event->value >> 8) & 0xff; - cmsg[9] = event->value & 0xff; - cmsg[10] = (byte) 255; + msg[0] = 0b11111111; + msg[1] = event->sourceId; + msg[2] = event->boardId; + msg[3] = event->topic; + msg[4] = event->index; + msg[5] = event->key; + msg[6] = event->value >> 24; + msg[7] = (event->value >> 16) & 0xff; + msg[8] = (event->value >> 8) & 0xff; + msg[9] = event->value & 0xff; + msg[10] = 0b10101010; + msg[11] = 0b01010101; for (int i = 0; i <= crossLink; i++) { if (i != sender) { - hwSerial[i]->write(cmsg, 11); + hwSerial[i]->write(msg, 12); } } } @@ -182,6 +187,7 @@ void EventDispatcher::update() { while (stackCounter >= 0) { + // stackCounter will reach -1 here, which means empty stack. Event *event = stackEvents[stackCounter--]; // Integer MAX_CROSS_LINKS is always higher than crossLinks, so this parameters means "no sender, send to all". callListeners(event, MAX_CROSS_LINKS, false); @@ -190,9 +196,10 @@ void EventDispatcher::update() for (int i = 0; i <= crossLink; i++) { - if (hwSerial[i]->available() >= 6) + if (hwSerial[i]->available() >= 7) { - // digitalWrite(25, LOW); // Write. + bool success = false; + byte startByte = hwSerial[i]->read(); if (startByte == 255) { @@ -201,8 +208,8 @@ void EventDispatcher::update() { if (sourceId == EVENT_CONFIGURATION) { - // Config Event has 11 bytes, 2 bytes are already parsed above. - while (hwSerial[i]->available() < 9) + // Config Event has 12 bytes, 2 bytes are already parsed above. + while (hwSerial[i]->available() < 10) { } @@ -217,9 +224,14 @@ void EventDispatcher::update() (hwSerial[i]->read() << 8) + hwSerial[i]->read(); byte stopByte = hwSerial[i]->read(); - if (stopByte == 255) + if (stopByte == 0b10101010) { - callListeners(new ConfigEvent(boardId, topic, index, key, value), i); + stopByte = hwSerial[i]->read(); + if (stopByte == 0b01010101) + { + success = true; + callListeners(new ConfigEvent(boardId, topic, index, key, value), i); + } } } else @@ -229,19 +241,25 @@ void EventDispatcher::update() { byte value = hwSerial[i]->read(); byte stopByte = hwSerial[i]->read(); - if (stopByte == 255) + if (stopByte == 0b10101010) { - if (sourceId == EVENT_POLL_EVENTS) + stopByte = hwSerial[i]->read(); + if (stopByte == 0b01010101) { - if (board == value) + success = true; + callListeners(new Event((char)sourceId, eventId, value), i, false); + + if (sourceId == EVENT_POLL_EVENTS && board == value) { if (rs485) { digitalWrite(rs485Pin, HIGH); // Write. + // Wait until the RS485 converter switched to write mode. delayMicroseconds(500); } while (stackCounter >= 0) { + // stackCounter will reach -1 here, which means empty stack. Event *event = stackEvents[stackCounter--]; // Integer MAX_CROSS_LINKS is always higher than crossLinks, so this parameters means "no sender, send to all". callListeners(event, MAX_CROSS_LINKS, true); @@ -250,19 +268,37 @@ void EventDispatcher::update() callListeners(new Event(EVENT_NULL), MAX_CROSS_LINKS, true); if (rs485) { - delayMicroseconds(500); + // Wait until the RS485 converter switched back to read mode. + delayMicroseconds(1000); digitalWrite(rs485Pin, LOW); // Read. } } } - else - { - callListeners(new Event((char)sourceId, eventId, value), i, false); - } } } } } + else { + // We didn't receive a start byte. Fake "success" to start over with the next byte. + success = true; + } + } + + if (!success) + { + while (hwSerial[i]->available()) + { + byte bits = hwSerial[i]->read(); + if (bits == 0b10101010 && hwSerial[i]->available()) + { + bits = hwSerial[i]->read(); + if (bits == 0b01010101) + { + // Now we should be back in sync. + break; + } + } + } } } } diff --git a/src/EventDispatcher/EventDispatcher.h b/src/EventDispatcher/EventDispatcher.h index 941b686..aa96683 100644 --- a/src/EventDispatcher/EventDispatcher.h +++ b/src/EventDispatcher/EventDispatcher.h @@ -63,8 +63,7 @@ class EventDispatcher { char eventListenerFilters[MAX_EVENT_LISTENERS]; int numListeners = -1; - byte msg[6] = {0}; - byte cmsg[11] = {0}; + byte msg[12]; bool rs485 = false; int rs485Pin = 0; diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index 658a6a2..8005c96 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -1,12 +1,12 @@ #include "Switches.h" void Switches::registerSwitch(byte p, byte n) { - if (last < MAX_SWITCHES) { - port[last] = p; - number[last] = n; - + if (last < (MAX_SWITCHES - 1)) { pinMode(p, INPUT); - state[last++] = digitalRead(p); + port[++last] = p; + number[last] = n; + toggled[last] = false; + state[last] = digitalRead(p); } } diff --git a/src/IODevices/Switches.h b/src/IODevices/Switches.h index 37a2035..7bdd2f7 100644 --- a/src/IODevices/Switches.h +++ b/src/IODevices/Switches.h @@ -25,7 +25,7 @@ class Switches : public EventListener { public: Switches(byte bId, EventDispatcher* eD) { boardId = bId; - + _ms = millis(); _eventDispatcher = eD; _eventDispatcher->addListener(this, EVENT_POLL_EVENTS); _eventDispatcher->addListener(this, EVENT_READ_SWITCHES); @@ -47,7 +47,7 @@ class Switches : public EventListener { byte number[MAX_SWITCHES] = {0}; bool state[MAX_SWITCHES] = {0}; bool toggled[MAX_SWITCHES] = {0}; - byte last = 0; + int last = -1; EventDispatcher* _eventDispatcher; }; diff --git a/test/HW_16_8_1/platformio.ini b/test/IO_16_8_1/platformio.ini similarity index 100% rename from test/HW_16_8_1/platformio.ini rename to test/IO_16_8_1/platformio.ini diff --git a/test/IO_16_8_1/src/main.cpp b/test/IO_16_8_1/src/main.cpp new file mode 100644 index 0000000..fdefd49 --- /dev/null +++ b/test/IO_16_8_1/src/main.cpp @@ -0,0 +1,45 @@ +// Markus Kalkbrenner 2023 + +#include + +#include "IOBoardController.h" +#include "EffectsController.h" + +IOBoardController ioBoardController(CONTROLLER_16_8_1); +// Platform will be adjusted by ConfigEvent. +EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_LIBPINMAME); + +// Each controller will be bound to its own core and has it's own +// EventDispatcher. Only the EventDispatcher of IOBoardController +// is attached to RS485. But both EventDispatchers must share the +// same MultiCoreCrosslink to send and receive events between +// both cores. + +void setup() +{ + Serial1.setTX(0); + Serial1.setRX(1); + Serial1.setFIFOSize(128); // @todo find the right size. + Serial1.begin(115200); + // The Pico implements USB itself so special care must be taken. Use while(!Serial){} in the setup() code before printing anything so that it waits for the USB connection to be established. + // https://community.platformio.org/t/serial-monitor-not-working/1512/25 + while (!Serial1) + { + } +} + +void setup1() +{ + effectsController.eventDispatcher()->setMultiCoreCrossLink( + ioBoardController.eventDispatcher()->getMultiCoreCrossLink()); +} + +void loop() +{ + ioBoardController.update(); +} + +void loop1() +{ + effectsController.update(); +} diff --git a/test/HW_16_8_1/test/README b/test/IO_16_8_1/test/README similarity index 100% rename from test/HW_16_8_1/test/README rename to test/IO_16_8_1/test/README diff --git a/test/IO_16_8_1_USB_DEBUG/platformio.ini b/test/IO_16_8_1_USB_DEBUG/platformio.ini new file mode 100644 index 0000000..4035b4d --- /dev/null +++ b/test/IO_16_8_1_USB_DEBUG/platformio.ini @@ -0,0 +1,14 @@ +[env:pico] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +board = pico +framework = arduino +board_build.core = earlephilhower +board_build.filesystem_size = 0.5m +build_flags = + -D PICO_STDIO_USB ; enable stdio over USB +lib_extra_dirs = + ../.. +lib_deps = + mkalkbrenner/WavePWM + kitesurfer1404/WS2812FX + Bounce2 diff --git a/test/HW_16_8_1/src/main.cpp b/test/IO_16_8_1_USB_DEBUG/src/main.cpp similarity index 94% rename from test/HW_16_8_1/src/main.cpp rename to test/IO_16_8_1_USB_DEBUG/src/main.cpp index bbffd8a..4992e20 100644 --- a/test/HW_16_8_1/src/main.cpp +++ b/test/IO_16_8_1_USB_DEBUG/src/main.cpp @@ -24,6 +24,9 @@ void setup() while (!Serial) { } + Serial.print("PPUC IO_16_8_1 board #"); + Serial.println(16 - ((int) ((analogRead(28) + 20) / 60))); + ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); Serial1.setTX(0); Serial1.setRX(1); @@ -34,8 +37,6 @@ void setup() while (!Serial1) { } - - ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); } void setup1() diff --git a/test/IO_16_8_1_USB_DEBUG/test/README b/test/IO_16_8_1_USB_DEBUG/test/README new file mode 100644 index 0000000..b94d089 --- /dev/null +++ b/test/IO_16_8_1_USB_DEBUG/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html From f53e945720b9701022012667b539738b07acf345 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 6 Sep 2023 18:49:06 +0200 Subject: [PATCH 011/102] improved address detection --- .github/workflows/ci.yml | 2 +- src/EffectsController.h | 2 +- src/IOBoardController.cpp | 2 +- test/IOBoardController/src/main.cpp | 2 +- test/IO_16_8_1_USB_DEBUG/src/main.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de3b905..d7dc656 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - controller: ['EffectController', 'EffectControllerPico', 'InputController', 'IOBoardController', 'NanoController'] + controller: ['EffectController', 'EffectControllerPico', 'InputController', 'IO_16_8_1', 'NanoController'] name: PPUC ${{ matrix.controller }} diff --git a/src/EffectsController.h b/src/EffectsController.h index 603de12..4387210 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -290,7 +290,7 @@ class EffectsController : public EventListener { } else if (controllerType == CONTROLLER_16_8_1) { // Read bordID. The read value is between 60 and 940. - boardId = 16 - ((int) ((analogRead(28) + 20) / 60)); + boardId = 16 - ((int) ((analogRead(28) + 30) / 60)); } else { Serial.print("Unsupported Effects Controller: "); Serial.println(controllerType); diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index f22fb57..83edca8 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -12,7 +12,7 @@ IOBoardController::IOBoardController(int controllerType) { digitalWrite(25, HIGH); // Read bordID. The read value is between 60 and 940. - boardId = 16 - ((int) ((analogRead(28) + 20) / 60)); + boardId = 16 - ((int) ((analogRead(28) + 30) / 60)); _eventDispatcher->setRS485ModePin(2); _eventDispatcher->setBoard(boardId); diff --git a/test/IOBoardController/src/main.cpp b/test/IOBoardController/src/main.cpp index 81e1fb5..c7d2b45 100644 --- a/test/IOBoardController/src/main.cpp +++ b/test/IOBoardController/src/main.cpp @@ -17,7 +17,7 @@ void setup1() { void loop() { ioBoardController.update(); - //Serial.println(16 - ((int) (analogRead(28) + 20) / 60)); + //Serial.println(16 - ((int) (analogRead(28) + 30) / 60)); } void loop1() { diff --git a/test/IO_16_8_1_USB_DEBUG/src/main.cpp b/test/IO_16_8_1_USB_DEBUG/src/main.cpp index 4992e20..3413f35 100644 --- a/test/IO_16_8_1_USB_DEBUG/src/main.cpp +++ b/test/IO_16_8_1_USB_DEBUG/src/main.cpp @@ -25,7 +25,7 @@ void setup() { } Serial.print("PPUC IO_16_8_1 board #"); - Serial.println(16 - ((int) ((analogRead(28) + 20) / 60))); + Serial.println(16 - ((int) ((analogRead(28) + 30) / 60))); ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); Serial1.setTX(0); From 6f3aeed27d4f7cc26c211326a4e3404d02d43003 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 6 Sep 2023 19:05:58 +0200 Subject: [PATCH 012/102] let LED flash --- src/IOBoardController.cpp | 10 +++++++++- src/IOBoardController.h | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 83edca8..75efa3b 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -1,11 +1,13 @@ #include "IOBoardController.h" -IOBoardController::IOBoardController(int controllerType) { +IOBoardController::IOBoardController(int cT) { _eventDispatcher = new EventDispatcher(); _eventDispatcher->addListener(this, EVENT_CONFIGURATION); _eventDispatcher->addListener(this, EVENT_PING); _eventDispatcher->addListener(this, EVENT_RESET); + controllerType = cT; + if (controllerType == CONTROLLER_16_8_1) { // Turn on the LED pinMode(25, OUTPUT); @@ -26,6 +28,12 @@ IOBoardController::IOBoardController(int controllerType) { } void IOBoardController::update() { + if (controllerType == CONTROLLER_16_8_1 && (millis() - ledMillis > 500)) { + ledState = !ledState; + digitalWrite(25, ledState); + ledMillis = millis(); + } + switches()->update(); pwmDevices()->update(); eventDispatcher()->update(); diff --git a/src/IOBoardController.h b/src/IOBoardController.h index 10f88c3..1de61ef 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -42,6 +42,7 @@ class IOBoardController : public EventListener { PwmDevices* _pwmDevices; Switches* _switches; + int controllerType; byte boardId; byte port = 0; byte number = 0; @@ -52,6 +53,9 @@ class IOBoardController : public EventListener { byte holdPowerActivationTime = 0; byte fastSwitch = 0; + long ledMillis = 0; + bool ledState = HIGH; + EventDispatcher* _eventDispatcher; #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) MultiCoreCrossLink* _multiCoreCrossLink; From d59e114651cddebe2039d8dac7541666e7fddfee Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 6 Sep 2023 21:59:22 +0200 Subject: [PATCH 013/102] use FIFO instead of LIFO for stacked Events --- src/EffectsController.h | 4 +++ src/EventDispatcher/Event.h | 2 ++ src/EventDispatcher/EventDispatcher.cpp | 38 ++++++++++++++++------- src/EventDispatcher/EventDispatcher.h | 3 +- src/IOBoardController.cpp | 10 ------ src/IOBoardController.h | 3 -- test/IO_16_8_1_USB_DEBUG/src/main.cpp | 41 +++++++++++++++++++++++++ 7 files changed, 76 insertions(+), 25 deletions(-) diff --git a/src/EffectsController.h b/src/EffectsController.h index 4387210..a222d17 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -31,6 +31,7 @@ #include "EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h" #include "EffectDevices/RgbStripDevice.h" #include "Effects/LedBlinkEffect.h" +#include "Effects/LedOnEffect.h" #include "Effects/NullEffect.h" #include "Effects/RGBColorCycleEffect.h" #include "Effects/WS2812FXEffect.h" @@ -291,6 +292,9 @@ class EffectsController : public EventListener { else if (controllerType == CONTROLLER_16_8_1) { // Read bordID. The read value is between 60 and 940. boardId = 16 - ((int) ((analogRead(28) + 30) / 60)); + + _ledBuiltInDevice = new LedBuiltInDevice(); + _ledBuiltInDevice->on(); } else { Serial.print("Unsupported Effects Controller: "); Serial.println(controllerType); diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 6250bb3..46fb4c3 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -25,6 +25,8 @@ #define EVENT_PING 88 // "X" #define EVENT_PONG 89 // "Y" #define EVENT_RESET 90 // "Z" +#define EVENT_NO_ERROR 98 // NO ERROR +#define EVENT_ERROR 99 // ERROR #define CONFIG_TOPIC_PLATFORM 102 // "f" #define CONFIG_TOPIC_LED_STRING 103 // "g" diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index b4d86e8..c10674d 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -185,13 +185,14 @@ void EventDispatcher::update() { if (!rs485) { - while (stackCounter >= 0) + for (int i = 0; i <= stackCounter; i++) { - // stackCounter will reach -1 here, which means empty stack. - Event *event = stackEvents[stackCounter--]; + Event *event = stackEvents[i]; // Integer MAX_CROSS_LINKS is always higher than crossLinks, so this parameters means "no sender, send to all". callListeners(event, MAX_CROSS_LINKS, false); } + // -1 means empty. + stackCounter = -1; } for (int i = 0; i <= crossLink; i++) @@ -257,13 +258,16 @@ void EventDispatcher::update() // Wait until the RS485 converter switched to write mode. delayMicroseconds(500); } - while (stackCounter >= 0) + + for (int k = 0; k <= stackCounter; k++) { - // stackCounter will reach -1 here, which means empty stack. - Event *event = stackEvents[stackCounter--]; + Event *event = stackEvents[k]; // Integer MAX_CROSS_LINKS is always higher than crossLinks, so this parameters means "no sender, send to all". callListeners(event, MAX_CROSS_LINKS, true); } + // -1 means empty. + stackCounter = -1; + // Send NULL event to indicate that transmission is complete. callListeners(new Event(EVENT_NULL), MAX_CROSS_LINKS, true); if (rs485) @@ -278,14 +282,26 @@ void EventDispatcher::update() } } } - else { - // We didn't receive a start byte. Fake "success" to start over with the next byte. - success = true; - } + } + else + { + // We didn't receive a start byte. Fake "success" to start over with the next byte. + success = true; } - if (!success) + if (success) { + if (error) + { + error = false; + dispatch(new Event(EVENT_NO_ERROR, 1, board)); + } + } + else + { + error = true; + dispatch(new Event(EVENT_ERROR, 1, board)); + while (hwSerial[i]->available()) { byte bits = hwSerial[i]->read(); diff --git a/src/EventDispatcher/EventDispatcher.h b/src/EventDispatcher/EventDispatcher.h index aa96683..068e1a8 100644 --- a/src/EventDispatcher/EventDispatcher.h +++ b/src/EventDispatcher/EventDispatcher.h @@ -16,7 +16,7 @@ #include "EventListener.h" #ifndef MAX_EVENT_LISTENERS -#define MAX_EVENT_LISTENERS 16 +#define MAX_EVENT_LISTENERS 32 #endif #ifndef MAX_CROSS_LINKS @@ -68,6 +68,7 @@ class EventDispatcher { bool rs485 = false; int rs485Pin = 0; byte board = 255; + bool error = false; bool multiCore = false; int crossLink = -1; diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 75efa3b..4691a37 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -9,10 +9,6 @@ IOBoardController::IOBoardController(int cT) { controllerType = cT; if (controllerType == CONTROLLER_16_8_1) { - // Turn on the LED - pinMode(25, OUTPUT); - digitalWrite(25, HIGH); - // Read bordID. The read value is between 60 and 940. boardId = 16 - ((int) ((analogRead(28) + 30) / 60)); @@ -28,12 +24,6 @@ IOBoardController::IOBoardController(int cT) { } void IOBoardController::update() { - if (controllerType == CONTROLLER_16_8_1 && (millis() - ledMillis > 500)) { - ledState = !ledState; - digitalWrite(25, ledState); - ledMillis = millis(); - } - switches()->update(); pwmDevices()->update(); eventDispatcher()->update(); diff --git a/src/IOBoardController.h b/src/IOBoardController.h index 1de61ef..8d45fc4 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -53,9 +53,6 @@ class IOBoardController : public EventListener { byte holdPowerActivationTime = 0; byte fastSwitch = 0; - long ledMillis = 0; - bool ledState = HIGH; - EventDispatcher* _eventDispatcher; #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) MultiCoreCrossLink* _multiCoreCrossLink; diff --git a/test/IO_16_8_1_USB_DEBUG/src/main.cpp b/test/IO_16_8_1_USB_DEBUG/src/main.cpp index 3413f35..441be90 100644 --- a/test/IO_16_8_1_USB_DEBUG/src/main.cpp +++ b/test/IO_16_8_1_USB_DEBUG/src/main.cpp @@ -43,6 +43,47 @@ void setup1() { effectsController.eventDispatcher()->setMultiCoreCrossLink( ioBoardController.eventDispatcher()->getMultiCoreCrossLink()); + + effectsController.ledBuiltInDevice()->off(); + + effectsController.addEffect( + new LedOnEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_SOURCE_LIGHT, 88, 1), + 1, // priority + 0, // repeat, -1 means endless + 0 // mode + ); + + effectsController.addEffect( + new NullEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_SOURCE_LIGHT, 88, 0), + 1, // priority + 0, // repeat, -1 means endless + 0 // mode + ); + + effectsController.addEffect( + new LedBlinkEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_ERROR, 1, /* board ID */ 0), + 2, // priority + -1, // repeat, -1 means endless + 0 // mode + ); + + // Controller start + effectsController.addEffect( + new NullEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_NO_ERROR, 1, /* board ID */ 0), + 3, // priority + 0, // repeat + 0 // mode + ); + + effectsController.start(); } void loop() From 837368abb6d3e9d7dc976ce33403d2722fd65763 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 6 Sep 2023 22:21:32 +0200 Subject: [PATCH 014/102] added missing LedOnEffect --- src/Effects/LedOnEffect.cpp | 6 ++++++ src/Effects/LedOnEffect.h | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/Effects/LedOnEffect.cpp create mode 100644 src/Effects/LedOnEffect.h diff --git a/src/Effects/LedOnEffect.cpp b/src/Effects/LedOnEffect.cpp new file mode 100644 index 0000000..35cdc0b --- /dev/null +++ b/src/Effects/LedOnEffect.cpp @@ -0,0 +1,6 @@ +#include "LedOnEffect.h" + +void LedOnEffect::update() { + device->on(); + stop(); +} diff --git a/src/Effects/LedOnEffect.h b/src/Effects/LedOnEffect.h new file mode 100644 index 0000000..7527334 --- /dev/null +++ b/src/Effects/LedOnEffect.h @@ -0,0 +1,21 @@ +/* + LedOnEffect.h + Created by Markus Kalkbrenner, 2023. + + Play more pinball! +*/ + +#ifndef LedOnEffect_h +#define LedOnEffect_h + +#include + +#include "Effect.h" + +class LedOnEffect : public Effect { +public: + void update(); + +}; + +#endif From 024e91ae73d300f631c3c06c71b1d0d5fc6e280a Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Fri, 8 Sep 2023 17:21:49 +0200 Subject: [PATCH 015/102] working prototype of event dispatching between cores --- src/EffectsController.cpp | 2 +- src/EventDispatcher/CrossLinkDebugger.cpp | 51 +++++++++-- src/EventDispatcher/CrossLinkDebugger.h | 11 ++- src/EventDispatcher/Event.h | 4 +- src/EventDispatcher/EventDispatcher.cpp | 26 +++--- src/EventDispatcher/MultiCoreCrossLink.h | 103 +++++++++++++--------- src/PPUC.h | 2 +- test/IO_16_8_1/platformio.ini | 17 ++++ test/IO_16_8_1/src/main.cpp | 62 +++++++++++++ test/IO_16_8_1_USB_DEBUG/platformio.ini | 14 --- test/IO_16_8_1_USB_DEBUG/src/main.cpp | 97 -------------------- test/IO_16_8_1_USB_DEBUG/test/README | 11 --- 12 files changed, 208 insertions(+), 192 deletions(-) delete mode 100644 test/IO_16_8_1_USB_DEBUG/platformio.ini delete mode 100644 test/IO_16_8_1_USB_DEBUG/src/main.cpp delete mode 100644 test/IO_16_8_1_USB_DEBUG/test/README diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 342b130..f46e0b9 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -376,7 +376,7 @@ void EffectsController::start() { if (ws2812FXbrightness[i] == 0) { - setBrightness(i + 1, WS2812FX_BRIGHTNESS); + //setBrightness(i + 1, WS2812FX_BRIGHTNESS); } } diff --git a/src/EventDispatcher/CrossLinkDebugger.cpp b/src/EventDispatcher/CrossLinkDebugger.cpp index 74ccad2..ec68931 100644 --- a/src/EventDispatcher/CrossLinkDebugger.cpp +++ b/src/EventDispatcher/CrossLinkDebugger.cpp @@ -1,20 +1,60 @@ #include "CrossLinkDebugger.h" -CrossLinkDebugger::CrossLinkDebugger() { - Serial.println("PPUC CrossLinkDebugger"); - Serial.println("----------------------"); +// https://stackoverflow.com/questions/20310000/error-iso-c-forbids-in-class-initialization-of-non-const-static-member +bool CrossLinkDebugger::lock = true; + +CrossLinkDebugger::CrossLinkDebugger() +{ +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) + if (get_core_num() == 0) + { + Serial.println("PPUC IO_16_8_1"); + Serial.print("PPUC board #"); + Serial.println(16 - ((int)((analogRead(28) + 30) / 60))); +#endif + Serial.println("PPUC CrossLinkDebugger"); + Serial.println("----------------------"); +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) + } + else + { + delayMicroseconds(500); + } +#endif + lock = false; } -void CrossLinkDebugger::handleEvent(Event* event) { +void CrossLinkDebugger::handleEvent(Event *event) +{ + while (lock) + { + } + lock = true; +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) + Serial.print("Core "); + Serial.print(get_core_num(), DEC); + Serial.print(" "); +#endif Serial.print("handleEvent: sourceId "); Serial.print(event->sourceId); Serial.print(", eventId "); Serial.print(event->eventId, DEC); Serial.print(", value "); Serial.println(event->value, DEC); + lock = false; } -void CrossLinkDebugger::handleEvent(ConfigEvent* event) { +void CrossLinkDebugger::handleEvent(ConfigEvent *event) +{ + while (lock) + { + } + lock = true; +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) + Serial.print("Core "); + Serial.print(get_core_num(), DEC); + Serial.print(" "); +#endif Serial.print("handleConfigEvent: boardId "); Serial.print(event->boardId, DEC); Serial.print(", topic "); @@ -25,4 +65,5 @@ void CrossLinkDebugger::handleEvent(ConfigEvent* event) { Serial.print(event->key, DEC); Serial.print(", value(HEX) "); Serial.println(event->value, HEX); + lock = false; } diff --git a/src/EventDispatcher/CrossLinkDebugger.h b/src/EventDispatcher/CrossLinkDebugger.h index 664f4ad..3b59de7 100644 --- a/src/EventDispatcher/CrossLinkDebugger.h +++ b/src/EventDispatcher/CrossLinkDebugger.h @@ -13,13 +13,16 @@ #include "Event.h" #include "EventListener.h" -class CrossLinkDebugger : public EventListener { +class CrossLinkDebugger : public EventListener +{ public: - CrossLinkDebugger(); + CrossLinkDebugger(); - void handleEvent(Event* event); - void handleEvent(ConfigEvent* event); + void handleEvent(Event *event); + void handleEvent(ConfigEvent *event); +private: + static bool lock; }; #endif diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 46fb4c3..cc1664c 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -121,7 +121,7 @@ struct Event { }; struct ConfigEvent { - byte sourceId; // EVENT_CONFIGURATION + byte sourceId = EVENT_CONFIGURATION; byte boardId; // byte topic; // lamps byte index; // 0, index of assignment @@ -129,7 +129,6 @@ struct ConfigEvent { int value; // FFFF00FF ConfigEvent(char b, char t, char i, char k, int v) { - sourceId = EVENT_CONFIGURATION; boardId = b; topic = t; index = i; @@ -139,7 +138,6 @@ struct ConfigEvent { // Clone the event. ConfigEvent(const ConfigEvent* other) { - sourceId = other->sourceId; boardId = other->boardId; topic = other->topic; index = other->index; diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index c10674d..90f6d4f 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -120,14 +120,14 @@ void EventDispatcher::callListeners(Event *event, int sender, bool flush) } } } + } #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - if (multiCore && sender != -1 && event->sourceId != EVENT_NULL) - { - multiCoreCrossLink->pushEventNonBlocking(event); - } -#endif + if (multiCore && sender != -1 && event->sourceId != EVENT_NULL) + { + multiCoreCrossLink->pushEvent(event); } +#endif // delete the event and free the memory delete event; @@ -170,7 +170,7 @@ void EventDispatcher::callListeners(ConfigEvent *event, int sender) } #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - if (multiCoreCrossLink) + if (multiCoreCrossLink && event->boardId == board) { multiCoreCrossLink->pushConfigEvent(event); } @@ -324,20 +324,14 @@ void EventDispatcher::update() { if (multiCoreCrossLink->eventAvailable()) { - Event *event; - if (multiCoreCrossLink->popEventNonBlocking(event)) - { - callListeners(event, -1, false); - } + Event *event = multiCoreCrossLink->popEvent(); + callListeners(event, -1, false); } if (multiCoreCrossLink->configEventAvailable()) { - ConfigEvent *configEvent; - if (multiCoreCrossLink->popConfigEventNonBlocking(configEvent)) - { - callListeners(configEvent, -1); - } + ConfigEvent *configEvent = multiCoreCrossLink->popConfigEvent(); + callListeners(configEvent, -1); } } #endif diff --git a/src/EventDispatcher/MultiCoreCrossLink.h b/src/EventDispatcher/MultiCoreCrossLink.h index 6b35670..d5c8ce7 100644 --- a/src/EventDispatcher/MultiCoreCrossLink.h +++ b/src/EventDispatcher/MultiCoreCrossLink.h @@ -5,72 +5,95 @@ #include #endif +#include #include "Event.h" #ifndef EVENT_STACK_SIZE #define EVENT_STACK_SIZE 128 #endif -class MultiCoreCrossLink { +typedef struct QueuedEvent +{ + byte sourceId; + word eventId; + byte value; + bool localFast; +} EventItem; + +typedef struct QueuedConfigEvent +{ + byte boardId; + byte topic; + byte index; + byte key; + int value; +} ConfigEventItem; + +class MultiCoreCrossLink +{ #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) public: - MultiCoreCrossLink() { - queue_init(&_eventQueue[0], sizeof(Event), EVENT_STACK_SIZE); - queue_init(&_eventQueue[1], sizeof(Event), EVENT_STACK_SIZE); - queue_init(&_configEventQueue, sizeof(ConfigEvent), EVENT_STACK_SIZE); + MultiCoreCrossLink() + { + if (get_core_num() == 0) + { + queue_init(&_eventQueue[0], sizeof(EventItem), EVENT_STACK_SIZE); + queue_init(&_eventQueue[1], sizeof(EventItem), EVENT_STACK_SIZE); + queue_init(&_configEventQueue, sizeof(ConfigEventItem), EVENT_STACK_SIZE); + } } - ~MultiCoreCrossLink() { /* noop */ }; + ~MultiCoreCrossLink(){}; - void pushEvent(Event* event) { - while (!pushEventNonBlocking(event)) { /* noop */ } - } + void pushEvent(Event *event) + { + QueuedEvent queuedEvent; + queuedEvent.sourceId = event->sourceId; + queuedEvent.eventId = event->eventId; + queuedEvent.value = event->value; + queuedEvent.localFast = event->localFast; - bool pushEventNonBlocking(Event* event) { - // Clone the event so that Eventdispatcher::callListeners() can delete the event. - return queue_try_add(&_eventQueue[get_core_num() ^ 1], new Event(event)); + queue_add_blocking(&_eventQueue[get_core_num() ^ 1], &queuedEvent); } - Event* popEvent() { - Event* event; - while (!popEventNonBlocking(event)) { /* noop */ } - return event; - } + Event *popEvent() + { + QueuedEvent queuedEvent; + queue_remove_blocking(&_eventQueue[get_core_num()], &queuedEvent); - bool popEventNonBlocking(Event* event) { - return queue_try_remove(&_eventQueue[get_core_num()], event); + return new Event(queuedEvent.sourceId, queuedEvent.eventId, queuedEvent.value, queuedEvent.localFast); } - int eventAvailable() { + int eventAvailable() + { return queue_get_level(&_eventQueue[get_core_num()]); } - void pushConfigEvent(ConfigEvent* event) { - if (get_core_num() == 0) { - while (!pushConfigEventNonBlocking(event)) { /* noop */ } - } - } - - bool pushConfigEventNonBlocking(ConfigEvent* event) { - if (get_core_num() == 0) { - // Clone the event so that Eventdispatcher::callListeners() can delete the event. - return queue_try_add(&_configEventQueue, new ConfigEvent(event)); + void pushConfigEvent(ConfigEvent *event) + { + if (get_core_num() == 0) + { + QueuedConfigEvent queuedConfigEvent; + queuedConfigEvent.boardId = event->boardId; + queuedConfigEvent.topic = event->topic; + queuedConfigEvent.index = event->index; + queuedConfigEvent.key = event->key; + queuedConfigEvent.value = event->value; + + queue_add_blocking(&_configEventQueue, &queuedConfigEvent); } - - return false; } - ConfigEvent* popConfigEvent() { - ConfigEvent* event; - while (!popConfigEventNonBlocking(event)) { /* noop */ } - return event; - } + ConfigEvent *popConfigEvent() + { + QueuedConfigEvent queuedConfigEvent; + queue_remove_blocking(&_configEventQueue, &queuedConfigEvent); - bool popConfigEventNonBlocking(ConfigEvent* event) { - return get_core_num() == 1 && queue_try_remove(&_configEventQueue, event); + return new ConfigEvent(queuedConfigEvent.boardId, queuedConfigEvent.topic, queuedConfigEvent.index, queuedConfigEvent.key, queuedConfigEvent.value); } - int configEventAvailable() { + int configEventAvailable() + { return get_core_num() == 1 && queue_get_level(&_configEventQueue); } diff --git a/src/PPUC.h b/src/PPUC.h index 0bf102a..a54560b 100644 --- a/src/PPUC.h +++ b/src/PPUC.h @@ -1,4 +1,4 @@ -/* +/** PPUC.h Created by Markus Kalkbrenner. */ diff --git a/test/IO_16_8_1/platformio.ini b/test/IO_16_8_1/platformio.ini index 4035b4d..7f57217 100644 --- a/test/IO_16_8_1/platformio.ini +++ b/test/IO_16_8_1/platformio.ini @@ -1,11 +1,28 @@ +[platformio] +default_envs = pico + [env:pico] platform = https://github.com/maxgerhardt/platform-raspberrypi.git board = pico framework = arduino board_build.core = earlephilhower board_build.filesystem_size = 0.5m +lib_extra_dirs = + ../.. +lib_deps = + mkalkbrenner/WavePWM + kitesurfer1404/WS2812FX + Bounce2 + +[env:usb_debug] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +board = pico +framework = arduino +board_build.core = earlephilhower +board_build.filesystem_size = 0.5m build_flags = -D PICO_STDIO_USB ; enable stdio over USB + -DUSB_DEBUG=1 lib_extra_dirs = ../.. lib_deps = diff --git a/test/IO_16_8_1/src/main.cpp b/test/IO_16_8_1/src/main.cpp index fdefd49..438aac2 100644 --- a/test/IO_16_8_1/src/main.cpp +++ b/test/IO_16_8_1/src/main.cpp @@ -4,6 +4,9 @@ #include "IOBoardController.h" #include "EffectsController.h" +#ifdef USB_DEBUG +#include "EventDispatcher/CrossLinkDebugger.h" +#endif IOBoardController ioBoardController(CONTROLLER_16_8_1); // Platform will be adjusted by ConfigEvent. @@ -17,6 +20,16 @@ EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_LIBPINMAME); void setup() { +#ifdef USB_DEBUG + Serial.begin(115200); + // The Pico implements USB itself so special care must be taken. Use while(!Serial){} in the setup() code before printing anything so that it waits for the USB connection to be established. + // https://community.platformio.org/t/serial-monitor-not-working/1512/25 + while (!Serial) + { + } + ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); +#endif + Serial1.setTX(0); Serial1.setRX(1); Serial1.setFIFOSize(128); // @todo find the right size. @@ -30,8 +43,57 @@ void setup() void setup1() { +#ifdef USB_DEBUG + while (!Serial) + { + } + + effectsController.eventDispatcher()->addListener(new CrossLinkDebugger()); +#endif + effectsController.eventDispatcher()->setMultiCoreCrossLink( ioBoardController.eventDispatcher()->getMultiCoreCrossLink()); + + effectsController.ledBuiltInDevice()->off(); + + effectsController.addEffect( + new LedOnEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_SOURCE_LIGHT, 88, 1), + 1, // priority + 0, // repeat, -1 means endless + 0 // mode + ); + + effectsController.addEffect( + new NullEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_SOURCE_LIGHT, 88, 0), + 1, // priority + 0, // repeat, -1 means endless + 0 // mode + ); + + effectsController.addEffect( + new LedBlinkEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_ERROR, 1, /* board ID */ 0), + 2, // priority + -1, // repeat, -1 means endless + 0 // mode + ); + + // Controller start + effectsController.addEffect( + new NullEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_NO_ERROR, 1, /* board ID */ 0), + 3, // priority + 0, // repeat + 0 // mode + ); + + effectsController.start(); } void loop() diff --git a/test/IO_16_8_1_USB_DEBUG/platformio.ini b/test/IO_16_8_1_USB_DEBUG/platformio.ini deleted file mode 100644 index 4035b4d..0000000 --- a/test/IO_16_8_1_USB_DEBUG/platformio.ini +++ /dev/null @@ -1,14 +0,0 @@ -[env:pico] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git -board = pico -framework = arduino -board_build.core = earlephilhower -board_build.filesystem_size = 0.5m -build_flags = - -D PICO_STDIO_USB ; enable stdio over USB -lib_extra_dirs = - ../.. -lib_deps = - mkalkbrenner/WavePWM - kitesurfer1404/WS2812FX - Bounce2 diff --git a/test/IO_16_8_1_USB_DEBUG/src/main.cpp b/test/IO_16_8_1_USB_DEBUG/src/main.cpp deleted file mode 100644 index 441be90..0000000 --- a/test/IO_16_8_1_USB_DEBUG/src/main.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// Markus Kalkbrenner 2023 - -#include - -#include "IOBoardController.h" -#include "EffectsController.h" -#include "EventDispatcher/CrossLinkDebugger.h" - -IOBoardController ioBoardController(CONTROLLER_16_8_1); -// Platform will be adjusted by ConfigEvent. -EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_LIBPINMAME); - -// Each controller will be bound to its own core and has it's own -// EventDispatcher. Only the EventDispatcher of IOBoardController -// is attached to RS485. But both EventDispatchers must share the -// same MultiCoreCrosslink to send and receive events between -// both cores. - -void setup() -{ - Serial.begin(115200); - // The Pico implements USB itself so special care must be taken. Use while(!Serial){} in the setup() code before printing anything so that it waits for the USB connection to be established. - // https://community.platformio.org/t/serial-monitor-not-working/1512/25 - while (!Serial) - { - } - Serial.print("PPUC IO_16_8_1 board #"); - Serial.println(16 - ((int) ((analogRead(28) + 30) / 60))); - ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); - - Serial1.setTX(0); - Serial1.setRX(1); - Serial1.setFIFOSize(128); // @todo find the right size. - Serial1.begin(115200); - // The Pico implements USB itself so special care must be taken. Use while(!Serial){} in the setup() code before printing anything so that it waits for the USB connection to be established. - // https://community.platformio.org/t/serial-monitor-not-working/1512/25 - while (!Serial1) - { - } -} - -void setup1() -{ - effectsController.eventDispatcher()->setMultiCoreCrossLink( - ioBoardController.eventDispatcher()->getMultiCoreCrossLink()); - - effectsController.ledBuiltInDevice()->off(); - - effectsController.addEffect( - new LedOnEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_LIGHT, 88, 1), - 1, // priority - 0, // repeat, -1 means endless - 0 // mode - ); - - effectsController.addEffect( - new NullEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_LIGHT, 88, 0), - 1, // priority - 0, // repeat, -1 means endless - 0 // mode - ); - - effectsController.addEffect( - new LedBlinkEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_ERROR, 1, /* board ID */ 0), - 2, // priority - -1, // repeat, -1 means endless - 0 // mode - ); - - // Controller start - effectsController.addEffect( - new NullEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_NO_ERROR, 1, /* board ID */ 0), - 3, // priority - 0, // repeat - 0 // mode - ); - - effectsController.start(); -} - -void loop() -{ - ioBoardController.update(); -} - -void loop1() -{ - effectsController.update(); -} diff --git a/test/IO_16_8_1_USB_DEBUG/test/README b/test/IO_16_8_1_USB_DEBUG/test/README deleted file mode 100644 index b94d089..0000000 --- a/test/IO_16_8_1_USB_DEBUG/test/README +++ /dev/null @@ -1,11 +0,0 @@ - -This directory is intended for PlatformIO Unit Testing and project tests. - -Unit Testing is a software testing method by which individual units of -source code, sets of one or more MCU program modules together with associated -control data, usage procedures, and operating procedures, are tested to -determine whether they are fit for use. Unit testing finds problems early -in the development cycle. - -More information about PlatformIO Unit Testing: -- https://docs.platformio.org/page/plus/unit-testing.html From b27e6e3d366f701b0854b3203d417e3e4a778a21 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 16 Sep 2023 17:37:03 +0200 Subject: [PATCH 016/102] added switch matrix support --- src/IOBoardController.cpp | 223 ++++++++++++++++++++++----------- src/IOBoardController.h | 30 +++-- src/IODevices/SwitchMatrix.cpp | 129 +++++++++++++++++++ src/IODevices/SwitchMatrix.h | 68 ++++++++++ src/PPUC.h | 16 +-- test/IO_16_8_1/src/main.cpp | 40 +++--- 6 files changed, 392 insertions(+), 114 deletions(-) create mode 100644 src/IODevices/SwitchMatrix.cpp create mode 100644 src/IODevices/SwitchMatrix.h diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 4691a37..dc234c5 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -1,6 +1,7 @@ #include "IOBoardController.h" -IOBoardController::IOBoardController(int cT) { +IOBoardController::IOBoardController(int cT) +{ _eventDispatcher = new EventDispatcher(); _eventDispatcher->addListener(this, EVENT_CONFIGURATION); _eventDispatcher->addListener(this, EVENT_PING); @@ -8,114 +9,184 @@ IOBoardController::IOBoardController(int cT) { controllerType = cT; - if (controllerType == CONTROLLER_16_8_1) { + if (controllerType == CONTROLLER_16_8_1) + { // Read bordID. The read value is between 60 and 940. - boardId = 16 - ((int) ((analogRead(28) + 30) / 60)); + boardId = 16 - ((int)((analogRead(28) + 30) / 60)); _eventDispatcher->setRS485ModePin(2); _eventDispatcher->setBoard(boardId); _eventDispatcher->setCrossLinkSerial(Serial1); +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) _multiCoreCrossLink = new MultiCoreCrossLink(); _eventDispatcher->setMultiCoreCrossLink(_multiCoreCrossLink); - +#endif _pwmDevices = new PwmDevices(_eventDispatcher); _switches = new Switches(boardId, _eventDispatcher); + _switchMatrix = new SwitchMatrix(boardId, _eventDispatcher); } } -void IOBoardController::update() { - switches()->update(); - pwmDevices()->update(); +void IOBoardController::update() +{ + if (activeSwitches) + { + switches()->update(); + } + if (activeSwitchMatrix) + { + switchMatrix()->update(); + } + if (activePwmDevices) + { + pwmDevices()->update(); + } + eventDispatcher()->update(); } -void IOBoardController::handleEvent(Event* event) { - switch (event->sourceId) { - case EVENT_PING: - _eventDispatcher->dispatch(new Event(EVENT_PONG, 1, boardId)); - break; +void IOBoardController::handleEvent(Event *event) +{ + switch (event->sourceId) + { + case EVENT_PING: + _eventDispatcher->dispatch(new Event(EVENT_PONG, 1, boardId)); + break; - case EVENT_RESET: - // @todo clear all configurations or reboot the device. - break; + case EVENT_RESET: + // @todo clear all configurations or reboot the device. + break; } } -void IOBoardController::handleEvent(ConfigEvent* event) { - if (event->boardId == boardId) { - switch (event->topic) { - case CONFIG_TOPIC_SWITCHES: - switch (event->key) { - case CONFIG_TOPIC_PORT: - port = event->value; - break; - case CONFIG_TOPIC_NUMBER: - _switches->registerSwitch((byte) port, event->value); - break; +void IOBoardController::handleEvent(ConfigEvent *event) +{ + if (event->boardId == boardId) + { + switch (event->topic) + { + case CONFIG_TOPIC_SWITCHES: + switch (event->key) + { + case CONFIG_TOPIC_PORT: + port = event->value; + break; + case CONFIG_TOPIC_NUMBER: + _switches->registerSwitch((byte)port, event->value); + activeSwitches = true; + break; + } + break; + + case CONFIG_TOPIC_SWITCH_MATRIX: + switch (event->key) + { + case CONFIG_TOPIC_ACTIVE_LOW: + if (event->value) + { + _switchMatrix->setActiveLow(); } break; + case CONFIG_TOPIC_MAX_PULSE_TIME: + _switchMatrix->setPulseTime((byte)event->value); + break; + case CONFIG_TOPIC_TYPE: + type = event->value; + number = 0; + port = 0; + break; + case CONFIG_TOPIC_NUMBER: + number = event->value; + break; + case CONFIG_TOPIC_PORT: + port = event->value; + if (MATRIX_TYPE_COLUMN == type) + { + _switchMatrix->registerColumn(port, number); + } + else + { + _switchMatrix->registerRow(port, number); + } + activeSwitchMatrix = true; + break; + } + + break; - case CONFIG_TOPIC_PWM: - switch (event->key) { - case CONFIG_TOPIC_PORT: - port = event->value; - number = 0; - power = 0; - minPulseTime = 0; - maxPulseTime = 0; - holdPower = 0; - holdPowerActivationTime = 0; - fastSwitch = 0; - break; - case CONFIG_TOPIC_NUMBER: - number = event->value; - break; - case CONFIG_TOPIC_POWER: - power = event->value; - break; - case CONFIG_TOPIC_MIN_PULSE_TIME: - minPulseTime = event->value; - break; - case CONFIG_TOPIC_MAX_PULSE_TIME: - maxPulseTime = event->value; - break; - case CONFIG_TOPIC_HOLD_POWER: - holdPower = event->value; - break; - case CONFIG_TOPIC_HOLD_POWER_ACTIVATION_TIME: - holdPowerActivationTime = event->value; - break; - case CONFIG_TOPIC_FAST_SWITCH: - fastSwitch = event->value; - break; - case CONFIG_TOPIC_TYPE: - switch (event->value) { - case PWM_TYPE_SOLENOID: // Coil - _pwmDevices->registerSolenoid((byte) port, number, power, minPulseTime, maxPulseTime, holdPower, holdPowerActivationTime, fastSwitch); - break; - case PWM_TYPE_FLASHER: // Flasher - _pwmDevices->registerFlasher((byte) port, number, power); - break; - case PWM_TYPE_LAMP: // Lamp - _pwmDevices->registerLamp((byte) port, number, power); - break; - } - break; + case CONFIG_TOPIC_PWM: + switch (event->key) + { + case CONFIG_TOPIC_PORT: + port = event->value; + number = 0; + power = 0; + minPulseTime = 0; + maxPulseTime = 0; + holdPower = 0; + holdPowerActivationTime = 0; + fastSwitch = 0; + break; + case CONFIG_TOPIC_NUMBER: + number = event->value; + break; + case CONFIG_TOPIC_POWER: + power = event->value; + break; + case CONFIG_TOPIC_MIN_PULSE_TIME: + minPulseTime = event->value; + break; + case CONFIG_TOPIC_MAX_PULSE_TIME: + maxPulseTime = event->value; + break; + case CONFIG_TOPIC_HOLD_POWER: + holdPower = event->value; + break; + case CONFIG_TOPIC_HOLD_POWER_ACTIVATION_TIME: + holdPowerActivationTime = event->value; + break; + case CONFIG_TOPIC_FAST_SWITCH: + fastSwitch = event->value; + break; + case CONFIG_TOPIC_TYPE: + switch (event->value) + { + case PWM_TYPE_SOLENOID: // Coil + _pwmDevices->registerSolenoid((byte)port, number, power, minPulseTime, maxPulseTime, holdPower, holdPowerActivationTime, fastSwitch); + activePwmDevices = true; + break; + case PWM_TYPE_FLASHER: // Flasher + _pwmDevices->registerFlasher((byte)port, number, power); + activePwmDevices = true; + break; + case PWM_TYPE_LAMP: // Lamp + _pwmDevices->registerLamp((byte)port, number, power); + activePwmDevices = true; + break; } break; + } + break; } } } -PwmDevices* IOBoardController::pwmDevices() { +PwmDevices *IOBoardController::pwmDevices() +{ return _pwmDevices; } -Switches* IOBoardController::switches() { +Switches *IOBoardController::switches() +{ return _switches; } -EventDispatcher* IOBoardController::eventDispatcher() { - return _eventDispatcher; +SwitchMatrix *IOBoardController::switchMatrix() +{ + return _switchMatrix; } +EventDispatcher *IOBoardController::eventDispatcher() +{ + return _eventDispatcher; +} diff --git a/src/IOBoardController.h b/src/IOBoardController.h index 8d45fc4..0b5d404 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -21,26 +21,35 @@ #include "EventDispatcher/MultiCoreCrossLink.h" #include "IODevices/PwmDevices.h" #include "IODevices/Switches.h" +#include "IODevices/SwitchMatrix.h" -class IOBoardController : public EventListener { +class IOBoardController : public EventListener +{ public: IOBoardController(int controllerType); - PwmDevices* pwmDevices(); + PwmDevices *pwmDevices(); - Switches* switches(); + Switches *switches(); - EventDispatcher* eventDispatcher(); + SwitchMatrix *switchMatrix(); - void handleEvent(Event* event); + EventDispatcher *eventDispatcher(); - void handleEvent(ConfigEvent* event); + void handleEvent(Event *event); + + void handleEvent(ConfigEvent *event); void update(); private: - PwmDevices* _pwmDevices; - Switches* _switches; + PwmDevices *_pwmDevices; + Switches *_switches; + SwitchMatrix *_switchMatrix; + + bool activePwmDevices = false; + bool activeSwitches = false; + bool activeSwitchMatrix = false; int controllerType; byte boardId; @@ -52,10 +61,11 @@ class IOBoardController : public EventListener { byte holdPower = 0; byte holdPowerActivationTime = 0; byte fastSwitch = 0; + byte type = 0; - EventDispatcher* _eventDispatcher; + EventDispatcher *_eventDispatcher; #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - MultiCoreCrossLink* _multiCoreCrossLink; + MultiCoreCrossLink *_multiCoreCrossLink; #endif }; diff --git a/src/IODevices/SwitchMatrix.cpp b/src/IODevices/SwitchMatrix.cpp new file mode 100644 index 0000000..3c46eb9 --- /dev/null +++ b/src/IODevices/SwitchMatrix.cpp @@ -0,0 +1,129 @@ +#include "SwitchMatrix.h" + +void SwitchMatrix::setActiveLow() +{ + activeLow = true; +} + +void SwitchMatrix::setPulseTime(byte pT) +{ + pulseTime = pT; +} + + +void SwitchMatrix::registerColumn(byte p, byte n) +{ + if (n > 0 && n < MAX_COLUMNS) + { + columns[n - 1] = p; + pinMode(p, OUTPUT); + } +} + +void SwitchMatrix::registerRow(byte p, byte n) +{ + if (n > 0 && n < MAX_ROWS) + { + rows[n - 1] = p; + pinMode(p, INPUT); + } +} + +void SwitchMatrix::update() +{ + unsigned long ms = millis(); + if (active) + { + if (ms > (_ms + (int)(pulseTime / 2))) + { + for (int row = 0; row < MAX_ROWS; row++) + { + if (rows[row] != -1 && !toggled[column][row]) + { + bool new_state = digitalRead(rows[row]); + if (new_state != state[column][row]) + { + state[column][row] = new_state; + toggled[column][row] = true; + + word number = (column + 1) * (row + 1); + if (platform != PLATFORM_DATA_EAST) + { + number = ((column + 1) * 10) + (row + 1); + } + // Dispatch all switch events as "local fast". + // If a PWM output registered to it, we have "fast flip". Useful for flippers, kick backs, jets and + // sling shots. + _eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, number, state[column][row], true)); + } + } + } + } + + if (ms > (_ms + pulseTime)) + { + digitalWrite(columns[column], activeLow); + active = false; + _ms = ms; + } + } + else if (!active && (ms > (_ms + pauseTime))) + { + column++; + if (column >= MAX_COLUMNS) + { + column = 0; + } + + // If column is not in use (-1), the next update will increase the column. + if (columns[column] != -1) + { + digitalWrite(columns[column], !activeLow); + active = true; + _ms = ms; + } + } +} + +void SwitchMatrix::handleEvent(Event *event) +{ + switch (event->sourceId) + { + case EVENT_POLL_EVENTS: + if (boardId == (byte)event->value) + { + // This I/O board has been polled for events, so all current switch states are transmitted. + // Reset switch toggles. + for (int col = 0; col < MAX_COLUMNS; col++) + { + for (int row = 0; row < MAX_ROWS; row++) + { + toggled[col][row] = false; + } + } + } + break; + + case EVENT_READ_SWITCHES: + // The CPU requested all current states. + for (int col = 0; col < MAX_COLUMNS; col++) + { + if (columns[col] != -1) + { + for (int row = 0; row < MAX_ROWS; row++) + { + if (rows[row] != -1) + { + word number = (column + 1) * (row + 1); + if (platform != PLATFORM_DATA_EAST) + { + number = ((column + 1) * 10) + (row + 1); + } + _eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, number, state[column][row])); + } + } + } + } + break; + } +} diff --git a/src/IODevices/SwitchMatrix.h b/src/IODevices/SwitchMatrix.h new file mode 100644 index 0000000..4cc6d76 --- /dev/null +++ b/src/IODevices/SwitchMatrix.h @@ -0,0 +1,68 @@ +/* + SwitchMatrix_h. + Created by Markus Kalkbrenner, 2023. +*/ + +#ifndef SwitchMatrix_h +#define SwitchMatrix_h + +#include "../PPUC.h" +#include "../EventDispatcher/Event.h" +#include "../EventDispatcher/EventDispatcher.h" + +#ifndef MAX_COLUMNS +#define MAX_COLUMNS 10 +#endif + +#ifndef MAX_ROWS +#define MAX_ROWS 8 +#endif + +class SwitchMatrix : public EventListener { +public: + SwitchMatrix(byte bId, EventDispatcher* eD) { + boardId = bId; + platform = PLATFORM_LIBPINMAME; + pulseTime = 2; + pauseTime = 2; + activeLow = false; + active = false; + + _ms = millis(); + _eventDispatcher = eD; + _eventDispatcher->addListener(this, EVENT_POLL_EVENTS); + _eventDispatcher->addListener(this, EVENT_READ_SWITCHES); + } + + void registerColumn(byte p, byte n); + void registerRow(byte p, byte n); + + void setActiveLow(); + void setPulseTime(byte pT); + + void update(); + + void handleEvent(Event* event); + + void handleEvent(ConfigEvent* event) {} + +private: + byte boardId; + byte platform; + byte pulseTime; + byte pauseTime; + bool activeLow; + bool active; + + unsigned long _ms; + + int columns[MAX_COLUMNS] = {-1}; + int rows[MAX_ROWS] = {-1}; + bool state[MAX_COLUMNS][MAX_ROWS] = {0}; + bool toggled[MAX_COLUMNS][MAX_ROWS] = {0}; + byte column = 0; + + EventDispatcher* _eventDispatcher; +}; + +#endif diff --git a/src/PPUC.h b/src/PPUC.h index a54560b..56130d2 100644 --- a/src/PPUC.h +++ b/src/PPUC.h @@ -8,16 +8,16 @@ #include -#define CONTROLLER_MEGA_ALL_INPUT 1 -#define CONTROLLER_TEENSY_OUTPUT 10 -#define CONTROLLER_TEENSY_OUTPUT_2 11 -#define CONTROLLER_PICO_OUTPUT 20 +#define CONTROLLER_MEGA_ALL_INPUT 1 +#define CONTROLLER_TEENSY_OUTPUT 10 +#define CONTROLLER_TEENSY_OUTPUT_2 11 +#define CONTROLLER_PICO_OUTPUT 20 #define CONTROLLER_NANO_PIN2DMD_OUTPUT 30 -#define CONTROLLER_16_8_1 40 +#define CONTROLLER_16_8_1 40 -#define PLATFORM_WPC 1 -#define PLATFORM_DATA_EAST 2 -#define PLATFORM_SYS11 3 +#define PLATFORM_WPC 1 +#define PLATFORM_DATA_EAST 2 +#define PLATFORM_SYS11 3 #define PLATFORM_LIBPINMAME 100 #include diff --git a/test/IO_16_8_1/src/main.cpp b/test/IO_16_8_1/src/main.cpp index 438aac2..a555184 100644 --- a/test/IO_16_8_1/src/main.cpp +++ b/test/IO_16_8_1/src/main.cpp @@ -59,7 +59,7 @@ void setup1() effectsController.addEffect( new LedOnEffect(), effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_LIGHT, 88, 1), + new Event(EVENT_SOURCE_LIGHT, 21, 1), 1, // priority 0, // repeat, -1 means endless 0 // mode @@ -68,30 +68,30 @@ void setup1() effectsController.addEffect( new NullEffect(), effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_LIGHT, 88, 0), + new Event(EVENT_SOURCE_LIGHT, 21, 0), 1, // priority 0, // repeat, -1 means endless 0 // mode ); - effectsController.addEffect( - new LedBlinkEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_ERROR, 1, /* board ID */ 0), - 2, // priority - -1, // repeat, -1 means endless - 0 // mode - ); - - // Controller start - effectsController.addEffect( - new NullEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_NO_ERROR, 1, /* board ID */ 0), - 3, // priority - 0, // repeat - 0 // mode - ); + // effectsController.addEffect( + // new LedBlinkEffect(), + // effectsController.ledBuiltInDevice(), + // new Event(EVENT_ERROR, 1, /* board ID */ 0), + // 2, // priority + // -1, // repeat, -1 means endless + // 0 // mode + // ); + + // // Controller start + // effectsController.addEffect( + // new NullEffect(), + // effectsController.ledBuiltInDevice(), + // new Event(EVENT_NO_ERROR, 1, /* board ID */ 0), + // 3, // priority + // 0, // repeat + // 0 // mode + // ); effectsController.start(); } From b26baec133a4a1525f5f7e6d34384fdea74acb2f Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 17 Sep 2023 19:38:01 +0200 Subject: [PATCH 017/102] send board ID with NullEvent --- src/EventDispatcher/EventDispatcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index 90f6d4f..b3a872f 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -269,7 +269,7 @@ void EventDispatcher::update() stackCounter = -1; // Send NULL event to indicate that transmission is complete. - callListeners(new Event(EVENT_NULL), MAX_CROSS_LINKS, true); + callListeners(new Event(EVENT_NULL, 1, board), MAX_CROSS_LINKS, true); if (rs485) { // Wait until the RS485 converter switched back to read mode. From 0928ec1afc740f9b3981e9f852ea68aa420da498 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 17 Sep 2023 20:01:25 +0200 Subject: [PATCH 018/102] flush the serial buffer and wait before turning RS485 back into read mode --- src/EventDispatcher/EventDispatcher.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index b3a872f..b4b1c0e 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -272,9 +272,11 @@ void EventDispatcher::update() callListeners(new Event(EVENT_NULL, 1, board), MAX_CROSS_LINKS, true); if (rs485) { - // Wait until the RS485 converter switched back to read mode. - delayMicroseconds(1000); + // Flush the serial buffer and wait until done. + hwSerial[i]->flush(); digitalWrite(rs485Pin, LOW); // Read. + // Wait until the RS485 converter switched back to read mode. + delayMicroseconds(500); } } } From 59b858419f986ae8b20c8e104fe0b00f3d205ae6 Mon Sep 17 00:00:00 2001 From: foenich <111463200+foenich@users.noreply.github.com> Date: Sat, 11 Nov 2023 00:54:00 +0100 Subject: [PATCH 019/102] Update IOBoardController.cpp Increase calculation accuracy. Part tolerances and imprecise calculation could add up to a wrong board-ID --- src/IOBoardController.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index dc234c5..cce9802 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -11,9 +11,8 @@ IOBoardController::IOBoardController(int cT) if (controllerType == CONTROLLER_16_8_1) { - // Read bordID. The read value is between 60 and 940. - boardId = 16 - ((int)((analogRead(28) + 30) / 60)); - + // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 -> 58.46 to 935.3 + boardId = 16 - ((int)((analogRead(28) + 29.32) / 58.46)); _eventDispatcher->setRS485ModePin(2); _eventDispatcher->setBoard(boardId); _eventDispatcher->setCrossLinkSerial(Serial1); From 60aea6549870035fe4c7f3eb8c2485df34fde183 Mon Sep 17 00:00:00 2001 From: foenich <111463200+foenich@users.noreply.github.com> Date: Sat, 11 Nov 2023 00:58:24 +0100 Subject: [PATCH 020/102] Update IOBoardController.cpp Increase calculation accuracy. Part tolerances and imprecise calculation could add up to a wrong board-ID --- src/IOBoardController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index cce9802..617533a 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -12,7 +12,7 @@ IOBoardController::IOBoardController(int cT) if (controllerType == CONTROLLER_16_8_1) { // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 -> 58.46 to 935.3 - boardId = 16 - ((int)((analogRead(28) + 29.32) / 58.46)); + boardId = 16 - ((int)((analogRead(28) + 29.23) / 58.46)); _eventDispatcher->setRS485ModePin(2); _eventDispatcher->setBoard(boardId); _eventDispatcher->setCrossLinkSerial(Serial1); From b0d9edf5c62cd3ccb9b24fa1f6aced3b5238c482 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 15 Nov 2023 20:40:48 +0100 Subject: [PATCH 021/102] more debug output, fixed multi core debugging, switch matrix fixes --- src/EventDispatcher/CrossLinkDebugger.cpp | 26 ++++---- src/EventDispatcher/EventDispatcher.cpp | 11 ++++ src/IODevices/PwmDevices.cpp | 9 +++ src/IODevices/SwitchMatrix.cpp | 19 +++++- src/IODevices/SwitchMatrix.h | 13 +++- src/IODevices/Switches.cpp | 73 +++++++++++++++-------- test/IO_16_8_1/src/main.cpp | 35 ++++++----- 7 files changed, 127 insertions(+), 59 deletions(-) diff --git a/src/EventDispatcher/CrossLinkDebugger.cpp b/src/EventDispatcher/CrossLinkDebugger.cpp index ec68931..cd6e7a5 100644 --- a/src/EventDispatcher/CrossLinkDebugger.cpp +++ b/src/EventDispatcher/CrossLinkDebugger.cpp @@ -1,13 +1,11 @@ #include "CrossLinkDebugger.h" -// https://stackoverflow.com/questions/20310000/error-iso-c-forbids-in-class-initialization-of-non-const-static-member -bool CrossLinkDebugger::lock = true; - CrossLinkDebugger::CrossLinkDebugger() { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) if (get_core_num() == 0) { + rp2040.idleOtherCore(); Serial.println("PPUC IO_16_8_1"); Serial.print("PPUC board #"); Serial.println(16 - ((int)((analogRead(28) + 30) / 60))); @@ -15,22 +13,19 @@ CrossLinkDebugger::CrossLinkDebugger() Serial.println("PPUC CrossLinkDebugger"); Serial.println("----------------------"); #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) + rp2040.resumeOtherCore(); } else { delayMicroseconds(500); } #endif - lock = false; } void CrossLinkDebugger::handleEvent(Event *event) { - while (lock) - { - } - lock = true; #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) + rp2040.idleOtherCore(); Serial.print("Core "); Serial.print(get_core_num(), DEC); Serial.print(" "); @@ -41,16 +36,15 @@ void CrossLinkDebugger::handleEvent(Event *event) Serial.print(event->eventId, DEC); Serial.print(", value "); Serial.println(event->value, DEC); - lock = false; +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) + rp2040.resumeOtherCore(); +#endif } void CrossLinkDebugger::handleEvent(ConfigEvent *event) { - while (lock) - { - } - lock = true; #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) + rp2040.idleOtherCore(); Serial.print("Core "); Serial.print(get_core_num(), DEC); Serial.print(" "); @@ -63,7 +57,11 @@ void CrossLinkDebugger::handleEvent(ConfigEvent *event) Serial.print(event->index, DEC); Serial.print(", key "); Serial.print(event->key, DEC); + Serial.print(", value(DEC) "); + Serial.print(event->value, DEC); Serial.print(", value(HEX) "); Serial.println(event->value, HEX); - lock = false; +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) + rp2040.resumeOtherCore(); +#endif } diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index b4b1c0e..dbb808f 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -119,6 +119,17 @@ void EventDispatcher::callListeners(Event *event, int sender, bool flush) hwSerial[i]->write(msg, 7); } } + +#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) + rp2040.idleOtherCore(); + Serial.print("Sent event: sourceId "); + Serial.print(event->sourceId); + Serial.print(", eventId "); + Serial.print(event->eventId, DEC); + Serial.print(", value "); + Serial.println(event->value, DEC); + rp2040.resumeOtherCore(); +#endif } } diff --git a/src/IODevices/PwmDevices.cpp b/src/IODevices/PwmDevices.cpp index 0675063..eda6b89 100644 --- a/src/IODevices/PwmDevices.cpp +++ b/src/IODevices/PwmDevices.cpp @@ -16,6 +16,15 @@ void PwmDevices::registerSolenoid(byte p, byte n, byte pow, byte minPT, byte max pinMode(p, OUTPUT); analogWrite(p, 0); type[last++] = PWM_TYPE_SOLENOID; + +#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) + rp2040.idleOtherCore(); + Serial.print("Register PWM Device "); + Serial.print(n, DEC); + Serial.print(" on port "); + Serial.println(p, DEC); + rp2040.resumeOtherCore(); +#endif } } diff --git a/src/IODevices/SwitchMatrix.cpp b/src/IODevices/SwitchMatrix.cpp index 3c46eb9..7eb0b6d 100644 --- a/src/IODevices/SwitchMatrix.cpp +++ b/src/IODevices/SwitchMatrix.cpp @@ -10,13 +10,21 @@ void SwitchMatrix::setPulseTime(byte pT) pulseTime = pT; } - void SwitchMatrix::registerColumn(byte p, byte n) { if (n > 0 && n < MAX_COLUMNS) { columns[n - 1] = p; pinMode(p, OUTPUT); + +#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) + rp2040.idleOtherCore(); + Serial.print("Register Switch Matrix Column "); + Serial.print(n, DEC); + Serial.print(" on port "); + Serial.println(p, DEC); + rp2040.resumeOtherCore(); +#endif } } @@ -26,6 +34,15 @@ void SwitchMatrix::registerRow(byte p, byte n) { rows[n - 1] = p; pinMode(p, INPUT); + +#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) + rp2040.idleOtherCore(); + Serial.print("Register Switch Matrix Row "); + Serial.print(n, DEC); + Serial.print(" on port "); + Serial.println(p, DEC); + rp2040.resumeOtherCore(); +#endif } } diff --git a/src/IODevices/SwitchMatrix.h b/src/IODevices/SwitchMatrix.h index 4cc6d76..b59b271 100644 --- a/src/IODevices/SwitchMatrix.h +++ b/src/IODevices/SwitchMatrix.h @@ -27,6 +27,15 @@ class SwitchMatrix : public EventListener { pauseTime = 2; activeLow = false; active = false; + + for (int col = 0; col < MAX_COLUMNS; col++) + { + columns[col] = -1; + } + for (int row = 0; row < MAX_ROWS; row++) + { + rows[row] = -1; + } _ms = millis(); _eventDispatcher = eD; @@ -56,8 +65,8 @@ class SwitchMatrix : public EventListener { unsigned long _ms; - int columns[MAX_COLUMNS] = {-1}; - int rows[MAX_ROWS] = {-1}; + int columns[MAX_COLUMNS]; + int rows[MAX_ROWS]; bool state[MAX_COLUMNS][MAX_ROWS] = {0}; bool toggled[MAX_COLUMNS][MAX_ROWS] = {0}; byte column = 0; diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index 8005c96..c5c3441 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -1,24 +1,39 @@ #include "Switches.h" -void Switches::registerSwitch(byte p, byte n) { - if (last < (MAX_SWITCHES - 1)) { +void Switches::registerSwitch(byte p, byte n) +{ + if (last < (MAX_SWITCHES - 1)) + { pinMode(p, INPUT); port[++last] = p; number[last] = n; toggled[last] = false; - state[last] = digitalRead(p); + state[last] = !digitalRead(p); +#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) + rp2040.idleOtherCore(); + Serial.print("Register Switch "); + Serial.print(n, DEC); + Serial.print(" on port "); + Serial.println(p, DEC); + rp2040.resumeOtherCore(); +#endif } } -void Switches::update() { +void Switches::update() +{ // Wait for SWITCH_DEBOUNCE milliseconds to debounce the switches. That covers the edge case that a switch was hit // right before the last polling of events. After SWITCH_DEBOUNCE milliseconds every switch is allowed to toggle // once until the events get polled again. - if (millis() - _ms >= SWITCH_DEBOUNCE) { - for (int i = 0; i <= last; i++) { - if (!toggled[i]) { - bool new_state = digitalRead(port[i]); - if (new_state != state[i]) { + if (millis() - _ms >= SWITCH_DEBOUNCE) + { + for (int i = 0; i <= last; i++) + { + if (!toggled[i]) + { + bool new_state = !digitalRead(port[i]); + if (new_state != state[i]) + { state[i] = new_state; toggled[i] = true; // Dispatch all switch events as "local fast". @@ -31,24 +46,34 @@ void Switches::update() { } } -void Switches::handleEvent(Event* event) { - switch (event->sourceId) { - case EVENT_POLL_EVENTS: - if (boardId == (byte) event->value) { - // This I/O board has been polled for events, so all current switch states are transmitted. Reset switch - // debounce timer and toggles. - _ms = millis(); - for (int i = 0; i <= last; i++) { - toggled[i] = false; - } +void Switches::handleEvent(Event *event) +{ + switch (event->sourceId) + { + case EVENT_POLL_EVENTS: + if (boardId == (byte)event->value) + { + // This I/O board has been polled for events, so all current switch states are transmitted. Reset switch + // debounce timer and toggles. + _ms = millis(); + for (int i = 0; i <= last; i++) + { + toggled[i] = false; } - break; + } + break; - case EVENT_READ_SWITCHES: - // The CPU requested all current states. - for (int i = 0; i <= last; i++) { + case EVENT_READ_SWITCHES: + // The CPU requested all current states. + for (int i = 0; i <= last; i++) + { + // Send all states of switches that haven't been toggled since last poll. + if (!toggled[i]) + { + toggled[i] = true; _eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), state[i])); } - break; + } + break; } } diff --git a/test/IO_16_8_1/src/main.cpp b/test/IO_16_8_1/src/main.cpp index a555184..7b874cd 100644 --- a/test/IO_16_8_1/src/main.cpp +++ b/test/IO_16_8_1/src/main.cpp @@ -74,24 +74,23 @@ void setup1() 0 // mode ); - // effectsController.addEffect( - // new LedBlinkEffect(), - // effectsController.ledBuiltInDevice(), - // new Event(EVENT_ERROR, 1, /* board ID */ 0), - // 2, // priority - // -1, // repeat, -1 means endless - // 0 // mode - // ); - - // // Controller start - // effectsController.addEffect( - // new NullEffect(), - // effectsController.ledBuiltInDevice(), - // new Event(EVENT_NO_ERROR, 1, /* board ID */ 0), - // 3, // priority - // 0, // repeat - // 0 // mode - // ); + effectsController.addEffect( + new LedBlinkEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_ERROR, 1, /* board ID */ 0), + 2, // priority + -1, // repeat, -1 means endless + 0 // mode + ); + + effectsController.addEffect( + new NullEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_NO_ERROR, 1, /* board ID */ 0), + 3, // priority + 0, // repeat + 0 // mode + ); effectsController.start(); } From 892dbbc44f9648b05b2827f78b663fefef00efc4 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Fri, 17 Nov 2023 12:20:03 +0100 Subject: [PATCH 022/102] added more debug output --- src/EventDispatcher/EventDispatcher.cpp | 45 ++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index dbb808f..602d1b5 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -281,23 +281,66 @@ void EventDispatcher::update() // Send NULL event to indicate that transmission is complete. callListeners(new Event(EVENT_NULL, 1, board), MAX_CROSS_LINKS, true); + if (rs485) { // Flush the serial buffer and wait until done. hwSerial[i]->flush(); digitalWrite(rs485Pin, LOW); // Read. // Wait until the RS485 converter switched back to read mode. - delayMicroseconds(500); + delayMicroseconds(200); } } } + else + { +#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) + rp2040.idleOtherCore(); + Serial.print("Received wrong second stop byte "); + Serial.println(stopByte, DEC); + rp2040.resumeOtherCore(); +#endif + } + } + else + { +#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) + rp2040.idleOtherCore(); + Serial.print("Received wrong first stop byte "); + Serial.println(stopByte, DEC); + rp2040.resumeOtherCore(); +#endif } } + else + { +#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) + rp2040.idleOtherCore(); + Serial.print("Received invalid event id "); + Serial.println(eventId, DEC); + rp2040.resumeOtherCore(); +#endif + } } } + else + { +#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) + rp2040.idleOtherCore(); + Serial.print("Received invalid source id "); + Serial.println(sourceId, DEC); + rp2040.resumeOtherCore(); +#endif + } } else { +#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) + rp2040.idleOtherCore(); + Serial.print("Received wrong start byte "); + Serial.println(startByte, DEC); + rp2040.resumeOtherCore(); +#endif // We didn't receive a start byte. Fake "success" to start over with the next byte. success = true; } From 01ae5cd673972f20f1d2d35491c7f6bc167bcd50 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 19 Nov 2023 00:33:55 +0100 Subject: [PATCH 023/102] Set mid power output as input. --- src/IODevices/Switches.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index c5c3441..164c0bc 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -4,6 +4,14 @@ void Switches::registerSwitch(byte p, byte n) { if (last < (MAX_SWITCHES - 1)) { + if (p >= 15 && p <= 18) { + // Set mid power output as input. + pinMode(p, OUTPUT); + digitalWrite(HIGH); + delayMicroseconds(100); + digitalWrite(LOW); + } + pinMode(p, INPUT); port[++last] = p; number[last] = n; From db66208e125f73bc361afca74580a543144b5dc9 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 20 Nov 2023 10:56:05 +0100 Subject: [PATCH 024/102] auto detection of usb debugging, fixed mid power inputs --- src/EventDispatcher/CrossLinkDebugger.cpp | 5 ++++- src/IODevices/PwmDevices.cpp | 9 -------- src/IODevices/Switches.cpp | 12 ++-------- test/IO_16_8_1/platformio.ini | 14 ------------ test/IO_16_8_1/src/main.cpp | 27 ++++++++++++++--------- 5 files changed, 22 insertions(+), 45 deletions(-) diff --git a/src/EventDispatcher/CrossLinkDebugger.cpp b/src/EventDispatcher/CrossLinkDebugger.cpp index cd6e7a5..fd517e4 100644 --- a/src/EventDispatcher/CrossLinkDebugger.cpp +++ b/src/EventDispatcher/CrossLinkDebugger.cpp @@ -8,7 +8,9 @@ CrossLinkDebugger::CrossLinkDebugger() rp2040.idleOtherCore(); Serial.println("PPUC IO_16_8_1"); Serial.print("PPUC board #"); - Serial.println(16 - ((int)((analogRead(28) + 30) / 60))); + // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 -> 58.46 to 935.3 + Serial.println(16 - ((int)((analogRead(28) + 29.23) / 58.46))); + Serial.println("PPUC core #0 started"); #endif Serial.println("PPUC CrossLinkDebugger"); Serial.println("----------------------"); @@ -17,6 +19,7 @@ CrossLinkDebugger::CrossLinkDebugger() } else { + Serial.println("PPUC core #1 started"); delayMicroseconds(500); } #endif diff --git a/src/IODevices/PwmDevices.cpp b/src/IODevices/PwmDevices.cpp index eda6b89..0675063 100644 --- a/src/IODevices/PwmDevices.cpp +++ b/src/IODevices/PwmDevices.cpp @@ -16,15 +16,6 @@ void PwmDevices::registerSolenoid(byte p, byte n, byte pow, byte minPT, byte max pinMode(p, OUTPUT); analogWrite(p, 0); type[last++] = PWM_TYPE_SOLENOID; - -#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) - rp2040.idleOtherCore(); - Serial.print("Register PWM Device "); - Serial.print(n, DEC); - Serial.print(" on port "); - Serial.println(p, DEC); - rp2040.resumeOtherCore(); -#endif } } diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index 164c0bc..a6cbaa1 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -7,9 +7,9 @@ void Switches::registerSwitch(byte p, byte n) if (p >= 15 && p <= 18) { // Set mid power output as input. pinMode(p, OUTPUT); - digitalWrite(HIGH); + digitalWrite(p, HIGH); delayMicroseconds(100); - digitalWrite(LOW); + digitalWrite(p, LOW); } pinMode(p, INPUT); @@ -17,14 +17,6 @@ void Switches::registerSwitch(byte p, byte n) number[last] = n; toggled[last] = false; state[last] = !digitalRead(p); -#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) - rp2040.idleOtherCore(); - Serial.print("Register Switch "); - Serial.print(n, DEC); - Serial.print(" on port "); - Serial.println(p, DEC); - rp2040.resumeOtherCore(); -#endif } } diff --git a/test/IO_16_8_1/platformio.ini b/test/IO_16_8_1/platformio.ini index 7f57217..6694b43 100644 --- a/test/IO_16_8_1/platformio.ini +++ b/test/IO_16_8_1/platformio.ini @@ -7,22 +7,8 @@ board = pico framework = arduino board_build.core = earlephilhower board_build.filesystem_size = 0.5m -lib_extra_dirs = - ../.. -lib_deps = - mkalkbrenner/WavePWM - kitesurfer1404/WS2812FX - Bounce2 - -[env:usb_debug] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git -board = pico -framework = arduino -board_build.core = earlephilhower -board_build.filesystem_size = 0.5m build_flags = -D PICO_STDIO_USB ; enable stdio over USB - -DUSB_DEBUG=1 lib_extra_dirs = ../.. lib_deps = diff --git a/test/IO_16_8_1/src/main.cpp b/test/IO_16_8_1/src/main.cpp index 7b874cd..590ca30 100644 --- a/test/IO_16_8_1/src/main.cpp +++ b/test/IO_16_8_1/src/main.cpp @@ -4,14 +4,14 @@ #include "IOBoardController.h" #include "EffectsController.h" -#ifdef USB_DEBUG #include "EventDispatcher/CrossLinkDebugger.h" -#endif IOBoardController ioBoardController(CONTROLLER_16_8_1); // Platform will be adjusted by ConfigEvent. EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_LIBPINMAME); +bool usb_debugging = false; + // Each controller will be bound to its own core and has it's own // EventDispatcher. Only the EventDispatcher of IOBoardController // is attached to RS485. But both EventDispatchers must share the @@ -20,15 +20,22 @@ EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_LIBPINMAME); void setup() { -#ifdef USB_DEBUG + uint32_t timeout = millis() + 2000; + Serial.begin(115200); // The Pico implements USB itself so special care must be taken. Use while(!Serial){} in the setup() code before printing anything so that it waits for the USB connection to be established. // https://community.platformio.org/t/serial-monitor-not-working/1512/25 - while (!Serial) + while (!Serial && millis() < timeout) + { + } + + if (Serial) { + usb_debugging = true; + delay(10); + ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); + rp2040.restartCore1(); } - ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); -#endif Serial1.setTX(0); Serial1.setRX(1); @@ -43,14 +50,12 @@ void setup() void setup1() { -#ifdef USB_DEBUG - while (!Serial) + if (usb_debugging) { + delay(10); + effectsController.eventDispatcher()->addListener(new CrossLinkDebugger()); } - effectsController.eventDispatcher()->addListener(new CrossLinkDebugger()); -#endif - effectsController.eventDispatcher()->setMultiCoreCrossLink( ioBoardController.eventDispatcher()->getMultiCoreCrossLink()); From f579234a8197ddfe594234998cf60fcbe25fec26 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 20 Nov 2023 19:06:23 +0100 Subject: [PATCH 025/102] fixed core initialization and lamps --- .../CombinedGiAndLightMatrixWS2812FXDevice.cpp | 3 --- .../CombinedGiAndLightMatrixWS2812FXDevice.h | 7 ++++++- src/EffectsController.cpp | 12 +++++------- src/EffectsController.h | 4 ++-- src/EventDispatcher/CrossLinkDebugger.cpp | 3 ++- src/EventDispatcher/EventDispatcher.cpp | 3 ++- src/IODevices/PwmDevices.h | 11 ++++------- src/IODevices/SwitchMatrix.cpp | 17 ----------------- src/IODevices/SwitchMatrix.h | 16 +++++++++------- test/IO_16_8_1/src/main.cpp | 13 ++++++++++--- 10 files changed, 40 insertions(+), 49 deletions(-) diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp index b29e353..79c7358 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp @@ -228,9 +228,6 @@ void CombinedGiAndLightMatrixWS2812FXDevice::handleEvent(Event *event) } else if (event->sourceId == EVENT_SOURCE_LIGHT || event->sourceId == EVENT_SOURCE_SOLENOID) { - // char system = (event->eventId & 0xFF00) >> 8; - // uint8_t number = event->eventId & 0x00FF; - uint8_t number = event->eventId; if (event->sourceId == EVENT_SOURCE_LIGHT) diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h index 755407f..d6f6637 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h @@ -51,6 +51,7 @@ #include "WS2812FXDevice.h" #include "../EventDispatcher/Event.h" +#include "../EventDispatcher/EventDispatcher.h" #include "../EventDispatcher/EventListener.h" #include "../InputDevices/GeneralIlluminationWPC.h" @@ -62,7 +63,7 @@ class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, public EventListener { public: - CombinedGiAndLightMatrixWS2812FXDevice(WS2812FX *ws2812FX, int firstLED, int lastLED, int firstSegment, int lastSegment) : WS2812FXDevice(ws2812FX, firstLED, lastLED, firstSegment, lastSegment) + CombinedGiAndLightMatrixWS2812FXDevice(WS2812FX *ws2812FX, int firstLED, int lastLED, int firstSegment, int lastSegment, EventDispatcher * eventDispatcher) : WS2812FXDevice(ws2812FX, firstLED, lastLED, firstSegment, lastSegment) { wavePWMHeatUp = new WavePWM(); wavePWMAfterGlow = new WavePWM(); @@ -81,6 +82,10 @@ class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, public Eve ledLightMatrixPositions[number][i] = -1; } } + + eventDispatcher->addListener(this, EVENT_SOURCE_GI); + eventDispatcher->addListener(this, EVENT_SOURCE_SOLENOID); // Flasher + eventDispatcher->addListener(this, EVENT_SOURCE_LIGHT); } void on(); diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index f46e0b9..691eb46 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -52,7 +52,8 @@ CombinedGiAndLightMatrixWS2812FXDevice *EffectsController::createCombinedGiAndLi ws2812FXDevice->getFirstLED(), ws2812FXDevice->getlastLED(), ws2812FXDevice->getFirstSegment(), - ws2812FXDevice->getLastSegment()); + ws2812FXDevice->getLastSegment(), + _eventDispatcher); giAndLightMatrix->off(); @@ -187,7 +188,6 @@ void EffectsController::handleEvent(ConfigEvent *event) break; case CONFIG_TOPIC_LIGHT_UP: config_heatUp = event->value; - if (!ws2812FXDevices[0][0]) { ws2812FXDevices[0][0] = new CombinedGiAndLightMatrixWS2812FXDevice( @@ -195,18 +195,16 @@ void EffectsController::handleEvent(ConfigEvent *event) 0, config_amount - 1, 0, - 0); + 0, + _eventDispatcher); ws2812FXDevices[0][0]->getWS2812FX()->init(); ws2812FXDeviceCounters[0] = 1; // Brightness might be overwritten later. // ws2812FXDevices[0][0]->setBrightness(WS2812FX_BRIGHTNESS); + // "off" means no effects, standard operation mode. ws2812FXDevices[0][0]->off(); ws2812FXstates[0] = true; - - _eventDispatcher->addListener((EventListener *)ws2812FXDevices[0][0], EVENT_SOURCE_GI); - _eventDispatcher->addListener((EventListener *)ws2812FXDevices[0][0], EVENT_SOURCE_SOLENOID); - _eventDispatcher->addListener((EventListener *)ws2812FXDevices[0][0], EVENT_SOURCE_LIGHT); } break; diff --git a/src/EffectsController.h b/src/EffectsController.h index a222d17..193066d 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -290,8 +290,8 @@ class EffectsController : public EventListener { #endif } else if (controllerType == CONTROLLER_16_8_1) { - // Read bordID. The read value is between 60 and 940. - boardId = 16 - ((int) ((analogRead(28) + 30) / 60)); + // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 -> 58.46 to 935.3 + boardId = 16 - ((int)((analogRead(28) + 29.23) / 58.46)); _ledBuiltInDevice = new LedBuiltInDevice(); _ledBuiltInDevice->on(); diff --git a/src/EventDispatcher/CrossLinkDebugger.cpp b/src/EventDispatcher/CrossLinkDebugger.cpp index fd517e4..94607e6 100644 --- a/src/EventDispatcher/CrossLinkDebugger.cpp +++ b/src/EventDispatcher/CrossLinkDebugger.cpp @@ -19,8 +19,9 @@ CrossLinkDebugger::CrossLinkDebugger() } else { + rp2040.idleOtherCore(); Serial.println("PPUC core #1 started"); - delayMicroseconds(500); + rp2040.resumeOtherCore(); } #endif } diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index 602d1b5..845ed9c 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -69,6 +69,7 @@ void EventDispatcher::dispatch(Event *event) { for (byte i = 0; i <= numListeners; i++) { + if (event->sourceId == eventListenerFilters[i] || EVENT_SOURCE_ANY == eventListenerFilters[i]) { eventListeners[i]->handleEvent(event); @@ -120,7 +121,7 @@ void EventDispatcher::callListeners(Event *event, int sender, bool flush) } } -#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.idleOtherCore(); Serial.print("Sent event: sourceId "); Serial.print(event->sourceId); diff --git a/src/IODevices/PwmDevices.h b/src/IODevices/PwmDevices.h index 89334f3..bbcc45e 100644 --- a/src/IODevices/PwmDevices.h +++ b/src/IODevices/PwmDevices.h @@ -20,12 +20,11 @@ class PwmDevices : public EventListener { public: // Constructor - PwmDevices(EventDispatcher *eD) + PwmDevices(EventDispatcher *eventDispatcher) { - _eventDispatcher = eD; - _eventDispatcher->addListener(this, EVENT_SOURCE_LIGHT); - _eventDispatcher->addListener(this, EVENT_SOURCE_SOLENOID); - _eventDispatcher->addListener(this, EVENT_SOURCE_SWITCH); + eventDispatcher->addListener(this, EVENT_SOURCE_LIGHT); + eventDispatcher->addListener(this, EVENT_SOURCE_SOLENOID); + eventDispatcher->addListener(this, EVENT_SOURCE_SWITCH); } void registerSolenoid(byte p, byte n, byte pow, byte minPT, byte maxPT, byte hP, byte hPAT, byte fS); @@ -54,8 +53,6 @@ class PwmDevices : public EventListener bool scheduled[MAX_PWM_OUTPUTS] = {0}; byte last = 0; - EventDispatcher *_eventDispatcher; - void updateSolenoidOrFlasher(bool targetState, byte i); }; diff --git a/src/IODevices/SwitchMatrix.cpp b/src/IODevices/SwitchMatrix.cpp index 7eb0b6d..69fb1fe 100644 --- a/src/IODevices/SwitchMatrix.cpp +++ b/src/IODevices/SwitchMatrix.cpp @@ -16,15 +16,6 @@ void SwitchMatrix::registerColumn(byte p, byte n) { columns[n - 1] = p; pinMode(p, OUTPUT); - -#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) - rp2040.idleOtherCore(); - Serial.print("Register Switch Matrix Column "); - Serial.print(n, DEC); - Serial.print(" on port "); - Serial.println(p, DEC); - rp2040.resumeOtherCore(); -#endif } } @@ -35,14 +26,6 @@ void SwitchMatrix::registerRow(byte p, byte n) rows[n - 1] = p; pinMode(p, INPUT); -#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) - rp2040.idleOtherCore(); - Serial.print("Register Switch Matrix Row "); - Serial.print(n, DEC); - Serial.print(" on port "); - Serial.println(p, DEC); - rp2040.resumeOtherCore(); -#endif } } diff --git a/src/IODevices/SwitchMatrix.h b/src/IODevices/SwitchMatrix.h index b59b271..5d8155a 100644 --- a/src/IODevices/SwitchMatrix.h +++ b/src/IODevices/SwitchMatrix.h @@ -18,20 +18,22 @@ #define MAX_ROWS 8 #endif -class SwitchMatrix : public EventListener { +class SwitchMatrix : public EventListener +{ public: - SwitchMatrix(byte bId, EventDispatcher* eD) { + SwitchMatrix(byte bId, EventDispatcher *eD) + { boardId = bId; platform = PLATFORM_LIBPINMAME; pulseTime = 2; pauseTime = 2; activeLow = false; active = false; - + for (int col = 0; col < MAX_COLUMNS; col++) { columns[col] = -1; - } + } for (int row = 0; row < MAX_ROWS; row++) { rows[row] = -1; @@ -51,9 +53,9 @@ class SwitchMatrix : public EventListener { void update(); - void handleEvent(Event* event); + void handleEvent(Event *event); - void handleEvent(ConfigEvent* event) {} + void handleEvent(ConfigEvent *event) {} private: byte boardId; @@ -71,7 +73,7 @@ class SwitchMatrix : public EventListener { bool toggled[MAX_COLUMNS][MAX_ROWS] = {0}; byte column = 0; - EventDispatcher* _eventDispatcher; + EventDispatcher *_eventDispatcher; }; #endif diff --git a/test/IO_16_8_1/src/main.cpp b/test/IO_16_8_1/src/main.cpp index 590ca30..f0e55e4 100644 --- a/test/IO_16_8_1/src/main.cpp +++ b/test/IO_16_8_1/src/main.cpp @@ -11,6 +11,7 @@ IOBoardController ioBoardController(CONTROLLER_16_8_1); EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_LIBPINMAME); bool usb_debugging = false; +bool core_0_initilized = false; // Each controller will be bound to its own core and has it's own // EventDispatcher. Only the EventDispatcher of IOBoardController @@ -34,9 +35,11 @@ void setup() usb_debugging = true; delay(10); ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); - rp2040.restartCore1(); } + core_0_initilized = true; + rp2040.restartCore1(); + Serial1.setTX(0); Serial1.setRX(1); Serial1.setFIFOSize(128); // @todo find the right size. @@ -50,6 +53,10 @@ void setup() void setup1() { + while (!core_0_initilized) + { + } + if (usb_debugging) { delay(10); @@ -64,7 +71,7 @@ void setup1() effectsController.addEffect( new LedOnEffect(), effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_LIGHT, 21, 1), + new Event(EVENT_SOURCE_LIGHT, 11, 1), 1, // priority 0, // repeat, -1 means endless 0 // mode @@ -73,7 +80,7 @@ void setup1() effectsController.addEffect( new NullEffect(), effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_LIGHT, 21, 0), + new Event(EVENT_SOURCE_LIGHT, 11, 0), 1, // priority 0, // repeat, -1 means endless 0 // mode From b07685c72d72677594b8db7a873e571132379297 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 20 Nov 2023 19:27:40 +0100 Subject: [PATCH 026/102] activated afterGlow support --- src/EffectsController.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 691eb46..3746c57 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -204,6 +204,14 @@ void EffectsController::handleEvent(ConfigEvent *event) // ws2812FXDevices[0][0]->setBrightness(WS2812FX_BRIGHTNESS); // "off" means no effects, standard operation mode. ws2812FXDevices[0][0]->off(); + if (config_heatUp > 0) + { + ((CombinedGiAndLightMatrixWS2812FXDevice*)ws2812FXDevices[0][0])->setHeatUp(config_heatUp); + } + if (config_afterGlow > 0) + { + ((CombinedGiAndLightMatrixWS2812FXDevice*)ws2812FXDevices[0][0])->setAfterGlow(config_afterGlow); + } ws2812FXstates[0] = true; } @@ -374,7 +382,7 @@ void EffectsController::start() { if (ws2812FXbrightness[i] == 0) { - //setBrightness(i + 1, WS2812FX_BRIGHTNESS); + // setBrightness(i + 1, WS2812FX_BRIGHTNESS); } } From cf77483e7fc9a40f5d20ee392f6603dc09fea8c7 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Tue, 21 Nov 2023 16:02:46 +0100 Subject: [PATCH 027/102] fixed debug output --- src/EventDispatcher/EventDispatcher.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index 845ed9c..e6512ce 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -295,7 +295,7 @@ void EventDispatcher::update() } else { -#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.idleOtherCore(); Serial.print("Received wrong second stop byte "); Serial.println(stopByte, DEC); @@ -305,7 +305,7 @@ void EventDispatcher::update() } else { -#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.idleOtherCore(); Serial.print("Received wrong first stop byte "); Serial.println(stopByte, DEC); @@ -315,7 +315,7 @@ void EventDispatcher::update() } else { -#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.idleOtherCore(); Serial.print("Received invalid event id "); Serial.println(eventId, DEC); @@ -326,7 +326,7 @@ void EventDispatcher::update() } else { -#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.idleOtherCore(); Serial.print("Received invalid source id "); Serial.println(sourceId, DEC); @@ -336,7 +336,7 @@ void EventDispatcher::update() } else { -#if defined(USB_DEBUG) && (defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040)) +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.idleOtherCore(); Serial.print("Received wrong start byte "); Serial.println(startByte, DEC); From 64558607dc23d1f3307c6e667c901926459b1dfb Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Tue, 21 Nov 2023 20:14:10 +0100 Subject: [PATCH 028/102] fixed switch initialization --- src/EventDispatcher/Event.h | 1 + src/IOBoardController.cpp | 28 ++++++++++++++++++---------- src/IOBoardController.h | 1 + src/IODevices/Switches.cpp | 18 ++++++++++++------ 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index cc1664c..f1b2d7e 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -25,6 +25,7 @@ #define EVENT_PING 88 // "X" #define EVENT_PONG 89 // "Y" #define EVENT_RESET 90 // "Z" +#define EVENT_RUN 91 // RUN #define EVENT_NO_ERROR 98 // NO ERROR #define EVENT_ERROR 99 // ERROR diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 617533a..315ecdd 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -5,6 +5,7 @@ IOBoardController::IOBoardController(int cT) _eventDispatcher = new EventDispatcher(); _eventDispatcher->addListener(this, EVENT_CONFIGURATION); _eventDispatcher->addListener(this, EVENT_PING); + _eventDispatcher->addListener(this, EVENT_RUN); _eventDispatcher->addListener(this, EVENT_RESET); controllerType = cT; @@ -28,17 +29,20 @@ IOBoardController::IOBoardController(int cT) void IOBoardController::update() { - if (activeSwitches) + if (running) { - switches()->update(); - } - if (activeSwitchMatrix) - { - switchMatrix()->update(); - } - if (activePwmDevices) - { - pwmDevices()->update(); + if (activeSwitches) + { + switches()->update(); + } + if (activeSwitchMatrix) + { + switchMatrix()->update(); + } + if (activePwmDevices) + { + pwmDevices()->update(); + } } eventDispatcher()->update(); @@ -52,6 +56,10 @@ void IOBoardController::handleEvent(Event *event) _eventDispatcher->dispatch(new Event(EVENT_PONG, 1, boardId)); break; + case EVENT_RUN: + running = (bool)event->value; + break; + case EVENT_RESET: // @todo clear all configurations or reboot the device. break; diff --git a/src/IOBoardController.h b/src/IOBoardController.h index 0b5d404..7032d42 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -47,6 +47,7 @@ class IOBoardController : public EventListener Switches *_switches; SwitchMatrix *_switchMatrix; + bool running = false; bool activePwmDevices = false; bool activeSwitches = false; bool activeSwitchMatrix = false; diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index a6cbaa1..85553b4 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -4,15 +4,17 @@ void Switches::registerSwitch(byte p, byte n) { if (last < (MAX_SWITCHES - 1)) { - if (p >= 15 && p <= 18) { + if (p >= 15 && p <= 18) + { // Set mid power output as input. pinMode(p, OUTPUT); digitalWrite(p, HIGH); - delayMicroseconds(100); + delayMicroseconds(10); digitalWrite(p, LOW); - } - + } + pinMode(p, INPUT); + delayMicroseconds(10); port[++last] = p; number[last] = n; toggled[last] = false; @@ -67,13 +69,17 @@ void Switches::handleEvent(Event *event) // The CPU requested all current states. for (int i = 0; i <= last; i++) { - // Send all states of switches that haven't been toggled since last poll. + // Send all states of switches that haven't been toggled since last poll (and dispatched their event already). if (!toggled[i]) { - toggled[i] = true; _eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), state[i])); } + else + { + toggled[i] = false; + } } + _ms = millis(); break; } } From 75b79becf32b9de7b88acf64ec811736e31764b5 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 4 Jan 2024 11:50:27 +0100 Subject: [PATCH 029/102] updated header files --- src/EventDispatcher/Event.h | 61 ++++++++++++++++++++++--------------- src/PPUC.h | 6 +--- src/PPUCPlatforms.h | 14 +++++++++ 3 files changed, 52 insertions(+), 29 deletions(-) create mode 100644 src/PPUCPlatforms.h diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index f1b2d7e..5f50677 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -1,8 +1,6 @@ /* Event.h Created by Markus Kalkbrenner, 2021-2023. - - Play more pinball! */ #ifndef EVENT_h @@ -67,13 +65,13 @@ #define MATRIX_TYPE_COLUMN 1 // Column #define MATRIX_TYPE_ROW 2 // Row -struct Event { - byte sourceId; - word eventId; - byte value; +struct Event +{ + uint8_t sourceId; + uint16_t eventId; + uint8_t value; bool localFast; - - Event(byte sId) + Event(uint8_t sId) { sourceId = sId; eventId = 1; @@ -81,21 +79,23 @@ struct Event { localFast = false; } - Event(byte sId, word eId) { + Event(uint8_t sId, uint16_t eId) + { sourceId = sId; eventId = eId; value = 1; localFast = false; } - Event(byte sId, word eId, byte v) { + Event(uint8_t sId, uint16_t eId, uint8_t v) + { sourceId = sId; eventId = eId; value = v; localFast = false; } - Event(byte sId, word eId, byte v, bool lf) { + Event(uint8_t sId, uint16_t eId, uint8_t v, bool lf) { sourceId = sId; eventId = eId; value = v; @@ -110,26 +110,39 @@ struct Event { localFast = other->localFast; } - bool operator==(const Event &other) const { - return this->sourceId == other.sourceId - && this->eventId == other.eventId - && this->value == other.value; + bool operator==(const Event &other) const + { + return this->sourceId == other.sourceId && this->eventId == other.eventId && this->value == other.value; } - bool operator!=(const Event &other) const { + bool operator!=(const Event &other) const + { return !(*this == other); } }; -struct ConfigEvent { - byte sourceId = EVENT_CONFIGURATION; - byte boardId; // - byte topic; // lamps - byte index; // 0, index of assignment - byte key; // ledType, assignment/brightness - int value; // FFFF00FF +struct ConfigEvent +{ + uint8_t sourceId; // EVENT_CONFIGURATION + uint8_t boardId; // + uint8_t topic; // lamps + uint8_t index; // 0, index of assignment + uint8_t key; // ledType, assignment/brightness + uint32_t value; // FFFF00FF - ConfigEvent(char b, char t, char i, char k, int v) { + ConfigEvent(uint8_t b) + { + sourceId = EVENT_CONFIGURATION; + boardId = b; + topic = CONFIG_TOPIC_NULL; + index = 1; + key = 1; + value = 1; + } + + ConfigEvent(uint8_t b, uint8_t t, uint8_t i, uint8_t k, uint32_t v) + { + sourceId = EVENT_CONFIGURATION; boardId = b; topic = t; index = i; diff --git a/src/PPUC.h b/src/PPUC.h index 56130d2..fa12c33 100644 --- a/src/PPUC.h +++ b/src/PPUC.h @@ -7,6 +7,7 @@ #define PPUC_h #include +#include "PPUCPlatforms.h" #define CONTROLLER_MEGA_ALL_INPUT 1 #define CONTROLLER_TEENSY_OUTPUT 10 @@ -15,11 +16,6 @@ #define CONTROLLER_NANO_PIN2DMD_OUTPUT 30 #define CONTROLLER_16_8_1 40 -#define PLATFORM_WPC 1 -#define PLATFORM_DATA_EAST 2 -#define PLATFORM_SYS11 3 -#define PLATFORM_LIBPINMAME 100 - #include #endif diff --git a/src/PPUCPlatforms.h b/src/PPUCPlatforms.h new file mode 100644 index 0000000..745bb48 --- /dev/null +++ b/src/PPUCPlatforms.h @@ -0,0 +1,14 @@ +/** + PPUC.h + Created by Markus Kalkbrenner. +*/ + +#ifndef PPUC_PLATFORMS_h +#define PPUC_PLATFORMS_h + +#define PLATFORM_WPC 1 +#define PLATFORM_DATA_EAST 2 +#define PLATFORM_SYS11 3 +#define PLATFORM_LIBPINMAME 100 + +#endif From c5f1acec91a34dfe9b01e3e76d90323ef0456d26 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Fri, 12 Jan 2024 12:35:22 +0100 Subject: [PATCH 030/102] applied "google" clang format --- .clang-format | 258 ++++++ ...CombinedGiAndLightMatrixWS2812FXDevice.cpp | 750 ++++++++---------- .../CombinedGiAndLightMatrixWS2812FXDevice.h | 147 ++-- src/EffectDevices/Definitions.h | 66 +- src/EffectDevices/EffectDevice.cpp | 4 +- src/EffectDevices/EffectDevice.h | 10 +- src/EffectDevices/LedBuiltInDevice.cpp | 8 +- src/EffectDevices/LedBuiltInDevice.h | 11 +- src/EffectDevices/NullDevice.cpp | 6 +- src/EffectDevices/NullDevice.h | 8 +- src/EffectDevices/RgbPWMDevice.cpp | 32 +- src/EffectDevices/RgbStripDevice.h | 53 +- src/EffectDevices/WS2812FXDevice.cpp | 52 +- src/EffectDevices/WS2812FXDevice.h | 77 +- src/EffectDevices/WavePWMDevice.cpp | 20 +- src/EffectDevices/WavePWMDevice.h | 30 +- src/Effects/Effect.cpp | 65 +- src/Effects/Effect.h | 43 +- src/Effects/EffectContainer.h | 70 +- src/Effects/ImpulsePWMEffect.cpp | 20 +- src/Effects/ImpulsePWMEffect.h | 14 +- src/Effects/LedBlinkEffect.cpp | 43 +- src/Effects/LedBlinkEffect.h | 5 +- src/Effects/LedOnEffect.cpp | 4 +- src/Effects/LedOnEffect.h | 5 +- src/Effects/NullEffect.cpp | 4 +- src/Effects/NullEffect.h | 5 +- src/Effects/RGBColorCycleEffect.cpp | 103 ++- src/Effects/RGBColorCycleEffect.h | 16 +- src/Effects/RampDownStopPWMEffect.cpp | 35 +- src/Effects/RampDownStopPWMEffect.h | 15 +- src/Effects/SinePWMEffect.cpp | 50 +- src/Effects/SinePWMEffect.h | 27 +- src/Effects/WS2812FXEffect.cpp | 39 +- src/Effects/WS2812FXEffect.h | 73 +- src/Effects/WavePWMEffect.cpp | 14 +- src/Effects/WavePWMEffect.h | 38 +- src/EffectsController.cpp | 601 +++++++------- src/EffectsController.h | 684 ++++++++-------- src/EventDispatcher/CrossLinkDebugger.cpp | 99 ++- src/EventDispatcher/CrossLinkDebugger.h | 7 +- src/EventDispatcher/Event.h | 293 ++++--- src/EventDispatcher/EventDispatcher.cpp | 591 ++++++-------- src/EventDispatcher/EventDispatcher.h | 61 +- src/EventDispatcher/EventListener.h | 6 +- src/EventDispatcher/MultiCoreCrossLink.h | 130 ++- src/IOBoardController.cpp | 305 ++++--- src/IOBoardController.h | 68 +- src/IODevices/PwmDevices.cpp | 229 +++--- src/IODevices/PwmDevices.h | 75 +- src/IODevices/SwitchMatrix.cpp | 179 ++--- src/IODevices/SwitchMatrix.h | 90 +-- src/IODevices/Switches.cpp | 128 ++- src/IODevices/Switches.h | 42 +- src/InputController.cpp | 70 +- src/InputController.h | 48 +- .../DistributionControllerTestButtons.cpp | 34 +- .../DistributionControllerTestButtons.h | 12 +- .../EffectControllerTestButtons.cpp | 25 +- .../EffectControllerTestButtons.h | 12 +- src/InputDevices/GeneralIlluminationWPC.cpp | 220 +++-- src/InputDevices/GeneralIlluminationWPC.h | 90 +-- .../InputControllerTestButtons.cpp | 25 +- src/InputDevices/InputControllerTestButtons.h | 12 +- src/InputDevices/LightMatrix.cpp | 164 ++-- src/InputDevices/LightMatrix.h | 48 +- src/InputDevices/Matrix.cpp | 137 ++-- src/InputDevices/Matrix.h | 49 +- src/InputDevices/PIN2DMD.cpp | 93 ++- src/InputDevices/PIN2DMD.h | 21 +- src/InputDevices/Solenoids.cpp | 287 ++++--- src/InputDevices/Solenoids.h | 56 +- src/InputDevices/SwitchMatrix.cpp | 93 +-- src/InputDevices/SwitchMatrix.h | 93 ++- src/PPUC.h | 1 + src/VisualPinball/PUPComLink.cpp | 75 +- src/VisualPinball/PUPComLink.h | 50 +- src/VisualPinball/VPXComLink.cpp | 73 +- src/VisualPinball/VPXComLink.h | 23 +- test/IOBoardController/src/main.cpp | 15 +- test/IO_16_8_1/src/main.cpp | 173 ++-- test/InputController/src/main.cpp | 101 +-- test/NanoController/src/main.cpp | 57 +- 83 files changed, 3942 insertions(+), 4023 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..91e8793 --- /dev/null +++ b/.clang-format @@ -0,0 +1,258 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAfterAttributes: Never +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Attach +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*\.h>' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 3 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '([-_](test|unittest))?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 2 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: NextLine +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Leave +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + CanonicalDelimiter: pb + BasedOnStyle: google +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseTab: Never +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +... diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp index 79c7358..4b0ff17 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp @@ -1,477 +1,401 @@ #include "CombinedGiAndLightMatrixWS2812FXDevice.h" -void CombinedGiAndLightMatrixWS2812FXDevice::on() -{ - WS2812FXDevice::on(); - effectRunning = true; +void CombinedGiAndLightMatrixWS2812FXDevice::on() { + WS2812FXDevice::on(); + effectRunning = true; } -void CombinedGiAndLightMatrixWS2812FXDevice::off() -{ - effectRunning = false; - // No stop. Just reset to quit effects and return to standard GI and Light Matrix operation. - reset(); +void CombinedGiAndLightMatrixWS2812FXDevice::off() { + effectRunning = false; + // No stop. Just reset to quit effects and return to standard GI and Light + // Matrix operation. + reset(); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToGiString(uint8_t giString, int16_t led) -{ - assignLedToGiString(giString, led, ULTRAWHITE); +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToGiString( + uint8_t giString, int16_t led) { + assignLedToGiString(giString, led, ULTRAWHITE); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToGiString(uint8_t giString, int16_t led, uint32_t color) -{ - if (numLEDsGI[--giString] < _MAX_LEDS_GI_STRING) - { - ledGIPositions[giString][numLEDsGI[giString]] = led; - ledGIColors[giString][numLEDsGI[giString]++] = color; - } +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToGiString( + uint8_t giString, int16_t led, uint32_t color) { + if (numLEDsGI[--giString] < _MAX_LEDS_GI_STRING) { + ledGIPositions[giString][numLEDsGI[giString]] = led; + ledGIColors[giString][numLEDsGI[giString]++] = color; + } } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedRangeToGiString(uint8_t giString, int16_t first, int16_t last) -{ - for (int16_t i = first; i <= last; i++) - { - assignLedToGiString(giString, i); - } +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedRangeToGiString( + uint8_t giString, int16_t first, int16_t last) { + for (int16_t i = first; i <= last; i++) { + assignLedToGiString(giString, i); + } } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrix(uint8_t column, uint8_t row, int16_t led) -{ - assignLedToLightMatrix(column, row, led, ULTRAWHITE); +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrix( + uint8_t column, uint8_t row, int16_t led) { + assignLedToLightMatrix(column, row, led, ULTRAWHITE); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrix(uint8_t column, uint8_t row, int16_t led, uint32_t color) -{ - assignLedToLightMatrixDE(((column - 1) * 8) + row, led, color); +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrix( + uint8_t column, uint8_t row, int16_t led, uint32_t color) { + assignLedToLightMatrixDE(((column - 1) * 8) + row, led, color); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixWPC(uint8_t number, int16_t led) -{ - assignLedToLightMatrixWPC(number, led, ULTRAWHITE); - wpc = true; +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixWPC( + uint8_t number, int16_t led) { + assignLedToLightMatrixWPC(number, led, ULTRAWHITE); + wpc = true; } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixWPC(uint8_t number, int16_t led, uint32_t color) -{ - assignLedToLightMatrix(number / 10 % 10, number % 10, led, color); - wpc = true; +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixWPC( + uint8_t number, int16_t led, uint32_t color) { + assignLedToLightMatrix(number / 10 % 10, number % 10, led, color); + wpc = true; } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixSYS11(uint8_t number, int16_t led) -{ - assignLedToLightMatrixDE(number, led, ULTRAWHITE); +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixSYS11( + uint8_t number, int16_t led) { + assignLedToLightMatrixDE(number, led, ULTRAWHITE); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixSYS11(uint8_t number, int16_t led, uint32_t color) -{ - assignLedToLightMatrixDE(number, led, color); +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixSYS11( + uint8_t number, int16_t led, uint32_t color) { + assignLedToLightMatrixDE(number, led, color); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE(uint8_t number, int16_t led) -{ - assignLedToLightMatrixDE(number, led, ULTRAWHITE); +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE( + uint8_t number, int16_t led) { + assignLedToLightMatrixDE(number, led, ULTRAWHITE); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE(uint8_t number, int16_t led, uint32_t color) -{ - --number; - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) - { - if (ledLightMatrixPositions[number][i] == -1) - { - ledLightMatrixPositions[number][i] = led; - ledLightMatrixColors[number][i] = color; - break; - } +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE( + uint8_t number, int16_t led, uint32_t color) { + --number; + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { + if (ledLightMatrixPositions[number][i] == -1) { + ledLightMatrixPositions[number][i] = led; + ledLightMatrixColors[number][i] = color; + break; } + } } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToFlasher(uint8_t number, int16_t led, uint32_t color) -{ - for (int offset = 0; offset < _MAX_FLASHERS; offset++) - { - if (flasherNumber[offset] == number) - { - // Flasher already registered, add another LED to it. - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) - { - if (ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + offset][i] == -1) - { - ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + offset][i] = led; - ledLightMatrixColors[_LIGHT_MATRIX_SIZE + offset][i] = color; - break; - } - } - - return; +void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToFlasher( + uint8_t number, int16_t led, uint32_t color) { + for (int offset = 0; offset < _MAX_FLASHERS; offset++) { + if (flasherNumber[offset] == number) { + // Flasher already registered, add another LED to it. + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { + if (ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + offset][i] == -1) { + ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + offset][i] = led; + ledLightMatrixColors[_LIGHT_MATRIX_SIZE + offset][i] = color; + break; } - } + } - // Flasher not yet registered, find a free slot. - for (int f = _MAX_LEDS_PER_LIGHT; f < _MAX_LEDS_PER_LIGHT + _MAX_FLASHERS; f++) - { - if (ledLightMatrixPositions[f][0] == -1) - { - ledLightMatrixPositions[f][0] = led; - ledLightMatrixColors[f][0] = color; - flasherNumber[_MAX_LEDS_PER_LIGHT - f] = number; - return; - } + return; } + } + + // Flasher not yet registered, find a free slot. + for (int f = _MAX_LEDS_PER_LIGHT; f < _MAX_LEDS_PER_LIGHT + _MAX_FLASHERS; + f++) { + if (ledLightMatrixPositions[f][0] == -1) { + ledLightMatrixPositions[f][0] = led; + ledLightMatrixColors[f][0] = color; + flasherNumber[_MAX_LEDS_PER_LIGHT - f] = number; + return; + } + } } -void CombinedGiAndLightMatrixWS2812FXDevice::handleEvent(Event *event) -{ - if (!effectRunning) - { - if (event->sourceId == EVENT_SOURCE_GI) - { - uint8_t giString = event->eventId - 1; - // Brightness is a value between 0 and 8. Convert it into a value from 0 to 255. - uint8_t giBrightness = 0; - switch (event->value) - { - case 1: - giBrightness = 35; - break; - case 2: - giBrightness = 60; - break; - case 3: - giBrightness = 85; - break; - case 4: - giBrightness = 115; - break; - case 5: - giBrightness = 155; - break; - case 6: - giBrightness = 205; - break; - case 7: - case 8: - giBrightness = 255; - break; - } - - if (targetGIBrightness[giString] != giBrightness) - { - if ( - (targetGIBrightness[giString] < giBrightness && msHeatUp == 0) || - (targetGIBrightness[giString] > giBrightness && msAfterGlow == 0)) - { - for (int i = 0; i <= numLEDsGI[giString]; i++) - { - setDimmedPixelColor(ledGIPositions[giString][i], ledGIColors[giString][i], giBrightness); - } +void CombinedGiAndLightMatrixWS2812FXDevice::handleEvent(Event *event) { + if (!effectRunning) { + if (event->sourceId == EVENT_SOURCE_GI) { + uint8_t giString = event->eventId - 1; + // Brightness is a value between 0 and 8. Convert it into a value from 0 + // to 255. + uint8_t giBrightness = 0; + switch (event->value) { + case 1: + giBrightness = 35; + break; + case 2: + giBrightness = 60; + break; + case 3: + giBrightness = 85; + break; + case 4: + giBrightness = 115; + break; + case 5: + giBrightness = 155; + break; + case 6: + giBrightness = 205; + break; + case 7: + case 8: + giBrightness = 255; + break; + } + + if (targetGIBrightness[giString] != giBrightness) { + if ((targetGIBrightness[giString] < giBrightness && msHeatUp == 0) || + (targetGIBrightness[giString] > giBrightness && msAfterGlow == 0)) { + for (int i = 0; i <= numLEDsGI[giString]; i++) { + setDimmedPixelColor(ledGIPositions[giString][i], + ledGIColors[giString][i], giBrightness); + } + } else { + if (targetGIBrightness[giString] < giBrightness) { + if (heatUpGI[giString] == 0 && afterGlowGI[giString] == 0) { + heatUpGI[giString] = millis(); + } else if (afterGlowGI[giString] > 0) { + // There's still an after glow effect running. Start heat up from + // current value. + byte value = wavePWMAfterGlow->getExponentialValue( + millis() - afterGlowGI[giString] + msAfterGlow); + afterGlowGI[giString] = 0; + for (int ms = 1; ms <= msHeatUp; ms++) { + if (wavePWMHeatUp->getExponentialValue(ms) >= value) { + heatUpGI[giString] = millis() - ms; + break; } - else - { - if (targetGIBrightness[giString] < giBrightness) - { - if (heatUpGI[giString] == 0 && afterGlowGI[giString] == 0) - { - heatUpGI[giString] = millis(); - } - else if (afterGlowGI[giString] > 0) - { - // There's still an after glow effect running. Start heat up from current value. - byte value = wavePWMAfterGlow->getExponentialValue(millis() - afterGlowGI[giString] + msAfterGlow); - afterGlowGI[giString] = 0; - for (int ms = 1; ms <= msHeatUp; ms++) - { - if (wavePWMHeatUp->getExponentialValue(ms) >= value) - { - heatUpGI[giString] = millis() - ms; - break; - } - } - // safety net - if (heatUpGI[giString] == 0) - { - heatUpGI[giString] = millis() - msHeatUp + 1; - } - } - } - else - { - if (afterGlowGI[giString] == 0 && heatUpGI[giString] == 0) - { - afterGlowGI[giString] = millis(); - } - else if (heatUpGI[giString] > 0) - { - // There's still a heat up effect running. Start after glow from current value. - byte value = wavePWMHeatUp->getExponentialValue(millis() - heatUp[giString]); - heatUpGI[giString] = 0; - for (int ms = msAfterGlow; ms <= (msAfterGlow * 2); ms++) - { - if (wavePWMAfterGlow->getExponentialValue(ms) <= value) - { - afterGlowGI[giString] = millis() - ms; - break; - } - } - // safety net - if (afterGlowGI[giString] == 0) - { - afterGlowGI[giString] = millis() - (2 * msAfterGlow) + 1; - } - } - } + } + // safety net + if (heatUpGI[giString] == 0) { + heatUpGI[giString] = millis() - msHeatUp + 1; + } + } + } else { + if (afterGlowGI[giString] == 0 && heatUpGI[giString] == 0) { + afterGlowGI[giString] = millis(); + } else if (heatUpGI[giString] > 0) { + // There's still a heat up effect running. Start after glow from + // current value. + byte value = wavePWMHeatUp->getExponentialValue(millis() - + heatUp[giString]); + heatUpGI[giString] = 0; + for (int ms = msAfterGlow; ms <= (msAfterGlow * 2); ms++) { + if (wavePWMAfterGlow->getExponentialValue(ms) <= value) { + afterGlowGI[giString] = millis() - ms; + break; } - - sourceGIBrightness[giString] = targetGIBrightness[giString]; - targetGIBrightness[giString] = giBrightness; + } + // safety net + if (afterGlowGI[giString] == 0) { + afterGlowGI[giString] = millis() - (2 * msAfterGlow) + 1; + } } + } } - else if (event->sourceId == EVENT_SOURCE_LIGHT || event->sourceId == EVENT_SOURCE_SOLENOID) - { - uint8_t number = event->eventId; - - if (event->sourceId == EVENT_SOURCE_LIGHT) - { - if (wpc) - { - // WPC - uint8_t column = number / 10 % 10; - uint8_t row = number % 10; - number = ((column - 1) * 8) + row; - } - --number; - } - else - { - number = 255; - for (int offset = 0; offset < _MAX_FLASHERS; offset++) - { - if (flasherNumber[offset] == number) - { - number = _LIGHT_MATRIX_SIZE + offset; - break; - } - } + sourceGIBrightness[giString] = targetGIBrightness[giString]; + targetGIBrightness[giString] = giBrightness; + } + } else if (event->sourceId == EVENT_SOURCE_LIGHT || + event->sourceId == EVENT_SOURCE_SOLENOID) { + uint8_t number = event->eventId; + + if (event->sourceId == EVENT_SOURCE_LIGHT) { + if (wpc) { + // WPC + uint8_t column = number / 10 % 10; + uint8_t row = number % 10; + number = ((column - 1) * 8) + row; + } - if (number == 255) - { - // The solenoid isn't a registered falsher. - return; - } - } + --number; + } else { + number = 255; + for (int offset = 0; offset < _MAX_FLASHERS; offset++) { + if (flasherNumber[offset] == number) { + number = _LIGHT_MATRIX_SIZE + offset; + break; + } + } - bool on = (bool)event->value; - - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) - { - if (ledLightMatrixPositions[number][i] >= 0) - { - if (on && msHeatUp == 0) - { - ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], ledLightMatrixColors[number][i]); - } - else if (!on && msAfterGlow == 0) - { - ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], RGBW_BLACK); - } - else if (i == 0) - { - if (on) - { - if (heatUp[number] == 0 && afterGlow[number] == 0) - { - heatUp[number] = millis(); - } - else if (afterGlow[number] > 0) - { - // There's still an after glow effect running. Start heat up from current value. - byte value = wavePWMAfterGlow->getExponentialValue(millis() - afterGlow[number] + msAfterGlow); - afterGlow[number] = 0; - for (int ms = 1; ms <= msHeatUp; ms++) - { - if (wavePWMHeatUp->getExponentialValue(ms) >= value) - { - heatUp[number] = millis() - ms; - break; - } - } - // safety net - if (heatUp[number] == 0) - { - heatUp[number] = millis() - msHeatUp + 1; - } - } - } - else - { - if (afterGlow[number] == 0 && heatUp[number] == 0) - { - afterGlow[number] = millis(); - } - else if (heatUp[number] > 0) - { - // There's still a heat up effect running. Start after glow from current value. - byte value = wavePWMHeatUp->getExponentialValue(millis() - heatUp[number]); - heatUp[number] = 0; - for (int ms = msAfterGlow; ms <= (msAfterGlow * 2); ms++) - { - if (wavePWMAfterGlow->getExponentialValue(ms) <= value) - { - afterGlow[number] = millis() - ms; - break; - } - } - // safety net - if (afterGlow[number] == 0) - { - afterGlow[number] = millis() - (2 * msAfterGlow) + 1; - } - } - } - - // terminate the loop - return; - } + if (number == 255) { + // The solenoid isn't a registered falsher. + return; + } + } + + bool on = (bool)event->value; + + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { + if (ledLightMatrixPositions[number][i] >= 0) { + if (on && msHeatUp == 0) { + ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], + ledLightMatrixColors[number][i]); + } else if (!on && msAfterGlow == 0) { + ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], + RGBW_BLACK); + } else if (i == 0) { + if (on) { + if (heatUp[number] == 0 && afterGlow[number] == 0) { + heatUp[number] = millis(); + } else if (afterGlow[number] > 0) { + // There's still an after glow effect running. Start heat up + // from current value. + byte value = wavePWMAfterGlow->getExponentialValue( + millis() - afterGlow[number] + msAfterGlow); + afterGlow[number] = 0; + for (int ms = 1; ms <= msHeatUp; ms++) { + if (wavePWMHeatUp->getExponentialValue(ms) >= value) { + heatUp[number] = millis() - ms; + break; + } + } + // safety net + if (heatUp[number] == 0) { + heatUp[number] = millis() - msHeatUp + 1; } + } + } else { + if (afterGlow[number] == 0 && heatUp[number] == 0) { + afterGlow[number] = millis(); + } else if (heatUp[number] > 0) { + // There's still a heat up effect running. Start after glow from + // current value. + byte value = wavePWMHeatUp->getExponentialValue(millis() - + heatUp[number]); + heatUp[number] = 0; + for (int ms = msAfterGlow; ms <= (msAfterGlow * 2); ms++) { + if (wavePWMAfterGlow->getExponentialValue(ms) <= value) { + afterGlow[number] = millis() - ms; + break; + } + } + // safety net + if (afterGlow[number] == 0) { + afterGlow[number] = millis() - (2 * msAfterGlow) + 1; + } + } } + + // terminate the loop + return; + } } + } } + } } -void CombinedGiAndLightMatrixWS2812FXDevice::updateAfterGlow() -{ - for (uint8_t giString = 0; giString < NUM_GI_STRINGS; giString++) - { - uint8_t glowBrightness = targetGIBrightness[giString]; - if (heatUpGI[giString] > 0) - { - if ((millis() - heatUpGI[giString]) >= msHeatUp) - { - heatUpGI[giString] = 0; - } - else - { - float diff = targetGIBrightness[giString] - sourceGIBrightness[giString]; - float mult = diff / 255; - glowBrightness = sourceGIBrightness[giString] + (wavePWMHeatUp->getExponentialValue(millis() - heatUpGI[giString]) * mult); - } - } - else if (afterGlowGI[giString] > 0) - { - if ((millis() - afterGlowGI[giString]) >= msAfterGlow) - { - afterGlowGI[giString] = 0; - } - else - { - float diff = sourceGIBrightness[giString] - targetGIBrightness[giString]; - float mult = diff / 255; - glowBrightness = targetGIBrightness[giString] + (wavePWMAfterGlow->getExponentialValue(millis() - afterGlowGI[giString] + msAfterGlow) * mult); - } - } - else - { - continue; - } - - for (int i = 0; i < numLEDsGI[giString]; i++) - { - if (ledGIPositions[giString][i] != -1) - { - setDimmedPixelColor(ledGIPositions[giString][i], ledGIColors[giString][i], glowBrightness); - } - } +void CombinedGiAndLightMatrixWS2812FXDevice::updateAfterGlow() { + for (uint8_t giString = 0; giString < NUM_GI_STRINGS; giString++) { + uint8_t glowBrightness = targetGIBrightness[giString]; + if (heatUpGI[giString] > 0) { + if ((millis() - heatUpGI[giString]) >= msHeatUp) { + heatUpGI[giString] = 0; + } else { + float diff = + targetGIBrightness[giString] - sourceGIBrightness[giString]; + float mult = diff / 255; + glowBrightness = + sourceGIBrightness[giString] + + (wavePWMHeatUp->getExponentialValue(millis() - heatUpGI[giString]) * + mult); + } + } else if (afterGlowGI[giString] > 0) { + if ((millis() - afterGlowGI[giString]) >= msAfterGlow) { + afterGlowGI[giString] = 0; + } else { + float diff = + sourceGIBrightness[giString] - targetGIBrightness[giString]; + float mult = diff / 255; + glowBrightness = targetGIBrightness[giString] + + (wavePWMAfterGlow->getExponentialValue( + millis() - afterGlowGI[giString] + msAfterGlow) * + mult); + } + } else { + continue; } - for (uint8_t number = 0; number < _LIGHT_MATRIX_SIZE + _MAX_FLASHERS; number++) - { - uint8_t glowBrightness; - if (heatUp[number] > 0) - { - if ((millis() - heatUp[number]) >= msHeatUp) - { - heatUp[number] = 0; - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) - { - if (ledLightMatrixPositions[number][i] != -1) - { - ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], ledLightMatrixColors[number][i]); - } - } - } - else - { - glowBrightness = wavePWMHeatUp->getExponentialValue(millis() - heatUp[number]); - } + for (int i = 0; i < numLEDsGI[giString]; i++) { + if (ledGIPositions[giString][i] != -1) { + setDimmedPixelColor(ledGIPositions[giString][i], + ledGIColors[giString][i], glowBrightness); + } + } + } + + for (uint8_t number = 0; number < _LIGHT_MATRIX_SIZE + _MAX_FLASHERS; + number++) { + uint8_t glowBrightness; + if (heatUp[number] > 0) { + if ((millis() - heatUp[number]) >= msHeatUp) { + heatUp[number] = 0; + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { + if (ledLightMatrixPositions[number][i] != -1) { + ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], + ledLightMatrixColors[number][i]); + } } - else if (afterGlow[number] > 0) - { - if ((millis() - afterGlow[number]) >= msAfterGlow) - { - afterGlow[number] = 0; - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) - { - if (ledLightMatrixPositions[number][i] != -1) - { - ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], RGBW_BLACK); - } - } - } - else - { - glowBrightness = wavePWMAfterGlow->getExponentialValue(millis() - afterGlow[number] + msAfterGlow); - } + } else { + glowBrightness = + wavePWMHeatUp->getExponentialValue(millis() - heatUp[number]); + } + } else if (afterGlow[number] > 0) { + if ((millis() - afterGlow[number]) >= msAfterGlow) { + afterGlow[number] = 0; + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { + if (ledLightMatrixPositions[number][i] != -1) { + ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], + RGBW_BLACK); + } } + } else { + glowBrightness = wavePWMAfterGlow->getExponentialValue( + millis() - afterGlow[number] + msAfterGlow); + } + } - if (heatUp[number] > 0 || afterGlow[number] > 0) - { - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) - { - if (ledLightMatrixPositions[number][i] != -1) - { - setDimmedPixelColor(ledLightMatrixPositions[number][i], ledLightMatrixColors[number][i], glowBrightness); - } - } + if (heatUp[number] > 0 || afterGlow[number] > 0) { + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { + if (ledLightMatrixPositions[number][i] != -1) { + setDimmedPixelColor(ledLightMatrixPositions[number][i], + ledLightMatrixColors[number][i], glowBrightness); } + } } + } } -void CombinedGiAndLightMatrixWS2812FXDevice::setDimmedPixelColor(int16_t led, uint32_t color, uint8_t brightness) -{ - uint8_t w = (color >> 24) & 0xFF; - uint8_t r = (color >> 16) & 0xFF; - uint8_t g = (color >> 8) & 0xFF; - uint8_t b = color & 0xFF; - - // uint32_t for more space during the operation - uint32_t mult = brightness + 1; - b = (b * mult) >> 8; - g = (g * mult) >> 8; - r = (r * mult) >> 8; - w = (w * mult) >> 8; - - ws2812FX->setPixelColor(led, r, g, b, w); +void CombinedGiAndLightMatrixWS2812FXDevice::setDimmedPixelColor( + int16_t led, uint32_t color, uint8_t brightness) { + uint8_t w = (color >> 24) & 0xFF; + uint8_t r = (color >> 16) & 0xFF; + uint8_t g = (color >> 8) & 0xFF; + uint8_t b = color & 0xFF; + + // uint32_t for more space during the operation + uint32_t mult = brightness + 1; + b = (b * mult) >> 8; + g = (g * mult) >> 8; + r = (r * mult) >> 8; + w = (w * mult) >> 8; + + ws2812FX->setPixelColor(led, r, g, b, w); } -void CombinedGiAndLightMatrixWS2812FXDevice::setHeatUp() -{ - setHeatUp(30); -} +void CombinedGiAndLightMatrixWS2812FXDevice::setHeatUp() { setHeatUp(30); } -void CombinedGiAndLightMatrixWS2812FXDevice::setAfterGlow() -{ - setAfterGlow(400); +void CombinedGiAndLightMatrixWS2812FXDevice::setAfterGlow() { + setAfterGlow(400); } -void CombinedGiAndLightMatrixWS2812FXDevice::setHeatUp(int ms) -{ - wavePWMHeatUp->setup(ms * 2); - msHeatUp = ms; +void CombinedGiAndLightMatrixWS2812FXDevice::setHeatUp(int ms) { + wavePWMHeatUp->setup(ms * 2); + msHeatUp = ms; } -void CombinedGiAndLightMatrixWS2812FXDevice::setAfterGlow(int ms) -{ - wavePWMAfterGlow->setup(ms * 2); - msAfterGlow = ms; +void CombinedGiAndLightMatrixWS2812FXDevice::setAfterGlow(int ms) { + wavePWMAfterGlow->setup(ms * 2); + msAfterGlow = ms; } diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h index d6f6637..7305620 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h @@ -49,108 +49,111 @@ #include #include -#include "WS2812FXDevice.h" #include "../EventDispatcher/Event.h" #include "../EventDispatcher/EventDispatcher.h" #include "../EventDispatcher/EventListener.h" #include "../InputDevices/GeneralIlluminationWPC.h" +#include "WS2812FXDevice.h" #define _MAX_LEDS_GI_STRING 50 #define _LIGHT_MATRIX_SIZE 64 #define _MAX_LEDS_PER_LIGHT 3 #define _MAX_FLASHERS 12 -class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, public EventListener -{ -public: - CombinedGiAndLightMatrixWS2812FXDevice(WS2812FX *ws2812FX, int firstLED, int lastLED, int firstSegment, int lastSegment, EventDispatcher * eventDispatcher) : WS2812FXDevice(ws2812FX, firstLED, lastLED, firstSegment, lastSegment) - { - wavePWMHeatUp = new WavePWM(); - wavePWMAfterGlow = new WavePWM(); - afterGlowSupport = true; - for (int number = 0; number < NUM_GI_STRINGS; number++) - { - for (int i = 0; i < _MAX_LEDS_GI_STRING; i++) - { - ledGIPositions[number][i] = -1; - } - } - for (int number = 0; number < _LIGHT_MATRIX_SIZE + _MAX_FLASHERS; number++) - { - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) - { - ledLightMatrixPositions[number][i] = -1; - } - } - - eventDispatcher->addListener(this, EVENT_SOURCE_GI); - eventDispatcher->addListener(this, EVENT_SOURCE_SOLENOID); // Flasher - eventDispatcher->addListener(this, EVENT_SOURCE_LIGHT); +class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, + public EventListener { + public: + CombinedGiAndLightMatrixWS2812FXDevice(WS2812FX *ws2812FX, int firstLED, + int lastLED, int firstSegment, + int lastSegment, + EventDispatcher *eventDispatcher) + : WS2812FXDevice(ws2812FX, firstLED, lastLED, firstSegment, lastSegment) { + wavePWMHeatUp = new WavePWM(); + wavePWMAfterGlow = new WavePWM(); + afterGlowSupport = true; + for (int number = 0; number < NUM_GI_STRINGS; number++) { + for (int i = 0; i < _MAX_LEDS_GI_STRING; i++) { + ledGIPositions[number][i] = -1; + } } + for (int number = 0; number < _LIGHT_MATRIX_SIZE + _MAX_FLASHERS; + number++) { + for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { + ledLightMatrixPositions[number][i] = -1; + } + } + + eventDispatcher->addListener(this, EVENT_SOURCE_GI); + eventDispatcher->addListener(this, EVENT_SOURCE_SOLENOID); // Flasher + eventDispatcher->addListener(this, EVENT_SOURCE_LIGHT); + } - void on(); - void off(); + void on(); + void off(); - void assignLedToGiString(uint8_t giString, int16_t led); - void assignLedToGiString(uint8_t giString, int16_t led, uint32_t color); + void assignLedToGiString(uint8_t giString, int16_t led); + void assignLedToGiString(uint8_t giString, int16_t led, uint32_t color); - void assignLedRangeToGiString(uint8_t giString, int16_t first, int16_t last); + void assignLedRangeToGiString(uint8_t giString, int16_t first, int16_t last); - void assignLedToLightMatrix(uint8_t column, uint8_t row, int16_t led); - void assignLedToLightMatrix(uint8_t column, uint8_t row, int16_t led, uint32_t color); + void assignLedToLightMatrix(uint8_t column, uint8_t row, int16_t led); + void assignLedToLightMatrix(uint8_t column, uint8_t row, int16_t led, + uint32_t color); - void assignLedToLightMatrixWPC(uint8_t number, int16_t led); - void assignLedToLightMatrixWPC(uint8_t number, int16_t led, uint32_t color); + void assignLedToLightMatrixWPC(uint8_t number, int16_t led); + void assignLedToLightMatrixWPC(uint8_t number, int16_t led, uint32_t color); - void assignLedToLightMatrixDE(uint8_t number, int16_t led); - void assignLedToLightMatrixDE(uint8_t number, int16_t led, uint32_t color); + void assignLedToLightMatrixDE(uint8_t number, int16_t led); + void assignLedToLightMatrixDE(uint8_t number, int16_t led, uint32_t color); - void assignLedToLightMatrixSYS11(uint8_t number, int16_t led); - void assignLedToLightMatrixSYS11(uint8_t number, int16_t led, uint32_t color); + void assignLedToLightMatrixSYS11(uint8_t number, int16_t led); + void assignLedToLightMatrixSYS11(uint8_t number, int16_t led, uint32_t color); - void assignLedToFlasher(uint8_t number, int16_t led, uint32_t color); + void assignLedToFlasher(uint8_t number, int16_t led, uint32_t color); - void setDimmedPixelColor(int16_t led, uint32_t color, uint8_t brightness); + void setDimmedPixelColor(int16_t led, uint32_t color, uint8_t brightness); - void setHeatUp(); - void setAfterGlow(); + void setHeatUp(); + void setAfterGlow(); - void setHeatUp(int ms); - void setAfterGlow(int ms); + void setHeatUp(int ms); + void setAfterGlow(int ms); - void handleEvent(Event *event); - void handleEvent(ConfigEvent *event) {} - void updateAfterGlow(); + void handleEvent(Event *event); + void handleEvent(ConfigEvent *event) {} + void updateAfterGlow(); -protected: - int16_t numLEDsGI[NUM_GI_STRINGS] = {0}; + protected: + int16_t numLEDsGI[NUM_GI_STRINGS] = {0}; - int16_t ledGIPositions[NUM_GI_STRINGS][_MAX_LEDS_GI_STRING] = {{0}}; - uint32_t ledGIColors[NUM_GI_STRINGS][_MAX_LEDS_GI_STRING] = {{0}}; - uint8_t sourceGIBrightness[NUM_GI_STRINGS] = {0}; - uint8_t targetGIBrightness[NUM_GI_STRINGS] = {0}; + int16_t ledGIPositions[NUM_GI_STRINGS][_MAX_LEDS_GI_STRING] = {{0}}; + uint32_t ledGIColors[NUM_GI_STRINGS][_MAX_LEDS_GI_STRING] = {{0}}; + uint8_t sourceGIBrightness[NUM_GI_STRINGS] = {0}; + uint8_t targetGIBrightness[NUM_GI_STRINGS] = {0}; - // Internally we store the positions in Data East numbering from 1 to 64. - // The WPC-specific functions convert the WPC-specific numbering. - int16_t ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS][_MAX_LEDS_PER_LIGHT] = {{0}}; - uint32_t ledLightMatrixColors[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS][_MAX_LEDS_PER_LIGHT] = {{0}}; + // Internally we store the positions in Data East numbering from 1 to 64. + // The WPC-specific functions convert the WPC-specific numbering. + int16_t ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS] + [_MAX_LEDS_PER_LIGHT] = {{0}}; + uint32_t ledLightMatrixColors[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS] + [_MAX_LEDS_PER_LIGHT] = {{0}}; - uint8_t flasherNumber[_MAX_FLASHERS] = {0}; + uint8_t flasherNumber[_MAX_FLASHERS] = {0}; - WavePWM *wavePWMHeatUp; - WavePWM *wavePWMAfterGlow; + WavePWM *wavePWMHeatUp; + WavePWM *wavePWMAfterGlow; - // When no effects are running, we're in normal GI and Light Matrix mode. - bool stopped = false; // Never stop the updates. - bool effectRunning = false; - bool wpc = false; + // When no effects are running, we're in normal GI and Light Matrix mode. + bool stopped = false; // Never stop the updates. + bool effectRunning = false; + bool wpc = false; - int16_t msHeatUp = 0; - int16_t msAfterGlow = 0; - uint32_t heatUpGI[NUM_GI_STRINGS] = {0}; - uint32_t afterGlowGI[NUM_GI_STRINGS] = {0}; - uint32_t heatUp[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS] = {0}; - uint32_t afterGlow[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS] = {0}; + int16_t msHeatUp = 0; + int16_t msAfterGlow = 0; + uint32_t heatUpGI[NUM_GI_STRINGS] = {0}; + uint32_t afterGlowGI[NUM_GI_STRINGS] = {0}; + uint32_t heatUp[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS] = {0}; + uint32_t afterGlow[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS] = {0}; }; #endif diff --git a/src/EffectDevices/Definitions.h b/src/EffectDevices/Definitions.h index 6e5f9f0..f8f44c2 100644 --- a/src/EffectDevices/Definitions.h +++ b/src/EffectDevices/Definitions.h @@ -6,42 +6,42 @@ #ifndef Definitions_h #define Definitions_h -#if defined(__IMXRT1062__) // Teensy 4.1 - #include +#if defined(__IMXRT1062__) // Teensy 4.1 +#include #else - #include +#include - #define WS2812_RGB NEO_RGB - #define WS2812_RBG NEO_RBG - #define WS2812_GBR NEO_GBR - #define WS2812_GRB NEO_GRB - #define WS2812_BRG NEO_BRG - #define WS2812_BGR NEO_BGR +#define WS2812_RGB NEO_RGB +#define WS2812_RBG NEO_RBG +#define WS2812_GBR NEO_GBR +#define WS2812_GRB NEO_GRB +#define WS2812_BRG NEO_BRG +#define WS2812_BGR NEO_BGR - #define WS2812_RGBW NEO_RGBW - #define WS2812_RBGW NEO_RBGW - #define WS2812_GBRW NEO_GBRW - #define WS2812_GRBW NEO_GRBW - #define WS2812_BRGW NEO_BRGW - #define WS2812_BGRW NEO_BGRW - #define WS2812_WRGB NEO_WRGB - #define WS2812_WRBG NEO_WRBG - #define WS2812_WGRB NEO_WGRB - #define WS2812_WGBR NEO_WGBR - #define WS2812_WBRG NEO_WBRG - #define WS2812_WBGR NEO_WBGR - #define WS2812_RWGB NEO_RWGB - #define WS2812_RWBG NEO_RWBG - #define WS2812_GWRB NEO_GWRB - #define WS2812_GWBR NEO_GWBR - #define WS2812_BWRG NEO_BWRG - #define WS2812_BWGR NEO_BWGR - #define WS2812_RGWB NEO_RGWB - #define WS2812_RBWG NEO_RBWG - #define WS2812_GRWB NEO_GRWB - #define WS2812_GBWR NEO_GBWR - #define WS2812_BRWG NEO_BRWG - #define WS2812_BGWR NEO_BGWR +#define WS2812_RGBW NEO_RGBW +#define WS2812_RBGW NEO_RBGW +#define WS2812_GBRW NEO_GBRW +#define WS2812_GRBW NEO_GRBW +#define WS2812_BRGW NEO_BRGW +#define WS2812_BGRW NEO_BGRW +#define WS2812_WRGB NEO_WRGB +#define WS2812_WRBG NEO_WRBG +#define WS2812_WGRB NEO_WGRB +#define WS2812_WGBR NEO_WGBR +#define WS2812_WBRG NEO_WBRG +#define WS2812_WBGR NEO_WBGR +#define WS2812_RWGB NEO_RWGB +#define WS2812_RWBG NEO_RWBG +#define WS2812_GWRB NEO_GWRB +#define WS2812_GWBR NEO_GWBR +#define WS2812_BWRG NEO_BWRG +#define WS2812_BWGR NEO_BWGR +#define WS2812_RGWB NEO_RGWB +#define WS2812_RBWG NEO_RBWG +#define WS2812_GRWB NEO_GRWB +#define WS2812_GBWR NEO_GBWR +#define WS2812_BRWG NEO_BRWG +#define WS2812_BGWR NEO_BGWR #endif diff --git a/src/EffectDevices/EffectDevice.cpp b/src/EffectDevices/EffectDevice.cpp index 1057f6f..f922a25 100644 --- a/src/EffectDevices/EffectDevice.cpp +++ b/src/EffectDevices/EffectDevice.cpp @@ -1,5 +1,3 @@ #include "EffectDevice.h" -void EffectDevice::off() { - reset(); -} +void EffectDevice::off() { reset(); } diff --git a/src/EffectDevices/EffectDevice.h b/src/EffectDevices/EffectDevice.h index 6fd0676..4dea4e7 100644 --- a/src/EffectDevices/EffectDevice.h +++ b/src/EffectDevices/EffectDevice.h @@ -9,14 +9,14 @@ #define EFFECTDEVICE_h class EffectDevice { -public: - virtual void reset() = 0; + public: + virtual void reset() = 0; - virtual void on() = 0; + virtual void on() = 0; - virtual void off(); + virtual void off(); - virtual ~EffectDevice() {} + virtual ~EffectDevice() {} }; #endif diff --git a/src/EffectDevices/LedBuiltInDevice.cpp b/src/EffectDevices/LedBuiltInDevice.cpp index 574a41a..a5202c4 100644 --- a/src/EffectDevices/LedBuiltInDevice.cpp +++ b/src/EffectDevices/LedBuiltInDevice.cpp @@ -1,9 +1,5 @@ #include "LedBuiltInDevice.h" -void LedBuiltInDevice::on() { - digitalWrite(LED_BUILTIN, HIGH); -} +void LedBuiltInDevice::on() { digitalWrite(LED_BUILTIN, HIGH); } -void LedBuiltInDevice::reset() { - digitalWrite(LED_BUILTIN, LOW); -} +void LedBuiltInDevice::reset() { digitalWrite(LED_BUILTIN, LOW); } diff --git a/src/EffectDevices/LedBuiltInDevice.h b/src/EffectDevices/LedBuiltInDevice.h index f54f368..ad95d57 100644 --- a/src/EffectDevices/LedBuiltInDevice.h +++ b/src/EffectDevices/LedBuiltInDevice.h @@ -13,15 +13,12 @@ #include "EffectDevice.h" class LedBuiltInDevice : public EffectDevice { -public: - LedBuiltInDevice() { - pinMode(LED_BUILTIN, OUTPUT); - } + public: + LedBuiltInDevice() { pinMode(LED_BUILTIN, OUTPUT); } - void on(); - - void reset(); + void on(); + void reset(); }; #endif diff --git a/src/EffectDevices/NullDevice.cpp b/src/EffectDevices/NullDevice.cpp index 7a51026..4ea05e5 100644 --- a/src/EffectDevices/NullDevice.cpp +++ b/src/EffectDevices/NullDevice.cpp @@ -1,7 +1,5 @@ #include "NullDevice.h" -void NullDevice::on() { -} +void NullDevice::on() {} -void NullDevice::reset() { -} +void NullDevice::reset() {} diff --git a/src/EffectDevices/NullDevice.h b/src/EffectDevices/NullDevice.h index 1e25976..db9a3c6 100644 --- a/src/EffectDevices/NullDevice.h +++ b/src/EffectDevices/NullDevice.h @@ -13,12 +13,10 @@ #include "EffectDevice.h" class NullDevice : public EffectDevice { -public: - - void on(); - - void reset(); + public: + void on(); + void reset(); }; #endif diff --git a/src/EffectDevices/RgbPWMDevice.cpp b/src/EffectDevices/RgbPWMDevice.cpp index 7f7406c..dbaefae 100644 --- a/src/EffectDevices/RgbPWMDevice.cpp +++ b/src/EffectDevices/RgbPWMDevice.cpp @@ -1,33 +1,21 @@ #include "RgbStripDevice.h" void RgbStripDevice::setPWM(uint8_t pwm) { - setPWMRed(pwm); - setPWMGreen(pwm); - setPWMBlue(pwm); + setPWMRed(pwm); + setPWMGreen(pwm); + setPWMBlue(pwm); - currentPWM = pwm; + currentPWM = pwm; } -void RgbStripDevice::setPWMRed(uint8_t pwm) { - analogWrite(pin, pwm); -} +void RgbStripDevice::setPWMRed(uint8_t pwm) { analogWrite(pin, pwm); } -void RgbStripDevice::setPWMGreen(uint8_t pwm) { - analogWrite(pinGreen, pwm); -} +void RgbStripDevice::setPWMGreen(uint8_t pwm) { analogWrite(pinGreen, pwm); } -void RgbStripDevice::setPWMBlue(uint8_t pwm) { - analogWrite(pinBlue, pwm); -} +void RgbStripDevice::setPWMBlue(uint8_t pwm) { analogWrite(pinBlue, pwm); } -WavePWM* RgbStripDevice::getWavePWMRed() { - return wavePWM; -} +WavePWM* RgbStripDevice::getWavePWMRed() { return wavePWM; } -WavePWM* RgbStripDevice::getWavePWMGreen() { - return wavePWMGreen; -} +WavePWM* RgbStripDevice::getWavePWMGreen() { return wavePWMGreen; } -WavePWM* RgbStripDevice::getWavePWMBlue() { - return wavePWMBlue; -} +WavePWM* RgbStripDevice::getWavePWMBlue() { return wavePWMBlue; } diff --git a/src/EffectDevices/RgbStripDevice.h b/src/EffectDevices/RgbStripDevice.h index 027b66f..b2f13d7 100644 --- a/src/EffectDevices/RgbStripDevice.h +++ b/src/EffectDevices/RgbStripDevice.h @@ -14,32 +14,33 @@ #include "WavePWMDevice.h" class RgbStripDevice : public WavePWMDevice { -public: - RgbStripDevice(int pinRed, int pinGreen, int pinBlue) : WavePWMDevice(pinRed){ - this->wavePWMGreen = new WavePWM(); - this->wavePWMBlue = new WavePWM(); - this->pinGreen = pinGreen; - this->pinBlue = pinBlue; - pinMode(pinGreen, OUTPUT); - pinMode(pinBlue, OUTPUT); - } - - void setPWM(uint8_t pwm); - - void setPWMRed(uint8_t pwm); - void setPWMGreen(uint8_t pwm); - void setPWMBlue(uint8_t pwm); - - WavePWM* getWavePWMRed(); - WavePWM* getWavePWMGreen(); - WavePWM* getWavePWMBlue(); - -protected: - WavePWM* wavePWMGreen; - WavePWM* wavePWMBlue; - - int pinGreen; - int pinBlue; + public: + RgbStripDevice(int pinRed, int pinGreen, int pinBlue) + : WavePWMDevice(pinRed) { + this->wavePWMGreen = new WavePWM(); + this->wavePWMBlue = new WavePWM(); + this->pinGreen = pinGreen; + this->pinBlue = pinBlue; + pinMode(pinGreen, OUTPUT); + pinMode(pinBlue, OUTPUT); + } + + void setPWM(uint8_t pwm); + + void setPWMRed(uint8_t pwm); + void setPWMGreen(uint8_t pwm); + void setPWMBlue(uint8_t pwm); + + WavePWM* getWavePWMRed(); + WavePWM* getWavePWMGreen(); + WavePWM* getWavePWMBlue(); + + protected: + WavePWM* wavePWMGreen; + WavePWM* wavePWMBlue; + + int pinGreen; + int pinBlue; }; #endif diff --git a/src/EffectDevices/WS2812FXDevice.cpp b/src/EffectDevices/WS2812FXDevice.cpp index f4eb0f0..09ee37c 100644 --- a/src/EffectDevices/WS2812FXDevice.cpp +++ b/src/EffectDevices/WS2812FXDevice.cpp @@ -1,57 +1,39 @@ #include "WS2812FXDevice.h" void WS2812FXDevice::on() { - reset(); - stopped = false; + reset(); + stopped = false; } void WS2812FXDevice::off() { - reset(); - stopped = true; + reset(); + stopped = true; } void WS2812FXDevice::reset() { - ws2812FX->setSegment(firstSegment, firstLED, lastLED, FX_MODE_STATIC, RGBW_BLACK, 1, NO_OPTIONS); + ws2812FX->setSegment(firstSegment, firstLED, lastLED, FX_MODE_STATIC, + RGBW_BLACK, 1, NO_OPTIONS); } -WS2812FX* WS2812FXDevice::getWS2812FX() { - return ws2812FX; -} +WS2812FX* WS2812FXDevice::getWS2812FX() { return ws2812FX; } -int WS2812FXDevice::getFirstLED() { - return firstLED; -} +int WS2812FXDevice::getFirstLED() { return firstLED; } -int WS2812FXDevice::getlastLED() { - return lastLED; -} +int WS2812FXDevice::getlastLED() { return lastLED; } -int WS2812FXDevice::getNumLEDs() { - return lastLED - firstLED + 1; -} +int WS2812FXDevice::getNumLEDs() { return lastLED - firstLED + 1; } -int WS2812FXDevice::getFirstSegment() { - return firstSegment; -} +int WS2812FXDevice::getFirstSegment() { return firstSegment; } -int WS2812FXDevice::getLastSegment() { - return lastSegment; -} +int WS2812FXDevice::getLastSegment() { return lastSegment; } -int WS2812FXDevice::getNumSegments() { - return lastSegment - firstSegment + 1; -} +int WS2812FXDevice::getNumSegments() { return lastSegment - firstSegment + 1; } -bool WS2812FXDevice::isStopped() { - return stopped; -} +bool WS2812FXDevice::isStopped() { return stopped; } void WS2812FXDevice::setBrightness(byte b) { - brightness = b; - ws2812FX->setBrightness(brightness); -} - -byte WS2812FXDevice::getBrightness() { - return brightness; + brightness = b; + ws2812FX->setBrightness(brightness); } +byte WS2812FXDevice::getBrightness() { return brightness; } diff --git a/src/EffectDevices/WS2812FXDevice.h b/src/EffectDevices/WS2812FXDevice.h index 196399b..e011599 100644 --- a/src/EffectDevices/WS2812FXDevice.h +++ b/src/EffectDevices/WS2812FXDevice.h @@ -13,62 +13,61 @@ #include "EffectDevice.h" -#define RGBW_BLACK (uint32_t)0x00000000 -#define RGBW_PUREWHITE (uint32_t)0xFF000000 +#define RGBW_BLACK (uint32_t)0x00000000 +#define RGBW_PUREWHITE (uint32_t)0xFF000000 #define RGBW_ULTRAWHITE (uint32_t)0xFFFFFFFF class WS2812FXDevice : public EffectDevice { -public: - WS2812FXDevice(WS2812FX* ws2812FX, int firstLED, int lastLED, int firstSegment, int lastSegment) { - this->ws2812FX = ws2812FX; - this->firstLED = firstLED; - this->lastLED = lastLED; - this->firstSegment = firstSegment; - this->lastSegment = lastSegment; - } + public: + WS2812FXDevice(WS2812FX* ws2812FX, int firstLED, int lastLED, + int firstSegment, int lastSegment) { + this->ws2812FX = ws2812FX; + this->firstLED = firstLED; + this->lastLED = lastLED; + this->firstSegment = firstSegment; + this->lastSegment = lastSegment; + } - virtual void on(); + virtual void on(); - virtual void off(); + virtual void off(); - void reset(); + void reset(); - WS2812FX* getWS2812FX(); + WS2812FX* getWS2812FX(); - int getFirstLED(); - int getlastLED(); - int getNumLEDs(); + int getFirstLED(); + int getlastLED(); + int getNumLEDs(); - int getFirstSegment(); - int getLastSegment(); - int getNumSegments(); + int getFirstSegment(); + int getLastSegment(); + int getNumSegments(); - bool isStopped(); + bool isStopped(); - void setBrightness(byte b); - byte getBrightness(); + void setBrightness(byte b); + byte getBrightness(); - void _reduceLEDs(int lastLED, int lastSegment) { - this->lastLED = lastLED; - this->lastSegment = lastSegment; - } + void _reduceLEDs(int lastLED, int lastSegment) { + this->lastLED = lastLED; + this->lastSegment = lastSegment; + } - bool hasAfterGlowSupport() { - return afterGlowSupport; - }; + bool hasAfterGlowSupport() { return afterGlowSupport; }; -protected: - WS2812FX* ws2812FX; + protected: + WS2812FX* ws2812FX; - int firstLED; - int lastLED; - int firstSegment; - int lastSegment; + int firstLED; + int lastLED; + int firstSegment; + int lastSegment; - byte brightness = 64; + byte brightness = 64; - bool stopped = true; - bool afterGlowSupport = false; + bool stopped = true; + bool afterGlowSupport = false; }; #endif diff --git a/src/EffectDevices/WavePWMDevice.cpp b/src/EffectDevices/WavePWMDevice.cpp index 4b5c883..870d272 100644 --- a/src/EffectDevices/WavePWMDevice.cpp +++ b/src/EffectDevices/WavePWMDevice.cpp @@ -1,22 +1,14 @@ #include "WavePWMDevice.h" -void WavePWMDevice::on() { - reset(); -} +void WavePWMDevice::on() { reset(); } -void WavePWMDevice::reset() { - setPWM(0); -} +void WavePWMDevice::reset() { setPWM(0); } void WavePWMDevice::setPWM(uint8_t pwm) { - analogWrite(pin, pwm); - currentPWM = pwm; + analogWrite(pin, pwm); + currentPWM = pwm; } -uint8_t WavePWMDevice::getPWM() { - return currentPWM; -} +uint8_t WavePWMDevice::getPWM() { return currentPWM; } -WavePWM* WavePWMDevice::getWavePWM() { - return wavePWM; -} +WavePWM* WavePWMDevice::getWavePWM() { return wavePWM; } diff --git a/src/EffectDevices/WavePWMDevice.h b/src/EffectDevices/WavePWMDevice.h index 2c36949..6933cf5 100644 --- a/src/EffectDevices/WavePWMDevice.h +++ b/src/EffectDevices/WavePWMDevice.h @@ -14,28 +14,28 @@ #include "EffectDevice.h" class WavePWMDevice : public EffectDevice { -public: - WavePWMDevice(int pin) { - this->wavePWM = new WavePWM(); - this->pin = pin; - pinMode(pin, OUTPUT); - } + public: + WavePWMDevice(int pin) { + this->wavePWM = new WavePWM(); + this->pin = pin; + pinMode(pin, OUTPUT); + } - void on(); + void on(); - void reset(); + void reset(); - virtual void setPWM(uint8_t pwm); + virtual void setPWM(uint8_t pwm); - uint8_t getPWM(); + uint8_t getPWM(); - WavePWM* getWavePWM(); + WavePWM* getWavePWM(); -protected: - WavePWM* wavePWM; + protected: + WavePWM* wavePWM; - int pin; - uint8_t currentPWM = 0; + int pin; + uint8_t currentPWM = 0; }; #endif diff --git a/src/Effects/Effect.cpp b/src/Effects/Effect.cpp index cdbaa2d..081471e 100644 --- a/src/Effects/Effect.cpp +++ b/src/Effects/Effect.cpp @@ -1,58 +1,45 @@ #include "Effect.h" -Effect::Effect() { -} +Effect::Effect() {} -void Effect::setEventDispatcher(EventDispatcher* eD) { - eventDispatcher = eD; -} +void Effect::setEventDispatcher(EventDispatcher* eD) { eventDispatcher = eD; } -void Effect::setDevice(EffectDevice* effectDevice) { - device = effectDevice; -} +void Effect::setDevice(EffectDevice* effectDevice) { device = effectDevice; } -void Effect::dispatch(Event* event) { - eventDispatcher->dispatch(event); -} +void Effect::dispatch(Event* event) { eventDispatcher->dispatch(event); } -bool Effect::isRunning() { - return running; -} +bool Effect::isRunning() { return running; } void Effect::start(int r) { - //Serial.print("effect started, repeat "); - //Serial.println(r); - - running = true; - repeat = r; - stage = 0; - ms = 0; - _ms = millis(); -} + // Serial.print("effect started, repeat "); + // Serial.println(r); -void Effect::updateMillis() { - ms = millis() - _ms; + running = true; + repeat = r; + stage = 0; + ms = 0; + _ms = millis(); } +void Effect::updateMillis() { ms = millis() - _ms; } + void Effect::resetMillis() { - ms = 0; - _ms = millis(); + ms = 0; + _ms = millis(); } void Effect::stop() { - if (repeat > 0) { - start(--repeat); - } - else if (repeat == -1) { - start(-1); - } - else { - terminate(); - } + if (repeat > 0) { + start(--repeat); + } else if (repeat == -1) { + start(-1); + } else { + terminate(); + } } void Effect::terminate() { - running = false; - stage = 0; - repeat = 0; + running = false; + stage = 0; + repeat = 0; } diff --git a/src/Effects/Effect.h b/src/Effects/Effect.h index 8186259..8c817ba 100644 --- a/src/Effects/Effect.h +++ b/src/Effects/Effect.h @@ -11,42 +11,43 @@ #include #include "../EffectDevices/EffectDevice.h" -#include "../EventDispatcher/EventDispatcher.h" #include "../EventDispatcher/Event.h" +#include "../EventDispatcher/EventDispatcher.h" class Effect { -public: - Effect(); + public: + Effect(); - bool isRunning(); + bool isRunning(); - virtual void start(int repeat = 0); + virtual void start(int repeat = 0); - virtual void stop(); + virtual void stop(); - virtual void terminate(); + virtual void terminate(); - virtual void update() = 0; + virtual void update() = 0; - virtual void updateMillis(); + virtual void updateMillis(); - virtual void resetMillis(); + virtual void resetMillis(); - void setEventDispatcher(EventDispatcher* eD); + void setEventDispatcher(EventDispatcher* eD); - virtual void setDevice(EffectDevice* effectDevice); + virtual void setDevice(EffectDevice* effectDevice); -protected: - void dispatch(Event* event); + protected: + void dispatch(Event* event); - EventDispatcher* eventDispatcher; - EffectDevice* device; + EventDispatcher* eventDispatcher; + EffectDevice* device; - bool running = false; - int repeat = 0; // -1 is endless, 0 means play once, 3 means repeat three times, ... - unsigned int ms; - unsigned long _ms; - int stage = 0; + bool running = false; + int repeat = + 0; // -1 is endless, 0 means play once, 3 means repeat three times, ... + unsigned int ms; + unsigned long _ms; + int stage = 0; }; #endif diff --git a/src/Effects/EffectContainer.h b/src/Effects/EffectContainer.h index 045ef32..64d538d 100644 --- a/src/Effects/EffectContainer.h +++ b/src/Effects/EffectContainer.h @@ -8,45 +8,45 @@ #ifndef EFFECTCONTAINER_h #define EFFECTCONTAINER_h -#include "Effect.h" #include "../EffectDevices/EffectDevice.h" #include "../EventDispatcher/Event.h" +#include "Effect.h" struct EffectContainer { - - Effect* effect; - EffectDevice* device; - Event* event; - int priority; // 0 = default, higher value means higher priority - int repeat; // 0 = no repeat, >=1 times repeat - int mode; // -1 = always, 0 = normal play, >=1 multiball, mode, scene, ball save ... - - EffectContainer(Effect* ef, EffectDevice* d, Event* ev, int p) { - effect = ef; - device = d; - event = ev; - priority = p; - repeat = 1; - mode = 0; - } - - EffectContainer(Effect* ef, EffectDevice* d, Event* ev, int p, int r) { - effect = ef; - device = d; - event = ev; - priority = p; - repeat = r; - mode = 0; - } - - EffectContainer(Effect* ef, EffectDevice* d, Event* ev, int p, int r, int m) { - effect = ef; - device = d; - event = ev; - priority = p; - repeat = r; - mode = m; - } + Effect* effect; + EffectDevice* device; + Event* event; + int priority; // 0 = default, higher value means higher priority + int repeat; // 0 = no repeat, >=1 times repeat + int mode; // -1 = always, 0 = normal play, >=1 multiball, mode, scene, ball + // save ... + + EffectContainer(Effect* ef, EffectDevice* d, Event* ev, int p) { + effect = ef; + device = d; + event = ev; + priority = p; + repeat = 1; + mode = 0; + } + + EffectContainer(Effect* ef, EffectDevice* d, Event* ev, int p, int r) { + effect = ef; + device = d; + event = ev; + priority = p; + repeat = r; + mode = 0; + } + + EffectContainer(Effect* ef, EffectDevice* d, Event* ev, int p, int r, int m) { + effect = ef; + device = d; + event = ev; + priority = p; + repeat = r; + mode = m; + } }; #endif diff --git a/src/Effects/ImpulsePWMEffect.cpp b/src/Effects/ImpulsePWMEffect.cpp index e1cfd8c..c27520a 100644 --- a/src/Effects/ImpulsePWMEffect.cpp +++ b/src/Effects/ImpulsePWMEffect.cpp @@ -1,17 +1,17 @@ #include "ImpulsePWMEffect.h" void ImpulsePWMEffect::update() { - if (ms > waveDuration) { - stop(); - return; - } + if (ms > waveDuration) { + stop(); + return; + } - uint8_t pwm = compression * wavePWM->getQuadraticValue(ms); + uint8_t pwm = compression * wavePWM->getQuadraticValue(ms); - // Safety net. - if (pwm > 255) { - pwm = 255; - } + // Safety net. + if (pwm > 255) { + pwm = 255; + } - ((WavePWMDevice *) device)->setPWM(pwm); + ((WavePWMDevice *)device)->setPWM(pwm); } diff --git a/src/Effects/ImpulsePWMEffect.h b/src/Effects/ImpulsePWMEffect.h index 95f7948..ddf7225 100644 --- a/src/Effects/ImpulsePWMEffect.h +++ b/src/Effects/ImpulsePWMEffect.h @@ -11,18 +11,18 @@ #include #include -#include "WavePWMEffect.h" #include "../EffectDevices/EffectDevice.h" #include "../EffectDevices/WavePWMDevice.h" +#include "WavePWMEffect.h" class ImpulsePWMEffect : public WavePWMEffect { -public: - - ImpulsePWMEffect(unsigned int frequency, uint8_t maxIntensity = 255) : WavePWMEffect(frequency, maxIntensity) { - // nop - } + public: + ImpulsePWMEffect(unsigned int frequency, uint8_t maxIntensity = 255) + : WavePWMEffect(frequency, maxIntensity) { + // nop + } - virtual void update(); + virtual void update(); }; #endif diff --git a/src/Effects/LedBlinkEffect.cpp b/src/Effects/LedBlinkEffect.cpp index 91b2c98..e41b9c9 100644 --- a/src/Effects/LedBlinkEffect.cpp +++ b/src/Effects/LedBlinkEffect.cpp @@ -1,28 +1,23 @@ #include "LedBlinkEffect.h" void LedBlinkEffect::update() { - if (stage == 0) { - device->off(); - ++stage; - } - else if (stage == 1 && ms >= 200) { - device->on(); - ++stage; - } - else if (stage == 2 && ms >= 400) { - device->off(); - ++stage; - } - else if (stage == 3 && ms >= 600) { - device->on(); - ++stage; - } - else if (stage == 4 && ms >= 800) { - device->off(); - ++stage; - } - else if (ms >= 1000) { - device->on(); - stop(); - } + if (stage == 0) { + device->off(); + ++stage; + } else if (stage == 1 && ms >= 200) { + device->on(); + ++stage; + } else if (stage == 2 && ms >= 400) { + device->off(); + ++stage; + } else if (stage == 3 && ms >= 600) { + device->on(); + ++stage; + } else if (stage == 4 && ms >= 800) { + device->off(); + ++stage; + } else if (ms >= 1000) { + device->on(); + stop(); + } } diff --git a/src/Effects/LedBlinkEffect.h b/src/Effects/LedBlinkEffect.h index bdc8c7f..1db31e2 100644 --- a/src/Effects/LedBlinkEffect.h +++ b/src/Effects/LedBlinkEffect.h @@ -13,9 +13,8 @@ #include "Effect.h" class LedBlinkEffect : public Effect { -public: - void update(); - + public: + void update(); }; #endif diff --git a/src/Effects/LedOnEffect.cpp b/src/Effects/LedOnEffect.cpp index 35cdc0b..9b3eb37 100644 --- a/src/Effects/LedOnEffect.cpp +++ b/src/Effects/LedOnEffect.cpp @@ -1,6 +1,6 @@ #include "LedOnEffect.h" void LedOnEffect::update() { - device->on(); - stop(); + device->on(); + stop(); } diff --git a/src/Effects/LedOnEffect.h b/src/Effects/LedOnEffect.h index 7527334..29dd892 100644 --- a/src/Effects/LedOnEffect.h +++ b/src/Effects/LedOnEffect.h @@ -13,9 +13,8 @@ #include "Effect.h" class LedOnEffect : public Effect { -public: - void update(); - + public: + void update(); }; #endif diff --git a/src/Effects/NullEffect.cpp b/src/Effects/NullEffect.cpp index 9e5cd79..2ac623e 100644 --- a/src/Effects/NullEffect.cpp +++ b/src/Effects/NullEffect.cpp @@ -1,6 +1,6 @@ #include "NullEffect.h" void NullEffect::update() { - device->reset(); - stop(); + device->reset(); + stop(); } diff --git a/src/Effects/NullEffect.h b/src/Effects/NullEffect.h index a990721..54a00da 100644 --- a/src/Effects/NullEffect.h +++ b/src/Effects/NullEffect.h @@ -13,9 +13,8 @@ #include "Effect.h" class NullEffect : public Effect { -public: - void update(); - + public: + void update(); }; #endif diff --git a/src/Effects/RGBColorCycleEffect.cpp b/src/Effects/RGBColorCycleEffect.cpp index fcb13e5..3a97ae0 100644 --- a/src/Effects/RGBColorCycleEffect.cpp +++ b/src/Effects/RGBColorCycleEffect.cpp @@ -1,61 +1,56 @@ #include "RGBColorCycleEffect.h" void RGBColorCycleEffect::update() { - WS2812FX* ws2812FX = ((WS2812FXDevice*) device)->getWS2812FX(); - if (stage == 0) { - color = 0xFF0000; - device->on(); - ++stage; - } + WS2812FX* ws2812FX = ((WS2812FXDevice*)device)->getWS2812FX(); + if (stage == 0) { + color = 0xFF0000; + device->on(); + ++stage; + } - int blue = color & 255; - int green = (color >> 8) & 255; - int red = (color >> 16) & 255; + int blue = color & 255; + int green = (color >> 8) & 255; + int red = (color >> 16) & 255; - if (ms >= delay) { - resetMillis(); - if (stage == 1) { - color = ws2812FX->Color(red, ++green, blue); - ws2812FX->setColor(color); - if (color >= 0xFFFF00) { - ++stage; - } - } - else if (stage == 2) { - color = ws2812FX->Color(red, green, ++blue); - ws2812FX->setColor(color); - if (color >= 0xFFFFFF) { - ++stage; - } - } - else if (stage == 3) { - color = ws2812FX->Color(--red, green, blue); - ws2812FX->setColor(color); - if (color <= 0x00FFFF) { - ++stage; - } - } - else if (stage == 4) { - color = ws2812FX->Color(red, --green, blue); - ws2812FX->setColor(color); - if (color <= 0x0000FF) { - ++stage; - } - } - else if (stage == 5) { - color = ws2812FX->Color(++red, green, blue); - ws2812FX->setColor(color); - if (color >= 0xFF00FF) { - ++stage; - } - } - else if (stage == 6) { - color = ws2812FX->Color(red, green, --blue); - ws2812FX->setColor(color); - if (color <= 0xFF0000) { - device->off(); - stop(); - } - } + if (ms >= delay) { + resetMillis(); + if (stage == 1) { + color = ws2812FX->Color(red, ++green, blue); + ws2812FX->setColor(color); + if (color >= 0xFFFF00) { + ++stage; + } + } else if (stage == 2) { + color = ws2812FX->Color(red, green, ++blue); + ws2812FX->setColor(color); + if (color >= 0xFFFFFF) { + ++stage; + } + } else if (stage == 3) { + color = ws2812FX->Color(--red, green, blue); + ws2812FX->setColor(color); + if (color <= 0x00FFFF) { + ++stage; + } + } else if (stage == 4) { + color = ws2812FX->Color(red, --green, blue); + ws2812FX->setColor(color); + if (color <= 0x0000FF) { + ++stage; + } + } else if (stage == 5) { + color = ws2812FX->Color(++red, green, blue); + ws2812FX->setColor(color); + if (color >= 0xFF00FF) { + ++stage; + } + } else if (stage == 6) { + color = ws2812FX->Color(red, green, --blue); + ws2812FX->setColor(color); + if (color <= 0xFF0000) { + device->off(); + stop(); + } } + } } diff --git a/src/Effects/RGBColorCycleEffect.h b/src/Effects/RGBColorCycleEffect.h index 45006f2..a5cadec 100644 --- a/src/Effects/RGBColorCycleEffect.h +++ b/src/Effects/RGBColorCycleEffect.h @@ -10,20 +10,18 @@ #include -#include "Effect.h" #include "../EffectDevices/WS2812FXDevice.h" +#include "Effect.h" class RGBColorCycleEffect : public Effect { -public: - RGBColorCycleEffect(unsigned int delayMs) { - delay = delayMs; - } + public: + RGBColorCycleEffect(unsigned int delayMs) { delay = delayMs; } - void update(); + void update(); -protected: - unsigned int delay; - uint32_t color; + protected: + unsigned int delay; + uint32_t color; }; #endif diff --git a/src/Effects/RampDownStopPWMEffect.cpp b/src/Effects/RampDownStopPWMEffect.cpp index 4ce5134..90656f7 100644 --- a/src/Effects/RampDownStopPWMEffect.cpp +++ b/src/Effects/RampDownStopPWMEffect.cpp @@ -1,28 +1,29 @@ #include "RampDownStopPWMEffect.h" void RampDownStopPWMEffect::updateMillis() { - // Immediately shift to the falling curve of the first period by adding (waveDuration / 2) - ms = millis() - _ms + (waveDuration / 2); + // Immediately shift to the falling curve of the first period by adding + // (waveDuration / 2) + ms = millis() - _ms + (waveDuration / 2); } void RampDownStopPWMEffect::update() { - if (ms > waveDuration) { - stop(); - return; - } + if (ms > waveDuration) { + stop(); + return; + } - if (stage < 1) { - maxIntensity = ((WavePWMDevice *) device)->getPWM(); - compression = 255 / maxIntensity; - stage = 1; - } + if (stage < 1) { + maxIntensity = ((WavePWMDevice *)device)->getPWM(); + compression = 255 / maxIntensity; + stage = 1; + } - uint8_t pwm = compression * wavePWM->getQuadraticValue(ms); + uint8_t pwm = compression * wavePWM->getQuadraticValue(ms); - // Safety net. - if (pwm > 255) { - pwm = 255; - } + // Safety net. + if (pwm > 255) { + pwm = 255; + } - ((WavePWMDevice *) device)->setPWM(pwm); + ((WavePWMDevice *)device)->setPWM(pwm); } diff --git a/src/Effects/RampDownStopPWMEffect.h b/src/Effects/RampDownStopPWMEffect.h index e0205a7..6f03ace 100644 --- a/src/Effects/RampDownStopPWMEffect.h +++ b/src/Effects/RampDownStopPWMEffect.h @@ -11,20 +11,19 @@ #include #include -#include "WavePWMEffect.h" #include "../EffectDevices/EffectDevice.h" #include "../EffectDevices/WavePWMDevice.h" +#include "WavePWMEffect.h" class RampDownStopPWMEffect : public WavePWMEffect { -public: - - RampDownStopPWMEffect(unsigned int frequency) : WavePWMEffect(frequency) { - // nop - } + public: + RampDownStopPWMEffect(unsigned int frequency) : WavePWMEffect(frequency) { + // nop + } - virtual void updateMillis(); + virtual void updateMillis(); - virtual void update(); + virtual void update(); }; #endif diff --git a/src/Effects/SinePWMEffect.cpp b/src/Effects/SinePWMEffect.cpp index 5255086..d1aacb5 100644 --- a/src/Effects/SinePWMEffect.cpp +++ b/src/Effects/SinePWMEffect.cpp @@ -1,38 +1,36 @@ #include "SinePWMEffect.h" void SinePWMEffect::update() { - uint8_t pwm = 0; + uint8_t pwm = 0; - if (stage == 0) { - if (ms < (waveDuration / 4)) { - pwm = rampCompression * wavePWM->getQuadraticValue(ms); - } - else { - stage = 1; - } + if (stage == 0) { + if (ms < (waveDuration / 4)) { + pwm = rampCompression * wavePWM->getQuadraticValue(ms); + } else { + stage = 1; } + } - if (stage == 1) { - if (ms < duration) { - pwm = compression * wavePWM->getQuadraticValue(ms) + minIntensity; - } - else { - stage = 2; - } + if (stage == 1) { + if (ms < duration) { + pwm = compression * wavePWM->getQuadraticValue(ms) + minIntensity; + } else { + stage = 2; } + } - if (stage == 2) { - pwm = rampCompression * wavePWM->getQuadraticValue(ms); - if (pwm == 0) { - stop(); - return; - } + if (stage == 2) { + pwm = rampCompression * wavePWM->getQuadraticValue(ms); + if (pwm == 0) { + stop(); + return; } + } - // Safety net. - if (pwm > 255) { - pwm = 255; - } + // Safety net. + if (pwm > 255) { + pwm = 255; + } - ((WavePWMDevice *) device)->setPWM(pwm); + ((WavePWMDevice *)device)->setPWM(pwm); } diff --git a/src/Effects/SinePWMEffect.h b/src/Effects/SinePWMEffect.h index 962643a..14f627a 100644 --- a/src/Effects/SinePWMEffect.h +++ b/src/Effects/SinePWMEffect.h @@ -11,23 +11,24 @@ #include #include -#include "WavePWMEffect.h" #include "../EffectDevices/EffectDevice.h" #include "../EffectDevices/WavePWMDevice.h" +#include "WavePWMEffect.h" class SinePWMEffect : public WavePWMEffect { -public: - - SinePWMEffect(unsigned int frequency, unsigned int duration, uint8_t maxIntensity = 255, uint8_t minIntensity = 0) : WavePWMEffect(frequency, maxIntensity, minIntensity) { - this->duration = duration; - this->rampCompression = 255 / maxIntensity; - } - - virtual void update(); - -protected: - unsigned int duration; - uint8_t rampCompression; + public: + SinePWMEffect(unsigned int frequency, unsigned int duration, + uint8_t maxIntensity = 255, uint8_t minIntensity = 0) + : WavePWMEffect(frequency, maxIntensity, minIntensity) { + this->duration = duration; + this->rampCompression = 255 / maxIntensity; + } + + virtual void update(); + + protected: + unsigned int duration; + uint8_t rampCompression; }; #endif diff --git a/src/Effects/WS2812FXEffect.cpp b/src/Effects/WS2812FXEffect.cpp index 94df349..895c909 100644 --- a/src/Effects/WS2812FXEffect.cpp +++ b/src/Effects/WS2812FXEffect.cpp @@ -1,50 +1,51 @@ #include "WS2812FXEffect.h" -void WS2812FXEffect::setDevice(EffectDevice* effectDevice) { - Effect::setDevice(effectDevice); - ws2812FX = (WS2812FX*) ((WS2812FXDevice *) device)->getWS2812FX(); +void WS2812FXEffect::setDevice(EffectDevice *effectDevice) { + Effect::setDevice(effectDevice); + ws2812FX = (WS2812FX *)((WS2812FXDevice *)device)->getWS2812FX(); } void WS2812FXEffect::start(int r) { - Effect::start(); - device->on(); - ws2812FX->setSegment(getFirstSegment(), getFirstLED(), getlastLED(), mode, colors, speed, options); - ws2812FX->resetSegmentRuntime(getFirstSegment()); + Effect::start(); + device->on(); + ws2812FX->setSegment(getFirstSegment(), getFirstLED(), getlastLED(), mode, + colors, speed, options); + ws2812FX->resetSegmentRuntime(getFirstSegment()); } void WS2812FXEffect::stop() { - device->off(); - Effect::stop(); + device->off(); + Effect::stop(); } void WS2812FXEffect::update() { - // Don't call service() here! + // Don't call service() here! - if (duration && duration < ms) { - stop(); - } + if (duration && duration < ms) { + stop(); + } } int WS2812FXEffect::getFirstLED() { - return ((WS2812FXDevice *) device)->getFirstLED(); + return ((WS2812FXDevice *)device)->getFirstLED(); } int WS2812FXEffect::getlastLED() { - return ((WS2812FXDevice *) device)->getlastLED(); + return ((WS2812FXDevice *)device)->getlastLED(); } int WS2812FXEffect::getNumLEDs() { - return ((WS2812FXDevice *) device)->getNumLEDs(); + return ((WS2812FXDevice *)device)->getNumLEDs(); } int WS2812FXEffect::getFirstSegment() { - return ((WS2812FXDevice *) device)->getFirstSegment(); + return ((WS2812FXDevice *)device)->getFirstSegment(); } int WS2812FXEffect::getLastSegment() { - return ((WS2812FXDevice *) device)->getLastSegment(); + return ((WS2812FXDevice *)device)->getLastSegment(); } int WS2812FXEffect::getNumSegments() { - return ((WS2812FXDevice *) device)->getNumSegments(); + return ((WS2812FXDevice *)device)->getNumSegments(); } diff --git a/src/Effects/WS2812FXEffect.h b/src/Effects/WS2812FXEffect.h index 210c5f7..04f9a0d 100644 --- a/src/Effects/WS2812FXEffect.h +++ b/src/Effects/WS2812FXEffect.h @@ -11,54 +11,55 @@ #include #include -#include "Effect.h" #include "../EffectDevices/EffectDevice.h" #include "../EffectDevices/WS2812FXDevice.h" +#include "Effect.h" class WS2812FXEffect : public Effect { -public: - - WS2812FXEffect(uint8_t mode, uint32_t color, uint16_t speed, uint8_t options, int duration = 0) { - this->mode = mode; - this->colors[0] = color; - this->speed = speed; - this->options = options; - this->duration = duration; - } + public: + WS2812FXEffect(uint8_t mode, uint32_t color, uint16_t speed, uint8_t options, + int duration = 0) { + this->mode = mode; + this->colors[0] = color; + this->speed = speed; + this->options = options; + this->duration = duration; + } - WS2812FXEffect(uint8_t mode, const uint32_t colors[], uint16_t speed, uint8_t options, int duration = 0) { - this->mode = mode; - this->colors[0] = colors[0]; - this->colors[1] = colors[1]; - this->colors[2] = colors[2]; - this->speed = speed; - this->options = options; - this->duration = duration; - } + WS2812FXEffect(uint8_t mode, const uint32_t colors[], uint16_t speed, + uint8_t options, int duration = 0) { + this->mode = mode; + this->colors[0] = colors[0]; + this->colors[1] = colors[1]; + this->colors[2] = colors[2]; + this->speed = speed; + this->options = options; + this->duration = duration; + } - virtual void setDevice(EffectDevice* effectDevice); + virtual void setDevice(EffectDevice* effectDevice); - virtual void start(int repeat = 0); + virtual void start(int repeat = 0); - virtual void stop(); + virtual void stop(); - virtual void update(); + virtual void update(); - int getFirstLED(); - int getlastLED(); - int getNumLEDs(); + int getFirstLED(); + int getlastLED(); + int getNumLEDs(); - int getFirstSegment(); - int getLastSegment(); - int getNumSegments(); + int getFirstSegment(); + int getLastSegment(); + int getNumSegments(); -protected: - WS2812FX* ws2812FX; - uint8_t mode; - uint32_t colors[3] = {0, 0, 0}; - uint16_t speed; - uint8_t options; - int duration; // 0 means unlimited + protected: + WS2812FX* ws2812FX; + uint8_t mode; + uint32_t colors[3] = {0, 0, 0}; + uint16_t speed; + uint8_t options; + int duration; // 0 means unlimited }; #endif diff --git a/src/Effects/WavePWMEffect.cpp b/src/Effects/WavePWMEffect.cpp index 19d9feb..9094d27 100644 --- a/src/Effects/WavePWMEffect.cpp +++ b/src/Effects/WavePWMEffect.cpp @@ -1,17 +1,17 @@ #include "WavePWMEffect.h" void WavePWMEffect::setDevice(EffectDevice* effectDevice) { - Effect::setDevice(effectDevice); - wavePWM = (WavePWM*) ((WavePWMDevice *) device)->getWavePWM(); + Effect::setDevice(effectDevice); + wavePWM = (WavePWM*)((WavePWMDevice*)device)->getWavePWM(); } void WavePWMEffect::start(int r) { - Effect::start(r); - device->on(); - wavePWM->setup(waveDuration); + Effect::start(r); + device->on(); + wavePWM->setup(waveDuration); } void WavePWMEffect::stop() { - device->off(); - Effect::stop(); + device->off(); + Effect::stop(); } diff --git a/src/Effects/WavePWMEffect.h b/src/Effects/WavePWMEffect.h index ea93062..6d0f41a 100644 --- a/src/Effects/WavePWMEffect.h +++ b/src/Effects/WavePWMEffect.h @@ -11,34 +11,34 @@ #include #include -#include "Effect.h" #include "../EffectDevices/EffectDevice.h" #include "../EffectDevices/WavePWMDevice.h" +#include "Effect.h" class WavePWMEffect : public Effect { -public: - - WavePWMEffect(unsigned int frequency, uint8_t maxIntensity = 255, uint8_t minIntensity = 0) { - this->waveDuration = 1000 / frequency; - this->maxIntensity = maxIntensity; - this->minIntensity = minIntensity; - this->compression = 255 / (maxIntensity - minIntensity); - } + public: + WavePWMEffect(unsigned int frequency, uint8_t maxIntensity = 255, + uint8_t minIntensity = 0) { + this->waveDuration = 1000 / frequency; + this->maxIntensity = maxIntensity; + this->minIntensity = minIntensity; + this->compression = 255 / (maxIntensity - minIntensity); + } - virtual void setDevice(EffectDevice* effectDevice); + virtual void setDevice(EffectDevice* effectDevice); - virtual void start(int repeat = 0); + virtual void start(int repeat = 0); - virtual void stop(); + virtual void stop(); - virtual void update() = 0; + virtual void update() = 0; -protected: - WavePWM* wavePWM; - unsigned int waveDuration; - uint8_t maxIntensity; - uint8_t minIntensity; - uint8_t compression; + protected: + WavePWM* wavePWM; + unsigned int waveDuration; + uint8_t maxIntensity; + uint8_t minIntensity; + uint8_t compression; }; #endif diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 3746c57..0cdbe17 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -3,389 +3,340 @@ // see https://forum.arduino.cc/index.php?topic=398610.0 EffectsController *EffectsController::effectsControllerInstance = NULL; -EventDispatcher *EffectsController::eventDispatcher() -{ - return _eventDispatcher; +EventDispatcher *EffectsController::eventDispatcher() { + return _eventDispatcher; } -LedBuiltInDevice *EffectsController::ledBuiltInDevice() -{ - return _ledBuiltInDevice; +LedBuiltInDevice *EffectsController::ledBuiltInDevice() { + return _ledBuiltInDevice; } -NullDevice *EffectsController::nullDevice() -{ - return _nullDevice; -} +NullDevice *EffectsController::nullDevice() { return _nullDevice; } -WavePWMDevice *EffectsController::shakerPWMDevice() -{ - return _shakerPWMDevice; -} +WavePWMDevice *EffectsController::shakerPWMDevice() { return _shakerPWMDevice; } -WavePWMDevice *EffectsController::ledPWMDevice() -{ - return _ledPWMDevice; -} +WavePWMDevice *EffectsController::ledPWMDevice() { return _ledPWMDevice; } -RgbStripDevice *EffectsController::rgbStripDevice() -{ - return _rgbStripeDevice; -} +RgbStripDevice *EffectsController::rgbStripDevice() { return _rgbStripeDevice; } -WS2812FXDevice *EffectsController::ws2812FXDevice(int port) -{ - return ws2812FXDevices[--port][0]; +WS2812FXDevice *EffectsController::ws2812FXDevice(int port) { + return ws2812FXDevices[--port][0]; } -CombinedGiAndLightMatrixWS2812FXDevice *EffectsController::giAndLightMatrix(int port) -{ - return (CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevice(port); +CombinedGiAndLightMatrixWS2812FXDevice *EffectsController::giAndLightMatrix( + int port) { + return (CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevice(port); } -CombinedGiAndLightMatrixWS2812FXDevice *EffectsController::createCombinedGiAndLightMatrixWs2812FXDevice(int port) -{ - WS2812FXDevice *ws2812FXDevice = ws2812FXDevices[--port][0]; +CombinedGiAndLightMatrixWS2812FXDevice * +EffectsController::createCombinedGiAndLightMatrixWs2812FXDevice(int port) { + WS2812FXDevice *ws2812FXDevice = ws2812FXDevices[--port][0]; - CombinedGiAndLightMatrixWS2812FXDevice *giAndLightMatrix = new CombinedGiAndLightMatrixWS2812FXDevice( - ws2812FXDevice->getWS2812FX(), - ws2812FXDevice->getFirstLED(), - ws2812FXDevice->getlastLED(), - ws2812FXDevice->getFirstSegment(), - ws2812FXDevice->getLastSegment(), - _eventDispatcher); + CombinedGiAndLightMatrixWS2812FXDevice *giAndLightMatrix = + new CombinedGiAndLightMatrixWS2812FXDevice( + ws2812FXDevice->getWS2812FX(), ws2812FXDevice->getFirstLED(), + ws2812FXDevice->getlastLED(), ws2812FXDevice->getFirstSegment(), + ws2812FXDevice->getLastSegment(), _eventDispatcher); - giAndLightMatrix->off(); + giAndLightMatrix->off(); - ws2812FXDevices[port][0] = giAndLightMatrix; - delete ws2812FXDevice; + ws2812FXDevices[port][0] = giAndLightMatrix; + delete ws2812FXDevice; - _eventDispatcher->addListener(giAndLightMatrix, EVENT_SOURCE_GI); - _eventDispatcher->addListener(giAndLightMatrix, EVENT_SOURCE_LIGHT); + _eventDispatcher->addListener(giAndLightMatrix, EVENT_SOURCE_GI); + _eventDispatcher->addListener(giAndLightMatrix, EVENT_SOURCE_LIGHT); - return giAndLightMatrix; + return giAndLightMatrix; } -WS2812FXDevice *EffectsController::createWS2812FXDevice(int port, int number, int segments, int firstLED, int lastLED) -{ - --port; +WS2812FXDevice *EffectsController::createWS2812FXDevice(int port, int number, + int segments, + int firstLED, + int lastLED) { + --port; - if (number == 0) - { - ws2812FXDevices[port][0]->_reduceLEDs(lastLED, segments - 1); - } - else - { - int firstSegment = ws2812FXDevices[port][number - 1]->getLastSegment() + 1; - - ws2812FXDevices[port][number] = new WS2812FXDevice( - ws2812FXDevices[port][0]->getWS2812FX(), - firstLED, - lastLED, - firstSegment, - firstSegment + segments - 1); - - ++ws2812FXDeviceCounters[port]; - } + if (number == 0) { + ws2812FXDevices[port][0]->_reduceLEDs(lastLED, segments - 1); + } else { + int firstSegment = ws2812FXDevices[port][number - 1]->getLastSegment() + 1; + + ws2812FXDevices[port][number] = + new WS2812FXDevice(ws2812FXDevices[port][0]->getWS2812FX(), firstLED, + lastLED, firstSegment, firstSegment + segments - 1); - return ws2812FXDevices[port][number]; + ++ws2812FXDeviceCounters[port]; + } + + return ws2812FXDevices[port][number]; } -WS2812FXDevice *EffectsController::ws2812FXDevice(int port, int number) -{ - return ws2812FXDevices[--port][number]; +WS2812FXDevice *EffectsController::ws2812FXDevice(int port, int number) { + return ws2812FXDevices[--port][number]; } -GeneralIlluminationWPC *EffectsController::generalIllumintationWPC() -{ - return _generalIllumintationWPC; +GeneralIlluminationWPC *EffectsController::generalIllumintationWPC() { + return _generalIllumintationWPC; } -void EffectsController::addEffect(Effect *effect, EffectDevice *device, Event *event, int priority, int repeat, int mode) -{ - addEffect(new EffectContainer(effect, device, event, priority, repeat, mode)); +void EffectsController::addEffect(Effect *effect, EffectDevice *device, + Event *event, int priority, int repeat, + int mode) { + addEffect(new EffectContainer(effect, device, event, priority, repeat, mode)); } -void EffectsController::addEffect(EffectContainer *container) -{ - container->effect->setEventDispatcher(this->eventDispatcher()); - container->effect->setDevice(container->device); - stackEffectContainers[++stackCounter] = container; +void EffectsController::addEffect(EffectContainer *container) { + container->effect->setEventDispatcher(this->eventDispatcher()); + container->effect->setDevice(container->device); + stackEffectContainers[++stackCounter] = container; } -void EffectsController::attachBrightnessControl(byte port, byte poti) -{ - brightnessControl[--port] = poti; +void EffectsController::attachBrightnessControl(byte port, byte poti) { + brightnessControl[--port] = poti; } -void EffectsController::setBrightness(byte port, byte brightness) -{ - ws2812FXDevices[--port][0]->setBrightness(brightness); - ws2812FXbrightness[port] = brightness; +void EffectsController::setBrightness(byte port, byte brightness) { + ws2812FXDevices[--port][0]->setBrightness(brightness); + ws2812FXbrightness[port] = brightness; } -void EffectsController::handleEvent(Event *event) -{ - for (int i = 0; i <= stackCounter; i++) - { - if ( - event->sourceId == stackEffectContainers[i]->event->sourceId && - event->eventId == stackEffectContainers[i]->event->eventId && - event->value == stackEffectContainers[i]->event->value && - (mode == stackEffectContainers[i]->mode || - -1 == stackEffectContainers[i]->mode // -1 means any mode - )) - { - for (int k = 0; k <= stackCounter; k++) - { - if ( - stackEffectContainers[i]->device == stackEffectContainers[k]->device && - stackEffectContainers[k]->effect->isRunning()) - { - if (stackEffectContainers[i]->priority > stackEffectContainers[k]->priority) - { - stackEffectContainers[k]->effect->terminate(); - stackEffectContainers[i]->effect->start(stackEffectContainers[i]->repeat); - } - break; - } - if (k == stackCounter) - { - stackEffectContainers[i]->effect->start(stackEffectContainers[i]->repeat); - } - } +void EffectsController::handleEvent(Event *event) { + for (int i = 0; i <= stackCounter; i++) { + if (event->sourceId == stackEffectContainers[i]->event->sourceId && + event->eventId == stackEffectContainers[i]->event->eventId && + event->value == stackEffectContainers[i]->event->value && + (mode == stackEffectContainers[i]->mode || + -1 == stackEffectContainers[i]->mode // -1 means any mode + )) { + for (int k = 0; k <= stackCounter; k++) { + if (stackEffectContainers[i]->device == + stackEffectContainers[k]->device && + stackEffectContainers[k]->effect->isRunning()) { + if (stackEffectContainers[i]->priority > + stackEffectContainers[k]->priority) { + stackEffectContainers[k]->effect->terminate(); + stackEffectContainers[i]->effect->start( + stackEffectContainers[i]->repeat); + } + break; } + if (k == stackCounter) { + stackEffectContainers[i]->effect->start( + stackEffectContainers[i]->repeat); + } + } } + } } -void EffectsController::handleEvent(ConfigEvent *event) -{ - if (event->boardId == boardId) - { - switch (event->topic) - { - case CONFIG_TOPIC_PLATFORM: - platform = event->value; +void EffectsController::handleEvent(ConfigEvent *event) { + if (event->boardId == boardId) { + switch (event->topic) { + case CONFIG_TOPIC_PLATFORM: + platform = event->value; + break; + + case CONFIG_TOPIC_LED_STRING: + switch (event->key) { + case CONFIG_TOPIC_PORT: + config_port = event->value; + config_type = 0; + config_amount = 0; + config_afterGlow = 0; break; - - case CONFIG_TOPIC_LED_STRING: - switch (event->key) - { - case CONFIG_TOPIC_PORT: - config_port = event->value; - config_type = 0; - config_amount = 0; - config_afterGlow = 0; - break; - case CONFIG_TOPIC_TYPE: - config_type = event->value; - break; - case CONFIG_TOPIC_AMOUNT_LEDS: - config_amount = event->value; - break; - case CONFIG_TOPIC_AFTER_GLOW: - config_afterGlow = event->value; - break; - case CONFIG_TOPIC_LIGHT_UP: - config_heatUp = event->value; - if (!ws2812FXDevices[0][0]) - { - ws2812FXDevices[0][0] = new CombinedGiAndLightMatrixWS2812FXDevice( - new WS2812FX(config_amount, config_port, config_type), - 0, - config_amount - 1, - 0, - 0, - _eventDispatcher); - ws2812FXDevices[0][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[0] = 1; - - // Brightness might be overwritten later. - // ws2812FXDevices[0][0]->setBrightness(WS2812FX_BRIGHTNESS); - // "off" means no effects, standard operation mode. - ws2812FXDevices[0][0]->off(); - if (config_heatUp > 0) - { - ((CombinedGiAndLightMatrixWS2812FXDevice*)ws2812FXDevices[0][0])->setHeatUp(config_heatUp); - } - if (config_afterGlow > 0) - { - ((CombinedGiAndLightMatrixWS2812FXDevice*)ws2812FXDevices[0][0])->setAfterGlow(config_afterGlow); - } - ws2812FXstates[0] = true; - } - - break; + case CONFIG_TOPIC_TYPE: + config_type = event->value; + break; + case CONFIG_TOPIC_AMOUNT_LEDS: + config_amount = event->value; + break; + case CONFIG_TOPIC_AFTER_GLOW: + config_afterGlow = event->value; + break; + case CONFIG_TOPIC_LIGHT_UP: + config_heatUp = event->value; + if (!ws2812FXDevices[0][0]) { + ws2812FXDevices[0][0] = + new CombinedGiAndLightMatrixWS2812FXDevice( + new WS2812FX(config_amount, config_port, config_type), 0, + config_amount - 1, 0, 0, _eventDispatcher); + ws2812FXDevices[0][0]->getWS2812FX()->init(); + ws2812FXDeviceCounters[0] = 1; + + // Brightness might be overwritten later. + // ws2812FXDevices[0][0]->setBrightness(WS2812FX_BRIGHTNESS); + // "off" means no effects, standard operation mode. + ws2812FXDevices[0][0]->off(); + if (config_heatUp > 0) { + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->setHeatUp(config_heatUp); + } + if (config_afterGlow > 0) { + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->setAfterGlow(config_afterGlow); + } + ws2812FXstates[0] = true; } + break; + } + break; - case CONFIG_TOPIC_LAMPS: - if (ws2812FXDevices[0][0]) - { - switch (event->key) - { - case CONFIG_TOPIC_PORT: - config_port = event->value; - config_type = 0; - config_number = 0; - config_ledNumber = 0; - config_brightness = 0; - config_color = 0; - break; - case CONFIG_TOPIC_TYPE: - config_type = event->value; - break; - case CONFIG_TOPIC_NUMBER: - config_number = event->value; - break; - case CONFIG_TOPIC_LED_NUMBER: - config_ledNumber = event->value; - break; - case CONFIG_TOPIC_BRIGHTNESS: - config_brightness = event->value; - break; - case CONFIG_TOPIC_COLOR: - config_color = event->value; - switch (config_type) - { - case LED_TYPE_GI: - ((CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevices[0][0])->assignLedToGiString(config_number, config_ledNumber, config_color); - break; - case LED_TYPE_LAMP: - if (platform == PLATFORM_WPC) - { - ((CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevices[0][0])->assignLedToLightMatrixWPC(config_number, config_ledNumber, config_color); - } - else - { - ((CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevices[0][0])->assignLedToLightMatrix(config_number, config_ledNumber, config_color); - } - break; - case LED_TYPE_FLASHER: - ((CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevices[0][0])->assignLedToFlasher(config_number, config_ledNumber, config_color); - break; - } - break; - } - break; - } + case CONFIG_TOPIC_LAMPS: + if (ws2812FXDevices[0][0]) { + switch (event->key) { + case CONFIG_TOPIC_PORT: + config_port = event->value; + config_type = 0; + config_number = 0; + config_ledNumber = 0; + config_brightness = 0; + config_color = 0; + break; + case CONFIG_TOPIC_TYPE: + config_type = event->value; + break; + case CONFIG_TOPIC_NUMBER: + config_number = event->value; + break; + case CONFIG_TOPIC_LED_NUMBER: + config_ledNumber = event->value; + break; + case CONFIG_TOPIC_BRIGHTNESS: + config_brightness = event->value; + break; + case CONFIG_TOPIC_COLOR: + config_color = event->value; + switch (config_type) { + case LED_TYPE_GI: + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignLedToGiString(config_number, config_ledNumber, + config_color); + break; + case LED_TYPE_LAMP: + if (platform == PLATFORM_WPC) { + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignLedToLightMatrixWPC( + config_number, config_ledNumber, config_color); + } else { + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignLedToLightMatrix( + config_number, config_ledNumber, config_color); + } + break; + case LED_TYPE_FLASHER: + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignLedToFlasher(config_number, config_ledNumber, + config_color); + break; + } + break; + } + break; } } + } } -void EffectsController::update() -{ - if (controllerType == CONTROLLER_MEGA_ALL_INPUT) - { - _testButtons->update(); - } +void EffectsController::update() { + if (controllerType == CONTROLLER_MEGA_ALL_INPUT) { + _testButtons->update(); + } - if (platform == PLATFORM_WPC && controllerType != CONTROLLER_16_8_1) - { - _generalIllumintationWPC->update(); - } + if (platform == PLATFORM_WPC && controllerType != CONTROLLER_16_8_1) { + _generalIllumintationWPC->update(); + } - _eventDispatcher->update(); + _eventDispatcher->update(); - for (int i = 0; i <= stackCounter; i++) - { - if (stackEffectContainers[i]->effect->isRunning()) - { - stackEffectContainers[i]->effect->updateMillis(); - stackEffectContainers[i]->effect->update(); - } + for (int i = 0; i <= stackCounter; i++) { + if (stackEffectContainers[i]->effect->isRunning()) { + stackEffectContainers[i]->effect->updateMillis(); + stackEffectContainers[i]->effect->update(); } - - if (millis() - ws2812UpdateInterval > UPDATE_INTERVAL_WS2812FX_EFFECTS) - { - // Updating the LEDs too fast leads to undefined behavior. Just update effects every 3ms. - ws2812UpdateInterval = millis(); - - for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) - { - if (ws2812FXstates[i]) - { - if (ws2812FXrunning[i]) - { - ws2812FXDevices[i][0]->getWS2812FX()->service(); - - bool stop = true; - for (int k = 0; k < ws2812FXDeviceCounters[i]; k++) - { - stop &= ws2812FXDevices[i][k]->isStopped(); - } - - if (stop) - { - ws2812FXDevices[i][0]->getWS2812FX()->stop(); - ws2812FXrunning[i] = false; - } - } - else - { - bool start = false; - for (int k = 0; k < ws2812FXDeviceCounters[i]; k++) - { - start |= !ws2812FXDevices[i][k]->isStopped(); - } - - if (start) - { - ws2812FXDevices[i][0]->getWS2812FX()->start(); - ws2812FXrunning[i] = true; - ws2812FXDevices[i][0]->getWS2812FX()->service(); - } - } - } + } + + if (millis() - ws2812UpdateInterval > UPDATE_INTERVAL_WS2812FX_EFFECTS) { + // Updating the LEDs too fast leads to undefined behavior. Just update + // effects every 3ms. + ws2812UpdateInterval = millis(); + + for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) { + if (ws2812FXstates[i]) { + if (ws2812FXrunning[i]) { + ws2812FXDevices[i][0]->getWS2812FX()->service(); + + bool stop = true; + for (int k = 0; k < ws2812FXDeviceCounters[i]; k++) { + stop &= ws2812FXDevices[i][k]->isStopped(); + } + + if (stop) { + ws2812FXDevices[i][0]->getWS2812FX()->stop(); + ws2812FXrunning[i] = false; + } + } else { + bool start = false; + for (int k = 0; k < ws2812FXDeviceCounters[i]; k++) { + start |= !ws2812FXDevices[i][k]->isStopped(); + } + + if (start) { + ws2812FXDevices[i][0]->getWS2812FX()->start(); + ws2812FXrunning[i] = true; + ws2812FXDevices[i][0]->getWS2812FX()->service(); + } } + } } - - if (millis() - ws2812AfterGlowUpdateInterval > UPDATE_INTERVAL_WS2812FX_AFTERGLOW) - { - // Updating the LEDs too fast leads to undefined behavior. Just update every 3ms. - ws2812AfterGlowUpdateInterval = millis(); - for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) - { - if (ws2812FXstates[i] && ws2812FXDevices[i][0]->hasAfterGlowSupport() && !ws2812FXrunning[i]) - { - // No other effect is running, handle after glow effect. - ((CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevices[i][0])->updateAfterGlow(); - ws2812FXDevices[i][0]->getWS2812FX()->show(); - } - } + } + + if (millis() - ws2812AfterGlowUpdateInterval > + UPDATE_INTERVAL_WS2812FX_AFTERGLOW) { + // Updating the LEDs too fast leads to undefined behavior. Just update every + // 3ms. + ws2812AfterGlowUpdateInterval = millis(); + for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) { + if (ws2812FXstates[i] && ws2812FXDevices[i][0]->hasAfterGlowSupport() && + !ws2812FXrunning[i]) { + // No other effect is running, handle after glow effect. + ((CombinedGiAndLightMatrixWS2812FXDevice *)ws2812FXDevices[i][0]) + ->updateAfterGlow(); + ws2812FXDevices[i][0]->getWS2812FX()->show(); + } } - - if (brightnessControlBasePin > 0) - { - if (millis() - brightnessUpdateInterval > UPDATE_INTERVAL_WS2812FX_BRIGHTNESS) - { - // Don't update the brightness too often. - brightnessUpdateInterval = millis(); - for (byte i = 0; i < PPUC_MAX_BRIGHTNESS_CONTROLS; i++) - { - brightnessControlReads[i] = analogRead(brightnessControlBasePin + i) / 4; - } - for (byte i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) - { - if (brightnessControl[i] > 0) - { - setBrightness(i + 1, brightnessControlReads[brightnessControl[i - 1]]); - } - } + } + + if (brightnessControlBasePin > 0) { + if (millis() - brightnessUpdateInterval > + UPDATE_INTERVAL_WS2812FX_BRIGHTNESS) { + // Don't update the brightness too often. + brightnessUpdateInterval = millis(); + for (byte i = 0; i < PPUC_MAX_BRIGHTNESS_CONTROLS; i++) { + brightnessControlReads[i] = + analogRead(brightnessControlBasePin + i) / 4; + } + for (byte i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) { + if (brightnessControl[i] > 0) { + setBrightness(i + 1, + brightnessControlReads[brightnessControl[i - 1]]); } + } } + } } -void EffectsController::start() -{ - for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) - { - if (ws2812FXbrightness[i] == 0) - { - // setBrightness(i + 1, WS2812FX_BRIGHTNESS); - } +void EffectsController::start() { + for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) { + if (ws2812FXbrightness[i] == 0) { + // setBrightness(i + 1, WS2812FX_BRIGHTNESS); } + } - _eventDispatcher->dispatch( - new Event(EVENT_SOURCE_EFFECT, 1, 255)); + _eventDispatcher->dispatch(new Event(EVENT_SOURCE_EFFECT, 1, 255)); } diff --git a/src/EffectsController.h b/src/EffectsController.h index 193066d..28aadc4 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -9,38 +9,38 @@ #define EFFECTSCONTROLLER_h #include "PPUC.h" -#if defined(__IMXRT1062__) // Teensy 4.1 - #include +#if defined(__IMXRT1062__) // Teensy 4.1 +#include #else - #include +#include #endif #include -#include "Effects/Effect.h" -#include "Effects/EffectContainer.h" -#include "EventDispatcher/CrossLinkDebugger.h" -#include "EventDispatcher/Event.h" -#include "EventDispatcher/EventDispatcher.h" -#include "EventDispatcher/EventListener.h" -#include "InputDevices/EffectControllerTestButtons.h" -#include "InputDevices/GeneralIlluminationWPC.h" +#include "EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h" #include "EffectDevices/LedBuiltInDevice.h" #include "EffectDevices/NullDevice.h" -#include "EffectDevices/WavePWMDevice.h" -#include "EffectDevices/WS2812FXDevice.h" -#include "EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h" #include "EffectDevices/RgbStripDevice.h" +#include "EffectDevices/WS2812FXDevice.h" +#include "EffectDevices/WavePWMDevice.h" +#include "Effects/Effect.h" +#include "Effects/EffectContainer.h" +#include "Effects/ImpulsePWMEffect.h" #include "Effects/LedBlinkEffect.h" #include "Effects/LedOnEffect.h" #include "Effects/NullEffect.h" #include "Effects/RGBColorCycleEffect.h" -#include "Effects/WS2812FXEffect.h" -#include "Effects/ImpulsePWMEffect.h" #include "Effects/RampDownStopPWMEffect.h" #include "Effects/SinePWMEffect.h" +#include "Effects/WS2812FXEffect.h" +#include "EventDispatcher/CrossLinkDebugger.h" +#include "EventDispatcher/Event.h" +#include "EventDispatcher/EventDispatcher.h" +#include "EventDispatcher/EventListener.h" +#include "InputDevices/EffectControllerTestButtons.h" +#include "InputDevices/GeneralIlluminationWPC.h" #ifndef EFFECT_STACK_SIZE - #define EFFECT_STACK_SIZE 128 +#define EFFECT_STACK_SIZE 128 #endif #define WS2812FX_BRIGHTNESS 64 @@ -49,368 +49,384 @@ #define UPDATE_INTERVAL_WS2812FX_AFTERGLOW 3 #define UPDATE_INTERVAL_WS2812FX_BRIGHTNESS 10 -#if PPUC_CONTROLLER == CONTROLLER_TEENSY_OUTPUT || PPUC_CONTROLLER == CONTROLLER_TEENSY_OUTPUT_2 || PPUC_CONTROLLER == CONTROLLER_PICO_OUTPUT - #define PPUC_MAX_WS2812FX_DEVICES 7 - #define PPUC_MAX_BRIGHTNESS_CONTROLS 4 +#if PPUC_CONTROLLER == CONTROLLER_TEENSY_OUTPUT || \ + PPUC_CONTROLLER == CONTROLLER_TEENSY_OUTPUT_2 || \ + PPUC_CONTROLLER == CONTROLLER_PICO_OUTPUT +#define PPUC_MAX_WS2812FX_DEVICES 7 +#define PPUC_MAX_BRIGHTNESS_CONTROLS 4 #else - #define PPUC_MAX_WS2812FX_DEVICES 1 - #define PPUC_MAX_BRIGHTNESS_CONTROLS 1 +#define PPUC_MAX_WS2812FX_DEVICES 1 +#define PPUC_MAX_BRIGHTNESS_CONTROLS 1 #endif -#if defined(PPUC_NUM_LEDS_1) && defined(PPUC_LED_TYPE_1) && defined(__IMXRT1062__) - DMAMEM byte frameBuffer1[PPUC_NUM_LEDS_1 * ((PPUC_LED_TYPE_1 < 6) ? 3 : 4) * 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW +#if defined(PPUC_NUM_LEDS_1) && defined(PPUC_LED_TYPE_1) && \ + defined(__IMXRT1062__) +DMAMEM byte frameBuffer1[PPUC_NUM_LEDS_1 * ((PPUC_LED_TYPE_1 < 6) ? 3 : 4) * + 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW #endif -#if defined(PPUC_NUM_LEDS_2) && defined(PPUC_LED_TYPE_2) && defined(__IMXRT1062__) - DMAMEM byte frameBuffer2[PPUC_NUM_LEDS_2 * ((PPUC_LED_TYPE_2 < 6) ? 3 : 4) * 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW +#if defined(PPUC_NUM_LEDS_2) && defined(PPUC_LED_TYPE_2) && \ + defined(__IMXRT1062__) +DMAMEM byte frameBuffer2[PPUC_NUM_LEDS_2 * ((PPUC_LED_TYPE_2 < 6) ? 3 : 4) * + 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW #endif -#if defined(PPUC_NUM_LEDS_3) && defined(PPUC_LED_TYPE_3) && defined(__IMXRT1062__) - DMAMEM byte frameBuffer3[PPUC_NUM_LEDS_3 * ((PPUC_LED_TYPE_3 < 6) ? 3 : 4) * 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW +#if defined(PPUC_NUM_LEDS_3) && defined(PPUC_LED_TYPE_3) && \ + defined(__IMXRT1062__) +DMAMEM byte frameBuffer3[PPUC_NUM_LEDS_3 * ((PPUC_LED_TYPE_3 < 6) ? 3 : 4) * + 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW #endif -#if defined(PPUC_NUM_LEDS_4) && defined(PPUC_LED_TYPE_4) && defined(__IMXRT1062__) - DMAMEM byte frameBuffer4[PPUC_NUM_LEDS_4 * ((PPUC_LED_TYPE_4 < 6) ? 3 : 4) * 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW +#if defined(PPUC_NUM_LEDS_4) && defined(PPUC_LED_TYPE_4) && \ + defined(__IMXRT1062__) +DMAMEM byte frameBuffer4[PPUC_NUM_LEDS_4 * ((PPUC_LED_TYPE_4 < 6) ? 3 : 4) * + 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW #endif -#if defined(PPUC_NUM_LEDS_5) && defined(PPUC_LED_TYPE_5) && defined(__IMXRT1062__) - DMAMEM byte frameBuffer5[PPUC_NUM_LEDS_5 * ((PPUC_LED_TYPE_5 < 6) ? 3 : 4) * 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW +#if defined(PPUC_NUM_LEDS_5) && defined(PPUC_LED_TYPE_5) && \ + defined(__IMXRT1062__) +DMAMEM byte frameBuffer5[PPUC_NUM_LEDS_5 * ((PPUC_LED_TYPE_5 < 6) ? 3 : 4) * + 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW #endif -#if defined(PPUC_NUM_LEDS_6) && defined(PPUC_LED_TYPE_6) && defined(__IMXRT1062__) - DMAMEM byte frameBuffer6[PPUC_NUM_LEDS_6 * ((PPUC_LED_TYPE_6 < 6) ? 3 : 4) * 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW +#if defined(PPUC_NUM_LEDS_6) && defined(PPUC_LED_TYPE_6) && \ + defined(__IMXRT1062__) +DMAMEM byte frameBuffer6[PPUC_NUM_LEDS_6 * ((PPUC_LED_TYPE_6 < 6) ? 3 : 4) * + 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW #endif -#if defined(PPUC_NUM_LEDS_7) && defined(PPUC_LED_TYPE_7) && defined(__IMXRT1062__) - DMAMEM byte frameBuffer7[PPUC_NUM_LEDS_7 * ((PPUC_LED_TYPE_7 < 6) ? 3 : 4) * 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW +#if defined(PPUC_NUM_LEDS_7) && defined(PPUC_LED_TYPE_7) && \ + defined(__IMXRT1062__) +DMAMEM byte frameBuffer7[PPUC_NUM_LEDS_7 * ((PPUC_LED_TYPE_7 < 6) ? 3 : 4) * + 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW #endif class EffectsController : public EventListener { + public: + EffectsController(int ct, int pf) : EventListener() { + controllerType = ct; + platform = pf; + + effectsControllerInstance = this; + _eventDispatcher = new EventDispatcher(); + _eventDispatcher->addListener(this); + + if (controllerType == CONTROLLER_TEENSY_OUTPUT || + controllerType == CONTROLLER_TEENSY_OUTPUT_2 || + controllerType == CONTROLLER_PICO_OUTPUT) { + _ledBuiltInDevice = new LedBuiltInDevice(); + _ledBuiltInDevice->on(); + _nullDevice = new NullDevice(); + _testButtons = new EffectControllerTestButtons(_eventDispatcher); + _shakerPWMDevice = new WavePWMDevice(36); + _shakerPWMDevice->off(); + _ledPWMDevice = new WavePWMDevice(37); + _ledPWMDevice->off(); + if (controllerType != CONTROLLER_TEENSY_OUTPUT) { + _rgbStripeDevice = new RgbStripDevice(9, 10, 11); + _rgbStripeDevice->off(); + } else { + // In revision 0.1.0 these pins are D5-D7, but we don't need them for + // the WPC GI. + pinMode(9, INPUT); + pinMode(10, INPUT); + pinMode(11, INPUT); + } + + brightnessControlBasePin = 38; + +#if defined(PPUC_NUM_LEDS_1) && defined(PPUC_LED_TYPE_1) + ws2812FXDevices[0][0] = + new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_1, 1, PPUC_LED_TYPE_1), + 0, PPUC_NUM_LEDS_1 - 1, 0, 0); + ws2812FXDevices[0][0]->getWS2812FX()->init(); + ws2812FXDeviceCounters[0] = 1; + +#if defined(__IMXRT1062__) // Teensy 4.1 + ws2812Serial[0] = + new WS2812Serial(PPUC_NUM_LEDS_1, frameBuffer1, + ws2812FXDevices[0][0]->getWS2812FX()->getPixels(), 1, + PPUC_LED_TYPE_1); + ws2812Serial[0]->begin(); + ws2812FXDevices[0][0]->getWS2812FX()->setCustomShow( + EffectsController::ws2812SerialShow1); +#endif -public: - EffectsController(int ct, int pf) : EventListener(){ - controllerType = ct; - platform = pf; - - effectsControllerInstance = this; - _eventDispatcher = new EventDispatcher(); - _eventDispatcher->addListener(this); - - if (controllerType == CONTROLLER_TEENSY_OUTPUT || controllerType == CONTROLLER_TEENSY_OUTPUT_2 || controllerType == CONTROLLER_PICO_OUTPUT) { - _ledBuiltInDevice = new LedBuiltInDevice(); - _ledBuiltInDevice->on(); - _nullDevice = new NullDevice(); - _testButtons = new EffectControllerTestButtons(_eventDispatcher); - _shakerPWMDevice = new WavePWMDevice(36); - _shakerPWMDevice->off(); - _ledPWMDevice = new WavePWMDevice(37); - _ledPWMDevice->off(); - if (controllerType != CONTROLLER_TEENSY_OUTPUT) { - _rgbStripeDevice = new RgbStripDevice(9, 10, 11); - _rgbStripeDevice->off(); - } - else { - // In revision 0.1.0 these pins are D5-D7, but we don't need them for the WPC GI. - pinMode(9, INPUT); - pinMode(10, INPUT); - pinMode(11, INPUT); - } - - brightnessControlBasePin = 38; - - #if defined(PPUC_NUM_LEDS_1) && defined(PPUC_LED_TYPE_1) - ws2812FXDevices[0][0] = new WS2812FXDevice( - new WS2812FX(PPUC_NUM_LEDS_1, 1, PPUC_LED_TYPE_1), - 0, - PPUC_NUM_LEDS_1 - 1, - 0, - 0 - ); - ws2812FXDevices[0][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[0] = 1; - - #if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[0] = new WS2812Serial(PPUC_NUM_LEDS_1, frameBuffer1, ws2812FXDevices[0][0]->getWS2812FX()->getPixels(), 1, PPUC_LED_TYPE_1); - ws2812Serial[0]->begin(); - ws2812FXDevices[0][0]->getWS2812FX()->setCustomShow(EffectsController::ws2812SerialShow1); - #endif - - ws2812FXDevices[0][0]->off(); - ws2812FXstates[0] = true; - #endif - #if defined(PPUC_NUM_LEDS_2) && defined(PPUC_LED_TYPE_2) - ws2812FXDevices[1][0] = new WS2812FXDevice( - new WS2812FX(PPUC_NUM_LEDS_2, 8, PPUC_LED_TYPE_2), - 0, - PPUC_NUM_LEDS_2 - 1, - 0, - 0 - ); - ws2812FXDevices[1][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[1] = 1; - - #if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[1] = new WS2812Serial(PPUC_NUM_LEDS_2, frameBuffer2, ws2812FXDevices[1][0]->getWS2812FX()->getPixels(), 8, PPUC_LED_TYPE_2); - ws2812Serial[1]->begin(); - ws2812FXDevices[1][0]->getWS2812FX()->setCustomShow(EffectsController::ws2812SerialShow2); - #endif - - ws2812FXDevices[1][0]->off(); - ws2812FXstates[1] = true; - #endif - #if defined(PPUC_NUM_LEDS_3) && defined(PPUC_LED_TYPE_3) - ws2812FXDevices[2][0] = new WS2812FXDevice( - new WS2812FX(PPUC_NUM_LEDS_3, 14, PPUC_LED_TYPE_3), - 0, - PPUC_NUM_LEDS_3 - 1, - 0, - 0 - ); - ws2812FXDevices[2][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[2] = 1; - - #if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[2] = new WS2812Serial(PPUC_NUM_LEDS_3, frameBuffer3, ws2812FXDevices[2][0]->getWS2812FX()->getPixels(), 14, PPUC_LED_TYPE_3); - ws2812Serial[2]->begin(); - ws2812FXDevices[2][0]->getWS2812FX()->setCustomShow(EffectsController::ws2812SerialShow3); - #endif - - ws2812FXDevices[2][0]->off(); - ws2812FXstates[2] = true; - #endif - #if defined(PPUC_NUM_LEDS_4) && defined(PPUC_LED_TYPE_4) - ws2812FXDevices[3][0] = new WS2812FXDevice( - new WS2812FX(PPUC_NUM_LEDS_4, 17, PPUC_LED_TYPE_4), - 0, - PPUC_NUM_LEDS_4 - 1, - 0, - 0 - ); - ws2812FXDevices[3][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[3] = 1; - - #if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[3] = new WS2812Serial(PPUC_NUM_LEDS_4, frameBuffer4, ws2812FXDevices[3][0]->getWS2812FX()->getPixels(), 17, PPUC_LED_TYPE_4); - ws2812Serial[3]->begin(); - ws2812FXDevices[3][0]->getWS2812FX()->setCustomShow(EffectsController::ws2812SerialShow4); - #endif - - ws2812FXDevices[3][0]->off(); - ws2812FXstates[3] = true; - #endif - #if defined(PPUC_NUM_LEDS_5) && defined(PPUC_LED_TYPE_5) - ws2812FXDevices[4][0] = new WS2812FXDevice( - new WS2812FX(PPUC_NUM_LEDS_5, 20, PPUC_LED_TYPE_5), - 0, - PPUC_NUM_LEDS_5 - 1, - 0, - 0 - ); - ws2812FXDevices[4][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[4] = 1; - - #if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[4] = new WS2812Serial(PPUC_NUM_LEDS_5, frameBuffer5, ws2812FXDevices[4][0]->getWS2812FX()->getPixels(), 20, PPUC_LED_TYPE_5); - ws2812Serial[4]->begin(); - ws2812FXDevices[4][0]->getWS2812FX()->setCustomShow(EffectsController::ws2812SerialShow5); - #endif - - ws2812FXDevices[4][0]->off(); - ws2812FXstates[4] = true; - #endif - #if defined(PPUC_NUM_LEDS_6) && defined(PPUC_LED_TYPE_6) - ws2812FXDevices[5][0] = new WS2812FXDevice( - new WS2812FX(PPUC_NUM_LEDS_6, 24, PPUC_LED_TYPE_6), - 0, - PPUC_NUM_LEDS_6 - 1, - 0, - 0 - ); - ws2812FXDevices[5][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[5] = 1; - - #if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[5] = new WS2812Serial(PPUC_NUM_LEDS_6, frameBuffer6, ws2812FXDevices[5][0]->getWS2812FX()->getPixels(), 24, PPUC_LED_TYPE_6); - ws2812Serial[5]->begin(); - ws2812FXDevices[5][0]->getWS2812FX()->setCustomShow(EffectsController::ws2812SerialShow6); - #endif - - ws2812FXDevices[5][0]->off(); - ws2812FXstates[5] = true; - #endif - #if defined(PPUC_NUM_LEDS_7) && defined(PPUC_LED_TYPE_7) - ws2812FXDevices[6][0] = new WS2812FXDevice( - new WS2812FX(PPUC_NUM_LEDS_7, 29, PPUC_LED_TYPE_7), - 0, - PPUC_NUM_LEDS_7 - 1, - 0, - 0 - ); - ws2812FXDevices[6][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[6] = 1; - - #if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[6] = new WS2812Serial(PPUC_NUM_LEDS_7, frameBuffer7, ws2812FXDevices[6][0]->getWS2812FX()->getPixels(), 29, PPUC_LED_TYPE_7); - ws2812Serial[6]->begin(); - ws2812FXDevices[6][0]->getWS2812FX()->setCustomShow(EffectsController::ws2812SerialShow7); - #endif - - ws2812FXDevices[6][0]->off(); - ws2812FXstates[6] = true; - #endif - _testButtons = new EffectControllerTestButtons(_eventDispatcher); - - if (platform == PLATFORM_WPC) { - _generalIllumintationWPC = new GeneralIlluminationWPC(_eventDispatcher); - _generalIllumintationWPC->start(); - } - } - else if (controllerType == CONTROLLER_NANO_PIN2DMD_OUTPUT) { - _ledBuiltInDevice = new LedBuiltInDevice(); - _ledBuiltInDevice->on(); - _nullDevice = new NullDevice(); - _shakerPWMDevice = new WavePWMDevice(9); - _shakerPWMDevice->off(); - #if defined(PIN_A0) - brightnessControlBasePin = PIN_A0; - #endif - #if defined(PPUC_NUM_LEDS_1) && defined(PPUC_LED_TYPE_1) - ws2812FXDevices[0][0] = new WS2812FXDevice( - new WS2812FX(PPUC_NUM_LEDS_1, 6, PPUC_LED_TYPE_1), - 0, - PPUC_NUM_LEDS_1 - 1, - 0, - 0 - ); - ws2812FXDevices[0][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[0] = 1; - - ws2812FXDevices[0][0]->off(); - ws2812FXstates[0] = true; - #endif - } - else if (controllerType == CONTROLLER_16_8_1) { - // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 -> 58.46 to 935.3 - boardId = 16 - ((int)((analogRead(28) + 29.23) / 58.46)); - - _ledBuiltInDevice = new LedBuiltInDevice(); - _ledBuiltInDevice->on(); - } else { - Serial.print("Unsupported Effects Controller: "); - Serial.println(controllerType); - } - } + ws2812FXDevices[0][0]->off(); + ws2812FXstates[0] = true; +#endif +#if defined(PPUC_NUM_LEDS_2) && defined(PPUC_LED_TYPE_2) + ws2812FXDevices[1][0] = + new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_2, 8, PPUC_LED_TYPE_2), + 0, PPUC_NUM_LEDS_2 - 1, 0, 0); + ws2812FXDevices[1][0]->getWS2812FX()->init(); + ws2812FXDeviceCounters[1] = 1; + +#if defined(__IMXRT1062__) // Teensy 4.1 + ws2812Serial[1] = + new WS2812Serial(PPUC_NUM_LEDS_2, frameBuffer2, + ws2812FXDevices[1][0]->getWS2812FX()->getPixels(), 8, + PPUC_LED_TYPE_2); + ws2812Serial[1]->begin(); + ws2812FXDevices[1][0]->getWS2812FX()->setCustomShow( + EffectsController::ws2812SerialShow2); +#endif + + ws2812FXDevices[1][0]->off(); + ws2812FXstates[1] = true; +#endif +#if defined(PPUC_NUM_LEDS_3) && defined(PPUC_LED_TYPE_3) + ws2812FXDevices[2][0] = + new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_3, 14, PPUC_LED_TYPE_3), + 0, PPUC_NUM_LEDS_3 - 1, 0, 0); + ws2812FXDevices[2][0]->getWS2812FX()->init(); + ws2812FXDeviceCounters[2] = 1; + +#if defined(__IMXRT1062__) // Teensy 4.1 + ws2812Serial[2] = + new WS2812Serial(PPUC_NUM_LEDS_3, frameBuffer3, + ws2812FXDevices[2][0]->getWS2812FX()->getPixels(), + 14, PPUC_LED_TYPE_3); + ws2812Serial[2]->begin(); + ws2812FXDevices[2][0]->getWS2812FX()->setCustomShow( + EffectsController::ws2812SerialShow3); +#endif + + ws2812FXDevices[2][0]->off(); + ws2812FXstates[2] = true; +#endif +#if defined(PPUC_NUM_LEDS_4) && defined(PPUC_LED_TYPE_4) + ws2812FXDevices[3][0] = + new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_4, 17, PPUC_LED_TYPE_4), + 0, PPUC_NUM_LEDS_4 - 1, 0, 0); + ws2812FXDevices[3][0]->getWS2812FX()->init(); + ws2812FXDeviceCounters[3] = 1; + +#if defined(__IMXRT1062__) // Teensy 4.1 + ws2812Serial[3] = + new WS2812Serial(PPUC_NUM_LEDS_4, frameBuffer4, + ws2812FXDevices[3][0]->getWS2812FX()->getPixels(), + 17, PPUC_LED_TYPE_4); + ws2812Serial[3]->begin(); + ws2812FXDevices[3][0]->getWS2812FX()->setCustomShow( + EffectsController::ws2812SerialShow4); +#endif + + ws2812FXDevices[3][0]->off(); + ws2812FXstates[3] = true; +#endif +#if defined(PPUC_NUM_LEDS_5) && defined(PPUC_LED_TYPE_5) + ws2812FXDevices[4][0] = + new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_5, 20, PPUC_LED_TYPE_5), + 0, PPUC_NUM_LEDS_5 - 1, 0, 0); + ws2812FXDevices[4][0]->getWS2812FX()->init(); + ws2812FXDeviceCounters[4] = 1; + +#if defined(__IMXRT1062__) // Teensy 4.1 + ws2812Serial[4] = + new WS2812Serial(PPUC_NUM_LEDS_5, frameBuffer5, + ws2812FXDevices[4][0]->getWS2812FX()->getPixels(), + 20, PPUC_LED_TYPE_5); + ws2812Serial[4]->begin(); + ws2812FXDevices[4][0]->getWS2812FX()->setCustomShow( + EffectsController::ws2812SerialShow5); +#endif - EventDispatcher* eventDispatcher(); + ws2812FXDevices[4][0]->off(); + ws2812FXstates[4] = true; +#endif +#if defined(PPUC_NUM_LEDS_6) && defined(PPUC_LED_TYPE_6) + ws2812FXDevices[5][0] = + new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_6, 24, PPUC_LED_TYPE_6), + 0, PPUC_NUM_LEDS_6 - 1, 0, 0); + ws2812FXDevices[5][0]->getWS2812FX()->init(); + ws2812FXDeviceCounters[5] = 1; + +#if defined(__IMXRT1062__) // Teensy 4.1 + ws2812Serial[5] = + new WS2812Serial(PPUC_NUM_LEDS_6, frameBuffer6, + ws2812FXDevices[5][0]->getWS2812FX()->getPixels(), + 24, PPUC_LED_TYPE_6); + ws2812Serial[5]->begin(); + ws2812FXDevices[5][0]->getWS2812FX()->setCustomShow( + EffectsController::ws2812SerialShow6); +#endif - LedBuiltInDevice* ledBuiltInDevice(); + ws2812FXDevices[5][0]->off(); + ws2812FXstates[5] = true; +#endif +#if defined(PPUC_NUM_LEDS_7) && defined(PPUC_LED_TYPE_7) + ws2812FXDevices[6][0] = + new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_7, 29, PPUC_LED_TYPE_7), + 0, PPUC_NUM_LEDS_7 - 1, 0, 0); + ws2812FXDevices[6][0]->getWS2812FX()->init(); + ws2812FXDeviceCounters[6] = 1; + +#if defined(__IMXRT1062__) // Teensy 4.1 + ws2812Serial[6] = + new WS2812Serial(PPUC_NUM_LEDS_7, frameBuffer7, + ws2812FXDevices[6][0]->getWS2812FX()->getPixels(), + 29, PPUC_LED_TYPE_7); + ws2812Serial[6]->begin(); + ws2812FXDevices[6][0]->getWS2812FX()->setCustomShow( + EffectsController::ws2812SerialShow7); +#endif - NullDevice* nullDevice(); + ws2812FXDevices[6][0]->off(); + ws2812FXstates[6] = true; +#endif + _testButtons = new EffectControllerTestButtons(_eventDispatcher); + + if (platform == PLATFORM_WPC) { + _generalIllumintationWPC = new GeneralIlluminationWPC(_eventDispatcher); + _generalIllumintationWPC->start(); + } + } else if (controllerType == CONTROLLER_NANO_PIN2DMD_OUTPUT) { + _ledBuiltInDevice = new LedBuiltInDevice(); + _ledBuiltInDevice->on(); + _nullDevice = new NullDevice(); + _shakerPWMDevice = new WavePWMDevice(9); + _shakerPWMDevice->off(); +#if defined(PIN_A0) + brightnessControlBasePin = PIN_A0; +#endif +#if defined(PPUC_NUM_LEDS_1) && defined(PPUC_LED_TYPE_1) + ws2812FXDevices[0][0] = + new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_1, 6, PPUC_LED_TYPE_1), + 0, PPUC_NUM_LEDS_1 - 1, 0, 0); + ws2812FXDevices[0][0]->getWS2812FX()->init(); + ws2812FXDeviceCounters[0] = 1; + + ws2812FXDevices[0][0]->off(); + ws2812FXstates[0] = true; +#endif + } else if (controllerType == CONTROLLER_16_8_1) { + // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 + // -> 58.46 to 935.3 + boardId = 16 - ((int)((analogRead(28) + 29.23) / 58.46)); + + _ledBuiltInDevice = new LedBuiltInDevice(); + _ledBuiltInDevice->on(); + } else { + Serial.print("Unsupported Effects Controller: "); + Serial.println(controllerType); + } + } - WavePWMDevice* shakerPWMDevice(); + EventDispatcher* eventDispatcher(); - WavePWMDevice* ledPWMDevice(); + LedBuiltInDevice* ledBuiltInDevice(); - RgbStripDevice* rgbStripDevice(); + NullDevice* nullDevice(); - WS2812FXDevice* ws2812FXDevice(int port); + WavePWMDevice* shakerPWMDevice(); - CombinedGiAndLightMatrixWS2812FXDevice* createCombinedGiAndLightMatrixWs2812FXDevice(int port); + WavePWMDevice* ledPWMDevice(); - CombinedGiAndLightMatrixWS2812FXDevice* giAndLightMatrix(int port); + RgbStripDevice* rgbStripDevice(); - WS2812FXDevice* createWS2812FXDevice(int port, int number, int segments, int firstLED, int lastLED); + WS2812FXDevice* ws2812FXDevice(int port); - WS2812FXDevice* ws2812FXDevice(int port, int number); + CombinedGiAndLightMatrixWS2812FXDevice* + createCombinedGiAndLightMatrixWs2812FXDevice(int port); - GeneralIlluminationWPC* generalIllumintationWPC(); + CombinedGiAndLightMatrixWS2812FXDevice* giAndLightMatrix(int port); - void addEffect(Effect* effect, EffectDevice* device, Event* event, int priority, int repeat, int mode); + WS2812FXDevice* createWS2812FXDevice(int port, int number, int segments, + int firstLED, int lastLED); - //void addEffect(Effect* effect, EffectDevice* device, EventSequence* sequence, int priority, int repeat); + WS2812FXDevice* ws2812FXDevice(int port, int number); - void addEffect(EffectContainer* container); + GeneralIlluminationWPC* generalIllumintationWPC(); - void attachBrightnessControl(byte port, byte poti); + void addEffect(Effect* effect, EffectDevice* device, Event* event, + int priority, int repeat, int mode); - void setBrightness(byte port, byte brightness); + // void addEffect(Effect* effect, EffectDevice* device, EventSequence* + // sequence, int priority, int repeat); - void start(); + void addEffect(EffectContainer* container); - void update(); + void attachBrightnessControl(byte port, byte poti); - void handleEvent(Event* event); + void setBrightness(byte port, byte brightness); - void handleEvent(ConfigEvent* event); + void start(); - #if defined(__IMXRT1062__) // Teensy 4.1 - static void ws2812SerialShow1() { - effectsControllerInstance->ws2812Serial[0]->show(); - } - static void ws2812SerialShow2() { - effectsControllerInstance->ws2812Serial[1]->show(); - } - static void ws2812SerialShow3() { - effectsControllerInstance->ws2812Serial[2]->show(); - } - static void ws2812SerialShow4() { - effectsControllerInstance->ws2812Serial[3]->show(); - } - static void ws2812SerialShow5() { - effectsControllerInstance->ws2812Serial[4]->show(); - } - static void ws2812SerialShow6() { - effectsControllerInstance->ws2812Serial[5]->show(); - } - static void ws2812SerialShow7() { - effectsControllerInstance->ws2812Serial[6]->show(); - } - #endif + void update(); -private: - EventDispatcher* _eventDispatcher; - LedBuiltInDevice* _ledBuiltInDevice; - NullDevice* _nullDevice; - WavePWMDevice* _shakerPWMDevice; - WavePWMDevice* _ledPWMDevice; - RgbStripDevice* _rgbStripeDevice; - WS2812FXDevice* ws2812FXDevices[PPUC_MAX_WS2812FX_DEVICES][10]; - int ws2812FXDeviceCounters[PPUC_MAX_WS2812FX_DEVICES] = {0}; - bool ws2812FXstates[PPUC_MAX_WS2812FX_DEVICES] = {0}; - bool ws2812FXrunning[PPUC_MAX_WS2812FX_DEVICES] = {0}; - bool ws2812FXbrightness[PPUC_MAX_WS2812FX_DEVICES] = {0}; - #if defined(__IMXRT1062__) // Teensy 4.1 - WS2812Serial* ws2812Serial[PPUC_MAX_WS2812FX_DEVICES]; - #endif - EffectContainer* stackEffectContainers[EFFECT_STACK_SIZE]; - int stackCounter = -1; - byte brightnessControl[PPUC_MAX_WS2812FX_DEVICES] = {0}; - byte brightnessControlReads[PPUC_MAX_BRIGHTNESS_CONTROLS] = {0}; - byte brightnessControlBasePin = 0; + void handleEvent(Event* event); - int mode = 0; + void handleEvent(ConfigEvent* event); - byte platform; - byte controllerType; - byte boardId = 255; - byte config_port = 0; - byte config_type = 0; - byte config_amount = 0; - byte config_afterGlow = 0; - byte config_heatUp = 0; - byte config_number = 0; - byte config_ledNumber = 0; - byte config_brightness = 0; - uint32_t config_color = 0; +#if defined(__IMXRT1062__) // Teensy 4.1 + static void ws2812SerialShow1() { + effectsControllerInstance->ws2812Serial[0]->show(); + } + static void ws2812SerialShow2() { + effectsControllerInstance->ws2812Serial[1]->show(); + } + static void ws2812SerialShow3() { + effectsControllerInstance->ws2812Serial[2]->show(); + } + static void ws2812SerialShow4() { + effectsControllerInstance->ws2812Serial[3]->show(); + } + static void ws2812SerialShow5() { + effectsControllerInstance->ws2812Serial[4]->show(); + } + static void ws2812SerialShow6() { + effectsControllerInstance->ws2812Serial[5]->show(); + } + static void ws2812SerialShow7() { + effectsControllerInstance->ws2812Serial[6]->show(); + } +#endif - unsigned long ws2812UpdateInterval = 0; - unsigned long ws2812AfterGlowUpdateInterval = 0; - unsigned long brightnessUpdateInterval = 0; - - EffectControllerTestButtons* _testButtons; - GeneralIlluminationWPC* _generalIllumintationWPC; - - static EffectsController* effectsControllerInstance; + private: + EventDispatcher* _eventDispatcher; + LedBuiltInDevice* _ledBuiltInDevice; + NullDevice* _nullDevice; + WavePWMDevice* _shakerPWMDevice; + WavePWMDevice* _ledPWMDevice; + RgbStripDevice* _rgbStripeDevice; + WS2812FXDevice* ws2812FXDevices[PPUC_MAX_WS2812FX_DEVICES][10]; + int ws2812FXDeviceCounters[PPUC_MAX_WS2812FX_DEVICES] = {0}; + bool ws2812FXstates[PPUC_MAX_WS2812FX_DEVICES] = {0}; + bool ws2812FXrunning[PPUC_MAX_WS2812FX_DEVICES] = {0}; + bool ws2812FXbrightness[PPUC_MAX_WS2812FX_DEVICES] = {0}; +#if defined(__IMXRT1062__) // Teensy 4.1 + WS2812Serial* ws2812Serial[PPUC_MAX_WS2812FX_DEVICES]; +#endif + EffectContainer* stackEffectContainers[EFFECT_STACK_SIZE]; + int stackCounter = -1; + byte brightnessControl[PPUC_MAX_WS2812FX_DEVICES] = {0}; + byte brightnessControlReads[PPUC_MAX_BRIGHTNESS_CONTROLS] = {0}; + byte brightnessControlBasePin = 0; + + int mode = 0; + + byte platform; + byte controllerType; + byte boardId = 255; + byte config_port = 0; + byte config_type = 0; + byte config_amount = 0; + byte config_afterGlow = 0; + byte config_heatUp = 0; + byte config_number = 0; + byte config_ledNumber = 0; + byte config_brightness = 0; + uint32_t config_color = 0; + + unsigned long ws2812UpdateInterval = 0; + unsigned long ws2812AfterGlowUpdateInterval = 0; + unsigned long brightnessUpdateInterval = 0; + + EffectControllerTestButtons* _testButtons; + GeneralIlluminationWPC* _generalIllumintationWPC; + + static EffectsController* effectsControllerInstance; }; #endif diff --git a/src/EventDispatcher/CrossLinkDebugger.cpp b/src/EventDispatcher/CrossLinkDebugger.cpp index 94607e6..42d004b 100644 --- a/src/EventDispatcher/CrossLinkDebugger.cpp +++ b/src/EventDispatcher/CrossLinkDebugger.cpp @@ -1,71 +1,66 @@ #include "CrossLinkDebugger.h" -CrossLinkDebugger::CrossLinkDebugger() -{ +CrossLinkDebugger::CrossLinkDebugger() { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - if (get_core_num() == 0) - { - rp2040.idleOtherCore(); - Serial.println("PPUC IO_16_8_1"); - Serial.print("PPUC board #"); - // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 -> 58.46 to 935.3 - Serial.println(16 - ((int)((analogRead(28) + 29.23) / 58.46))); - Serial.println("PPUC core #0 started"); + if (get_core_num() == 0) { + rp2040.idleOtherCore(); + Serial.println("PPUC IO_16_8_1"); + Serial.print("PPUC board #"); + // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 -> 58.46 + // to 935.3 + Serial.println(16 - ((int)((analogRead(28) + 29.23) / 58.46))); + Serial.println("PPUC core #0 started"); #endif - Serial.println("PPUC CrossLinkDebugger"); - Serial.println("----------------------"); + Serial.println("PPUC CrossLinkDebugger"); + Serial.println("----------------------"); #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.resumeOtherCore(); - } - else - { - rp2040.idleOtherCore(); - Serial.println("PPUC core #1 started"); - rp2040.resumeOtherCore(); - } + rp2040.resumeOtherCore(); + } else { + rp2040.idleOtherCore(); + Serial.println("PPUC core #1 started"); + rp2040.resumeOtherCore(); + } #endif } -void CrossLinkDebugger::handleEvent(Event *event) -{ +void CrossLinkDebugger::handleEvent(Event *event) { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Core "); - Serial.print(get_core_num(), DEC); - Serial.print(" "); + rp2040.idleOtherCore(); + Serial.print("Core "); + Serial.print(get_core_num(), DEC); + Serial.print(" "); #endif - Serial.print("handleEvent: sourceId "); - Serial.print(event->sourceId); - Serial.print(", eventId "); - Serial.print(event->eventId, DEC); - Serial.print(", value "); - Serial.println(event->value, DEC); + Serial.print("handleEvent: sourceId "); + Serial.print(event->sourceId); + Serial.print(", eventId "); + Serial.print(event->eventId, DEC); + Serial.print(", value "); + Serial.println(event->value, DEC); #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.resumeOtherCore(); + rp2040.resumeOtherCore(); #endif } -void CrossLinkDebugger::handleEvent(ConfigEvent *event) -{ +void CrossLinkDebugger::handleEvent(ConfigEvent *event) { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Core "); - Serial.print(get_core_num(), DEC); - Serial.print(" "); + rp2040.idleOtherCore(); + Serial.print("Core "); + Serial.print(get_core_num(), DEC); + Serial.print(" "); #endif - Serial.print("handleConfigEvent: boardId "); - Serial.print(event->boardId, DEC); - Serial.print(", topic "); - Serial.print(event->topic, DEC); - Serial.print(", index "); - Serial.print(event->index, DEC); - Serial.print(", key "); - Serial.print(event->key, DEC); - Serial.print(", value(DEC) "); - Serial.print(event->value, DEC); - Serial.print(", value(HEX) "); - Serial.println(event->value, HEX); + Serial.print("handleConfigEvent: boardId "); + Serial.print(event->boardId, DEC); + Serial.print(", topic "); + Serial.print(event->topic, DEC); + Serial.print(", index "); + Serial.print(event->index, DEC); + Serial.print(", key "); + Serial.print(event->key, DEC); + Serial.print(", value(DEC) "); + Serial.print(event->value, DEC); + Serial.print(", value(HEX) "); + Serial.println(event->value, HEX); #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.resumeOtherCore(); + rp2040.resumeOtherCore(); #endif } diff --git a/src/EventDispatcher/CrossLinkDebugger.h b/src/EventDispatcher/CrossLinkDebugger.h index 3b59de7..5a4103c 100644 --- a/src/EventDispatcher/CrossLinkDebugger.h +++ b/src/EventDispatcher/CrossLinkDebugger.h @@ -13,15 +13,14 @@ #include "Event.h" #include "EventListener.h" -class CrossLinkDebugger : public EventListener -{ -public: +class CrossLinkDebugger : public EventListener { + public: CrossLinkDebugger(); void handleEvent(Event *event); void handleEvent(ConfigEvent *event); -private: + private: static bool lock; }; diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 5f50677..a5bbab8 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -6,158 +6,151 @@ #ifndef EVENT_h #define EVENT_h -#define EVENT_SOURCE_ANY 42 // "*" -#define EVENT_SOURCE_DEBUG 66 // "B" Debug -#define EVENT_CONFIGURATION 67 // "C" Configure I/O -#define EVENT_SOURCE_DMD 68 // "D" VPX/DOF/PUP -#define EVENT_SOURCE_EVENT 69 // "E" VPX/DOF/PUP common event from different system, like -#define EVENT_SOURCE_EFFECT 70 // "F" custom event from running Effect -#define EVENT_SOURCE_GI 71 // "G" WPC GI -#define EVENT_SOURCE_LIGHT 76 // "L" VPX/DOF/PUP lights, mainly playfield inserts -#define EVENT_NULL 78 // "N" NULL event -#define EVENT_SOURCE_SOUND 79 // "O" sound command -#define EVENT_POLL_EVENTS 80 // "P" Poll events command, mainly read switches -#define EVENT_READ_SWITCHES 82 // "R" Read current state of all switches on i/o boards -#define EVENT_SOURCE_SOLENOID 83 // "S" VPX/DOF/PUP includes flashers -#define EVENT_SOURCE_SWITCH 87 // "W" VPX/DOF/PUP -#define EVENT_PING 88 // "X" -#define EVENT_PONG 89 // "Y" -#define EVENT_RESET 90 // "Z" -#define EVENT_RUN 91 // RUN -#define EVENT_NO_ERROR 98 // NO ERROR -#define EVENT_ERROR 99 // ERROR - -#define CONFIG_TOPIC_PLATFORM 102 // "f" -#define CONFIG_TOPIC_LED_STRING 103 // "g" -#define CONFIG_TOPIC_LAMPS 108 // "l" -#define CONFIG_TOPIC_MECHS 109 // "m" -#define CONFIG_TOPIC_PWM 112 // "p" -#define CONFIG_TOPIC_SWITCHES 115 // "s" -#define CONFIG_TOPIC_SWITCH_MATRIX 120 // "x" - -#define CONFIG_TOPIC_HOLD_POWER_ACTIVATION_TIME 65 // "A" -#define CONFIG_TOPIC_BRIGHTNESS 66 // "B" -#define CONFIG_TOPIC_COLOR 67 // "C" -#define CONFIG_TOPIC_FAST_SWITCH 70 // "F" -#define CONFIG_TOPIC_AFTER_GLOW 71 // "G" -#define CONFIG_TOPIC_HOLD_POWER 72 // "H" -#define CONFIG_TOPIC_LED_NUMBER 76 // "L" -#define CONFIG_TOPIC_MAX_PULSE_TIME 77 // "M" -#define CONFIG_TOPIC_NUMBER 78 // "N" -#define CONFIG_TOPIC_AMOUNT_LEDS 79 // "O" -#define CONFIG_TOPIC_PORT 80 // "P" -#define CONFIG_TOPIC_MAX_PULSE_TIME 77 // "M" -#define CONFIG_TOPIC_MIN_PULSE_TIME 84 // "T" -#define CONFIG_TOPIC_LIGHT_UP 85 // "U" -#define CONFIG_TOPIC_ACTIVE_LOW 86 // "V" -#define CONFIG_TOPIC_POWER 87 // "W" -#define CONFIG_TOPIC_TYPE 89 // "Y" -#define CONFIG_TOPIC_NULL 99 // NULL - -#define PWM_TYPE_SOLENOID 1 // Coil -#define PWM_TYPE_FLASHER 2 // Flasher -#define PWM_TYPE_LAMP 3 // Lamp - -#define LED_TYPE_GI 1 // GI -#define LED_TYPE_FLASHER 2 // Flasher -#define LED_TYPE_LAMP 3 // Lamp - -#define MATRIX_TYPE_COLUMN 1 // Column -#define MATRIX_TYPE_ROW 2 // Row - -struct Event -{ - uint8_t sourceId; - uint16_t eventId; - uint8_t value; - bool localFast; - Event(uint8_t sId) - { - sourceId = sId; - eventId = 1; - value = 1; - localFast = false; - } - - Event(uint8_t sId, uint16_t eId) - { - sourceId = sId; - eventId = eId; - value = 1; - localFast = false; - } - - Event(uint8_t sId, uint16_t eId, uint8_t v) - { - sourceId = sId; - eventId = eId; - value = v; - localFast = false; - } - - Event(uint8_t sId, uint16_t eId, uint8_t v, bool lf) { - sourceId = sId; - eventId = eId; - value = v; - localFast = lf; - } - - // Clone the event. - Event(const Event* other) { - sourceId = other->sourceId; - eventId = other->eventId; - value = other->value; - localFast = other->localFast; - } - - bool operator==(const Event &other) const - { - return this->sourceId == other.sourceId && this->eventId == other.eventId && this->value == other.value; - } - - bool operator!=(const Event &other) const - { - return !(*this == other); - } +#define EVENT_SOURCE_ANY 42 // "*" +#define EVENT_SOURCE_DEBUG 66 // "B" Debug +#define EVENT_CONFIGURATION 67 // "C" Configure I/O +#define EVENT_SOURCE_DMD 68 // "D" VPX/DOF/PUP +#define EVENT_SOURCE_EVENT \ + 69 // "E" VPX/DOF/PUP common event from different system, like +#define EVENT_SOURCE_EFFECT 70 // "F" custom event from running Effect +#define EVENT_SOURCE_GI 71 // "G" WPC GI +#define EVENT_SOURCE_LIGHT \ + 76 // "L" VPX/DOF/PUP lights, mainly playfield inserts +#define EVENT_NULL 78 // "N" NULL event +#define EVENT_SOURCE_SOUND 79 // "O" sound command +#define EVENT_POLL_EVENTS 80 // "P" Poll events command, mainly read switches +#define EVENT_READ_SWITCHES \ + 82 // "R" Read current state of all switches on i/o boards +#define EVENT_SOURCE_SOLENOID 83 // "S" VPX/DOF/PUP includes flashers +#define EVENT_SOURCE_SWITCH 87 // "W" VPX/DOF/PUP +#define EVENT_PING 88 // "X" +#define EVENT_PONG 89 // "Y" +#define EVENT_RESET 90 // "Z" +#define EVENT_RUN 91 // RUN +#define EVENT_NO_ERROR 98 // NO ERROR +#define EVENT_ERROR 99 // ERROR + +#define CONFIG_TOPIC_PLATFORM 102 // "f" +#define CONFIG_TOPIC_LED_STRING 103 // "g" +#define CONFIG_TOPIC_LAMPS 108 // "l" +#define CONFIG_TOPIC_MECHS 109 // "m" +#define CONFIG_TOPIC_PWM 112 // "p" +#define CONFIG_TOPIC_SWITCHES 115 // "s" +#define CONFIG_TOPIC_SWITCH_MATRIX 120 // "x" + +#define CONFIG_TOPIC_HOLD_POWER_ACTIVATION_TIME 65 // "A" +#define CONFIG_TOPIC_BRIGHTNESS 66 // "B" +#define CONFIG_TOPIC_COLOR 67 // "C" +#define CONFIG_TOPIC_FAST_SWITCH 70 // "F" +#define CONFIG_TOPIC_AFTER_GLOW 71 // "G" +#define CONFIG_TOPIC_HOLD_POWER 72 // "H" +#define CONFIG_TOPIC_LED_NUMBER 76 // "L" +#define CONFIG_TOPIC_MAX_PULSE_TIME 77 // "M" +#define CONFIG_TOPIC_NUMBER 78 // "N" +#define CONFIG_TOPIC_AMOUNT_LEDS 79 // "O" +#define CONFIG_TOPIC_PORT 80 // "P" +#define CONFIG_TOPIC_MAX_PULSE_TIME 77 // "M" +#define CONFIG_TOPIC_MIN_PULSE_TIME 84 // "T" +#define CONFIG_TOPIC_LIGHT_UP 85 // "U" +#define CONFIG_TOPIC_ACTIVE_LOW 86 // "V" +#define CONFIG_TOPIC_POWER 87 // "W" +#define CONFIG_TOPIC_TYPE 89 // "Y" +#define CONFIG_TOPIC_NULL 99 // NULL + +#define PWM_TYPE_SOLENOID 1 // Coil +#define PWM_TYPE_FLASHER 2 // Flasher +#define PWM_TYPE_LAMP 3 // Lamp + +#define LED_TYPE_GI 1 // GI +#define LED_TYPE_FLASHER 2 // Flasher +#define LED_TYPE_LAMP 3 // Lamp + +#define MATRIX_TYPE_COLUMN 1 // Column +#define MATRIX_TYPE_ROW 2 // Row + +struct Event { + uint8_t sourceId; + uint16_t eventId; + uint8_t value; + bool localFast; + Event(uint8_t sId) { + sourceId = sId; + eventId = 1; + value = 1; + localFast = false; + } + + Event(uint8_t sId, uint16_t eId) { + sourceId = sId; + eventId = eId; + value = 1; + localFast = false; + } + + Event(uint8_t sId, uint16_t eId, uint8_t v) { + sourceId = sId; + eventId = eId; + value = v; + localFast = false; + } + + Event(uint8_t sId, uint16_t eId, uint8_t v, bool lf) { + sourceId = sId; + eventId = eId; + value = v; + localFast = lf; + } + + // Clone the event. + Event(const Event* other) { + sourceId = other->sourceId; + eventId = other->eventId; + value = other->value; + localFast = other->localFast; + } + + bool operator==(const Event& other) const { + return this->sourceId == other.sourceId && this->eventId == other.eventId && + this->value == other.value; + } + + bool operator!=(const Event& other) const { return !(*this == other); } }; -struct ConfigEvent -{ - uint8_t sourceId; // EVENT_CONFIGURATION - uint8_t boardId; // - uint8_t topic; // lamps - uint8_t index; // 0, index of assignment - uint8_t key; // ledType, assignment/brightness - uint32_t value; // FFFF00FF - - ConfigEvent(uint8_t b) - { - sourceId = EVENT_CONFIGURATION; - boardId = b; - topic = CONFIG_TOPIC_NULL; - index = 1; - key = 1; - value = 1; - } - - ConfigEvent(uint8_t b, uint8_t t, uint8_t i, uint8_t k, uint32_t v) - { - sourceId = EVENT_CONFIGURATION; - boardId = b; - topic = t; - index = i; - key = k; - value = v; - } - - // Clone the event. - ConfigEvent(const ConfigEvent* other) { - boardId = other->boardId; - topic = other->topic; - index = other->index; - key = other->key; - value = other->value; - } +struct ConfigEvent { + uint8_t sourceId; // EVENT_CONFIGURATION + uint8_t boardId; // + uint8_t topic; // lamps + uint8_t index; // 0, index of assignment + uint8_t key; // ledType, assignment/brightness + uint32_t value; // FFFF00FF + + ConfigEvent(uint8_t b) { + sourceId = EVENT_CONFIGURATION; + boardId = b; + topic = CONFIG_TOPIC_NULL; + index = 1; + key = 1; + value = 1; + } + + ConfigEvent(uint8_t b, uint8_t t, uint8_t i, uint8_t k, uint32_t v) { + sourceId = EVENT_CONFIGURATION; + boardId = b; + topic = t; + index = i; + key = k; + value = v; + } + + // Clone the event. + ConfigEvent(const ConfigEvent* other) { + boardId = other->boardId; + topic = other->topic; + index = other->index; + key = other->key; + value = other->value; + } }; #endif diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index e6512ce..b8fc6af 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -1,395 +1,328 @@ #include "EventDispatcher.h" -EventDispatcher::EventDispatcher() -{ -} +EventDispatcher::EventDispatcher() {} -void EventDispatcher::setRS485ModePin(int pin) -{ - rs485 = true; - rs485Pin = pin; - pinMode(rs485Pin, OUTPUT); - digitalWrite(rs485Pin, LOW); // Read. +void EventDispatcher::setRS485ModePin(int pin) { + rs485 = true; + rs485Pin = pin; + pinMode(rs485Pin, OUTPUT); + digitalWrite(rs485Pin, LOW); // Read. } -void EventDispatcher::setBoard(byte b) -{ - board = b; -} +void EventDispatcher::setBoard(byte b) { board = b; } -void EventDispatcher::setMultiCoreCrossLink(MultiCoreCrossLink *mccl) -{ +void EventDispatcher::setMultiCoreCrossLink(MultiCoreCrossLink *mccl) { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - multiCoreCrossLink = mccl; - multiCore = true; + multiCoreCrossLink = mccl; + multiCore = true; #endif } -MultiCoreCrossLink *EventDispatcher::getMultiCoreCrossLink() -{ - return multiCoreCrossLink; +MultiCoreCrossLink *EventDispatcher::getMultiCoreCrossLink() { + return multiCoreCrossLink; } -void EventDispatcher::setCrossLinkSerial(HardwareSerial &reference) -{ - hwSerial[0] = (HardwareSerial *)&reference; - crossLink = 0; +void EventDispatcher::setCrossLinkSerial(HardwareSerial &reference) { + hwSerial[0] = (HardwareSerial *)&reference; + crossLink = 0; } -void EventDispatcher::addCrossLinkSerial(HardwareSerial &reference) -{ - hwSerial[++crossLink] = (HardwareSerial *)&reference; - hwSerial[crossLink]->begin(115200); - while (!hwSerial[crossLink]) - { - } +void EventDispatcher::addCrossLinkSerial(HardwareSerial &reference) { + hwSerial[++crossLink] = (HardwareSerial *)&reference; + hwSerial[crossLink]->begin(115200); + while (!hwSerial[crossLink]) { + } } -void EventDispatcher::addListener(EventListener *eventListener) -{ - addListener(eventListener, EVENT_SOURCE_ANY); +void EventDispatcher::addListener(EventListener *eventListener) { + addListener(eventListener, EVENT_SOURCE_ANY); } -void EventDispatcher::addListener(EventListener *eventListener, char sourceId) -{ - if (numListeners < (MAX_EVENT_LISTENERS - 1)) - { - eventListeners[++numListeners] = eventListener; - eventListenerFilters[numListeners] = sourceId; - } +void EventDispatcher::addListener(EventListener *eventListener, char sourceId) { + if (numListeners < (MAX_EVENT_LISTENERS - 1)) { + eventListeners[++numListeners] = eventListener; + eventListenerFilters[numListeners] = sourceId; + } } -void EventDispatcher::dispatch(Event *event) -{ - if (stackCounter < (EVENT_STACK_SIZE - 1)) - { - stackEvents[++stackCounter] = event; +void EventDispatcher::dispatch(Event *event) { + if (stackCounter < (EVENT_STACK_SIZE - 1)) { + stackEvents[++stackCounter] = event; - if (event->localFast) - { - for (byte i = 0; i <= numListeners; i++) - { - - if (event->sourceId == eventListenerFilters[i] || EVENT_SOURCE_ANY == eventListenerFilters[i]) - { - eventListeners[i]->handleEvent(event); - } - } + if (event->localFast) { + for (byte i = 0; i <= numListeners; i++) { + if (event->sourceId == eventListenerFilters[i] || + EVENT_SOURCE_ANY == eventListenerFilters[i]) { + eventListeners[i]->handleEvent(event); } + } } - else - { - // Too many events stacked, delete the event and free the memory. - delete event; - } + } else { + // Too many events stacked, delete the event and free the memory. + delete event; + } } -void EventDispatcher::callListeners(Event *event, int sender, bool flush) -{ - if (!event->localFast) - { - for (byte i = 0; i <= numListeners; i++) - { - if (event->sourceId == eventListenerFilters[i] || EVENT_SOURCE_ANY == eventListenerFilters[i]) - { - eventListeners[i]->handleEvent(event); - } - } +void EventDispatcher::callListeners(Event *event, int sender, bool flush) { + if (!event->localFast) { + for (byte i = 0; i <= numListeners; i++) { + if (event->sourceId == eventListenerFilters[i] || + EVENT_SOURCE_ANY == eventListenerFilters[i]) { + eventListeners[i]->handleEvent(event); + } } - - if (!rs485 || flush) - { - // Send to other micro controller. But only if there's room left in write buffer. Otherwise the program will be - // blocked. The buffer gets full if the data is not fetched by the other controller for any reason. - // @todo Possible optimization to check hwSerial->availableForWrite() >= 6 failed on Arduino for unknown reason. - - if (crossLink != -1 /* && hwSerial->availableForWrite() >= 6 */) - { - msg[0] = 0b11111111; - msg[1] = event->sourceId; - msg[2] = highByte(event->eventId); - msg[3] = lowByte(event->eventId); - msg[4] = event->value; - msg[5] = 0b10101010; - msg[6] = 0b01010101; - - for (int i = 0; i <= crossLink; i++) - { - if (i != sender) - { - hwSerial[i]->write(msg, 7); - } - } + } + + if (!rs485 || flush) { + // Send to other micro controller. But only if there's room left in write + // buffer. Otherwise the program will be blocked. The buffer gets full if + // the data is not fetched by the other controller for any reason. + // @todo Possible optimization to check hwSerial->availableForWrite() >= 6 + // failed on Arduino for unknown reason. + + if (crossLink != -1 /* && hwSerial->availableForWrite() >= 6 */) { + msg[0] = 0b11111111; + msg[1] = event->sourceId; + msg[2] = highByte(event->eventId); + msg[3] = lowByte(event->eventId); + msg[4] = event->value; + msg[5] = 0b10101010; + msg[6] = 0b01010101; + + for (int i = 0; i <= crossLink; i++) { + if (i != sender) { + hwSerial[i]->write(msg, 7); + } + } #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Sent event: sourceId "); - Serial.print(event->sourceId); - Serial.print(", eventId "); - Serial.print(event->eventId, DEC); - Serial.print(", value "); - Serial.println(event->value, DEC); - rp2040.resumeOtherCore(); + rp2040.idleOtherCore(); + Serial.print("Sent event: sourceId "); + Serial.print(event->sourceId); + Serial.print(", eventId "); + Serial.print(event->eventId, DEC); + Serial.print(", value "); + Serial.println(event->value, DEC); + rp2040.resumeOtherCore(); #endif - } } + } #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - if (multiCore && sender != -1 && event->sourceId != EVENT_NULL) - { - multiCoreCrossLink->pushEvent(event); - } + if (multiCore && sender != -1 && event->sourceId != EVENT_NULL) { + multiCoreCrossLink->pushEvent(event); + } #endif - // delete the event and free the memory - delete event; + // delete the event and free the memory + delete event; } -void EventDispatcher::callListeners(ConfigEvent *event, int sender) -{ - for (byte i = 0; i <= numListeners; i++) - { - if (EVENT_CONFIGURATION == eventListenerFilters[i] || EVENT_SOURCE_ANY == eventListenerFilters[i]) - { - eventListeners[i]->handleEvent(event); - } +void EventDispatcher::callListeners(ConfigEvent *event, int sender) { + for (byte i = 0; i <= numListeners; i++) { + if (EVENT_CONFIGURATION == eventListenerFilters[i] || + EVENT_SOURCE_ANY == eventListenerFilters[i]) { + eventListeners[i]->handleEvent(event); } - - if (sender != -1) - { - if (crossLink != -1 /* && hwSerial->availableForWrite() >= 6 */) - { - msg[0] = 0b11111111; - msg[1] = event->sourceId; - msg[2] = event->boardId; - msg[3] = event->topic; - msg[4] = event->index; - msg[5] = event->key; - msg[6] = event->value >> 24; - msg[7] = (event->value >> 16) & 0xff; - msg[8] = (event->value >> 8) & 0xff; - msg[9] = event->value & 0xff; - msg[10] = 0b10101010; - msg[11] = 0b01010101; - - for (int i = 0; i <= crossLink; i++) - { - if (i != sender) - { - hwSerial[i]->write(msg, 12); - } - } + } + + if (sender != -1) { + if (crossLink != -1 /* && hwSerial->availableForWrite() >= 6 */) { + msg[0] = 0b11111111; + msg[1] = event->sourceId; + msg[2] = event->boardId; + msg[3] = event->topic; + msg[4] = event->index; + msg[5] = event->key; + msg[6] = event->value >> 24; + msg[7] = (event->value >> 16) & 0xff; + msg[8] = (event->value >> 8) & 0xff; + msg[9] = event->value & 0xff; + msg[10] = 0b10101010; + msg[11] = 0b01010101; + + for (int i = 0; i <= crossLink; i++) { + if (i != sender) { + hwSerial[i]->write(msg, 12); } + } + } #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - if (multiCoreCrossLink && event->boardId == board) - { - multiCoreCrossLink->pushConfigEvent(event); - } -#endif + if (multiCoreCrossLink && event->boardId == board) { + multiCoreCrossLink->pushConfigEvent(event); } +#endif + } - // delete the event and free the memory - delete event; + // delete the event and free the memory + delete event; } -void EventDispatcher::update() -{ - if (!rs485) - { - for (int i = 0; i <= stackCounter; i++) - { - Event *event = stackEvents[i]; - // Integer MAX_CROSS_LINKS is always higher than crossLinks, so this parameters means "no sender, send to all". - callListeners(event, MAX_CROSS_LINKS, false); - } - // -1 means empty. - stackCounter = -1; +void EventDispatcher::update() { + if (!rs485) { + for (int i = 0; i <= stackCounter; i++) { + Event *event = stackEvents[i]; + // Integer MAX_CROSS_LINKS is always higher than crossLinks, so this + // parameters means "no sender, send to all". + callListeners(event, MAX_CROSS_LINKS, false); } + // -1 means empty. + stackCounter = -1; + } + + for (int i = 0; i <= crossLink; i++) { + if (hwSerial[i]->available() >= 7) { + bool success = false; + + byte startByte = hwSerial[i]->read(); + if (startByte == 255) { + byte sourceId = hwSerial[i]->read(); + if (sourceId != 0) { + if (sourceId == EVENT_CONFIGURATION) { + // Config Event has 12 bytes, 2 bytes are already parsed above. + while (hwSerial[i]->available() < 10) { + } - for (int i = 0; i <= crossLink; i++) - { - if (hwSerial[i]->available() >= 7) - { - bool success = false; - - byte startByte = hwSerial[i]->read(); - if (startByte == 255) - { - byte sourceId = hwSerial[i]->read(); - if (sourceId != 0) - { - if (sourceId == EVENT_CONFIGURATION) - { - // Config Event has 12 bytes, 2 bytes are already parsed above. - while (hwSerial[i]->available() < 10) - { - } - - // We have a ConfigEvent. - byte boardId = hwSerial[i]->read(); - byte topic = hwSerial[i]->read(); - byte index = hwSerial[i]->read(); - byte key = hwSerial[i]->read(); - int value = - (hwSerial[i]->read() << 24) + - (hwSerial[i]->read() << 16) + - (hwSerial[i]->read() << 8) + - hwSerial[i]->read(); - byte stopByte = hwSerial[i]->read(); - if (stopByte == 0b10101010) - { - stopByte = hwSerial[i]->read(); - if (stopByte == 0b01010101) - { - success = true; - callListeners(new ConfigEvent(boardId, topic, index, key, value), i); - } - } + // We have a ConfigEvent. + byte boardId = hwSerial[i]->read(); + byte topic = hwSerial[i]->read(); + byte index = hwSerial[i]->read(); + byte key = hwSerial[i]->read(); + int value = (hwSerial[i]->read() << 24) + + (hwSerial[i]->read() << 16) + + (hwSerial[i]->read() << 8) + hwSerial[i]->read(); + byte stopByte = hwSerial[i]->read(); + if (stopByte == 0b10101010) { + stopByte = hwSerial[i]->read(); + if (stopByte == 0b01010101) { + success = true; + callListeners( + new ConfigEvent(boardId, topic, index, key, value), i); + } + } + } else { + word eventId = word(hwSerial[i]->read(), hwSerial[i]->read()); + if (eventId != 0) { + byte value = hwSerial[i]->read(); + byte stopByte = hwSerial[i]->read(); + if (stopByte == 0b10101010) { + stopByte = hwSerial[i]->read(); + if (stopByte == 0b01010101) { + success = true; + callListeners(new Event((char)sourceId, eventId, value), i, + false); + + if (sourceId == EVENT_POLL_EVENTS && board == value) { + if (rs485) { + digitalWrite(rs485Pin, HIGH); // Write. + // Wait until the RS485 converter switched to write mode. + delayMicroseconds(500); } - else - { - word eventId = word(hwSerial[i]->read(), hwSerial[i]->read()); - if (eventId != 0) - { - byte value = hwSerial[i]->read(); - byte stopByte = hwSerial[i]->read(); - if (stopByte == 0b10101010) - { - stopByte = hwSerial[i]->read(); - if (stopByte == 0b01010101) - { - success = true; - callListeners(new Event((char)sourceId, eventId, value), i, false); - - if (sourceId == EVENT_POLL_EVENTS && board == value) - { - if (rs485) - { - digitalWrite(rs485Pin, HIGH); // Write. - // Wait until the RS485 converter switched to write mode. - delayMicroseconds(500); - } - - for (int k = 0; k <= stackCounter; k++) - { - Event *event = stackEvents[k]; - // Integer MAX_CROSS_LINKS is always higher than crossLinks, so this parameters means "no sender, send to all". - callListeners(event, MAX_CROSS_LINKS, true); - } - // -1 means empty. - stackCounter = -1; - - // Send NULL event to indicate that transmission is complete. - callListeners(new Event(EVENT_NULL, 1, board), MAX_CROSS_LINKS, true); - - if (rs485) - { - // Flush the serial buffer and wait until done. - hwSerial[i]->flush(); - digitalWrite(rs485Pin, LOW); // Read. - // Wait until the RS485 converter switched back to read mode. - delayMicroseconds(200); - } - } - } - else - { + + for (int k = 0; k <= stackCounter; k++) { + Event *event = stackEvents[k]; + // Integer MAX_CROSS_LINKS is always higher than + // crossLinks, so this parameters means "no sender, send + // to all". + callListeners(event, MAX_CROSS_LINKS, true); + } + // -1 means empty. + stackCounter = -1; + + // Send NULL event to indicate that transmission is + // complete. + callListeners(new Event(EVENT_NULL, 1, board), + MAX_CROSS_LINKS, true); + + if (rs485) { + // Flush the serial buffer and wait until done. + hwSerial[i]->flush(); + digitalWrite(rs485Pin, LOW); // Read. + // Wait until the RS485 converter switched back to read + // mode. + delayMicroseconds(200); + } + } + } else { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Received wrong second stop byte "); - Serial.println(stopByte, DEC); - rp2040.resumeOtherCore(); + rp2040.idleOtherCore(); + Serial.print("Received wrong second stop byte "); + Serial.println(stopByte, DEC); + rp2040.resumeOtherCore(); #endif - } - } - else - { + } + } else { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Received wrong first stop byte "); - Serial.println(stopByte, DEC); - rp2040.resumeOtherCore(); + rp2040.idleOtherCore(); + Serial.print("Received wrong first stop byte "); + Serial.println(stopByte, DEC); + rp2040.resumeOtherCore(); #endif - } - } - else - { + } + } else { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Received invalid event id "); - Serial.println(eventId, DEC); - rp2040.resumeOtherCore(); + rp2040.idleOtherCore(); + Serial.print("Received invalid event id "); + Serial.println(eventId, DEC); + rp2040.resumeOtherCore(); #endif - } - } - } - else - { + } + } + } else { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Received invalid source id "); - Serial.println(sourceId, DEC); - rp2040.resumeOtherCore(); + rp2040.idleOtherCore(); + Serial.print("Received invalid source id "); + Serial.println(sourceId, DEC); + rp2040.resumeOtherCore(); #endif - } - } - else - { + } + } else { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Received wrong start byte "); - Serial.println(startByte, DEC); - rp2040.resumeOtherCore(); + rp2040.idleOtherCore(); + Serial.print("Received wrong start byte "); + Serial.println(startByte, DEC); + rp2040.resumeOtherCore(); #endif - // We didn't receive a start byte. Fake "success" to start over with the next byte. - success = true; - } - - if (success) - { - if (error) - { - error = false; - dispatch(new Event(EVENT_NO_ERROR, 1, board)); - } - } - else - { - error = true; - dispatch(new Event(EVENT_ERROR, 1, board)); - - while (hwSerial[i]->available()) - { - byte bits = hwSerial[i]->read(); - if (bits == 0b10101010 && hwSerial[i]->available()) - { - bits = hwSerial[i]->read(); - if (bits == 0b01010101) - { - // Now we should be back in sync. - break; - } - } - } + // We didn't receive a start byte. Fake "success" to start over with the + // next byte. + success = true; + } + + if (success) { + if (error) { + error = false; + dispatch(new Event(EVENT_NO_ERROR, 1, board)); + } + } else { + error = true; + dispatch(new Event(EVENT_ERROR, 1, board)); + + while (hwSerial[i]->available()) { + byte bits = hwSerial[i]->read(); + if (bits == 0b10101010 && hwSerial[i]->available()) { + bits = hwSerial[i]->read(); + if (bits == 0b01010101) { + // Now we should be back in sync. + break; } + } } + } } + } #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - if (multiCoreCrossLink) - { - if (multiCoreCrossLink->eventAvailable()) - { - Event *event = multiCoreCrossLink->popEvent(); - callListeners(event, -1, false); - } + if (multiCoreCrossLink) { + if (multiCoreCrossLink->eventAvailable()) { + Event *event = multiCoreCrossLink->popEvent(); + callListeners(event, -1, false); + } - if (multiCoreCrossLink->configEventAvailable()) - { - ConfigEvent *configEvent = multiCoreCrossLink->popConfigEvent(); - callListeners(configEvent, -1); - } + if (multiCoreCrossLink->configEventAvailable()) { + ConfigEvent *configEvent = multiCoreCrossLink->popConfigEvent(); + callListeners(configEvent, -1); } + } #endif } diff --git a/src/EventDispatcher/EventDispatcher.h b/src/EventDispatcher/EventDispatcher.h index 068e1a8..2eff10b 100644 --- a/src/EventDispatcher/EventDispatcher.h +++ b/src/EventDispatcher/EventDispatcher.h @@ -10,10 +10,9 @@ #include -#include "MultiCoreCrossLink.h" - #include "Event.h" #include "EventListener.h" +#include "MultiCoreCrossLink.h" #ifndef MAX_EVENT_LISTENERS #define MAX_EVENT_LISTENERS 32 @@ -28,52 +27,52 @@ #endif class EventDispatcher { -public: - EventDispatcher(); + public: + EventDispatcher(); - void setRS485ModePin(int pin); + void setRS485ModePin(int pin); - void setBoard(byte b); + void setBoard(byte b); - void setMultiCoreCrossLink(MultiCoreCrossLink* mccl); + void setMultiCoreCrossLink(MultiCoreCrossLink* mccl); - MultiCoreCrossLink* getMultiCoreCrossLink(); + MultiCoreCrossLink* getMultiCoreCrossLink(); - void setCrossLinkSerial(HardwareSerial &reference); + void setCrossLinkSerial(HardwareSerial& reference); - void addCrossLinkSerial(HardwareSerial &reference); + void addCrossLinkSerial(HardwareSerial& reference); - void addListener(EventListener* eventListener, char sourceId); + void addListener(EventListener* eventListener, char sourceId); - void addListener(EventListener* eventListener); + void addListener(EventListener* eventListener); - void dispatch(Event* event); + void dispatch(Event* event); - void update(); + void update(); -private: - void callListeners(Event* event, int sender, bool flush); + private: + void callListeners(Event* event, int sender, bool flush); - void callListeners(ConfigEvent* event, int sender); + void callListeners(ConfigEvent* event, int sender); - Event* stackEvents[EVENT_STACK_SIZE]; - int stackCounter = -1; + Event* stackEvents[EVENT_STACK_SIZE]; + int stackCounter = -1; - EventListener* eventListeners[MAX_EVENT_LISTENERS]; - char eventListenerFilters[MAX_EVENT_LISTENERS]; - int numListeners = -1; + EventListener* eventListeners[MAX_EVENT_LISTENERS]; + char eventListenerFilters[MAX_EVENT_LISTENERS]; + int numListeners = -1; - byte msg[12]; + byte msg[12]; - bool rs485 = false; - int rs485Pin = 0; - byte board = 255; - bool error = false; + bool rs485 = false; + int rs485Pin = 0; + byte board = 255; + bool error = false; - bool multiCore = false; - int crossLink = -1; - HardwareSerial* hwSerial[MAX_CROSS_LINKS]; - MultiCoreCrossLink* multiCoreCrossLink; + bool multiCore = false; + int crossLink = -1; + HardwareSerial* hwSerial[MAX_CROSS_LINKS]; + MultiCoreCrossLink* multiCoreCrossLink; }; #endif diff --git a/src/EventDispatcher/EventListener.h b/src/EventDispatcher/EventListener.h index 948b55f..2b0c67f 100644 --- a/src/EventDispatcher/EventListener.h +++ b/src/EventDispatcher/EventListener.h @@ -11,9 +11,9 @@ #include "Event.h" class EventListener { -public: - virtual void handleEvent(Event* event) = 0; - virtual void handleEvent(ConfigEvent* event) = 0; + public: + virtual void handleEvent(Event* event) = 0; + virtual void handleEvent(ConfigEvent* event) = 0; }; #endif diff --git a/src/EventDispatcher/MultiCoreCrossLink.h b/src/EventDispatcher/MultiCoreCrossLink.h index d5c8ce7..16851de 100644 --- a/src/EventDispatcher/MultiCoreCrossLink.h +++ b/src/EventDispatcher/MultiCoreCrossLink.h @@ -6,100 +6,90 @@ #endif #include + #include "Event.h" #ifndef EVENT_STACK_SIZE #define EVENT_STACK_SIZE 128 #endif -typedef struct QueuedEvent -{ - byte sourceId; - word eventId; - byte value; - bool localFast; +typedef struct QueuedEvent { + byte sourceId; + word eventId; + byte value; + bool localFast; } EventItem; -typedef struct QueuedConfigEvent -{ - byte boardId; - byte topic; - byte index; - byte key; - int value; +typedef struct QueuedConfigEvent { + byte boardId; + byte topic; + byte index; + byte key; + int value; } ConfigEventItem; -class MultiCoreCrossLink -{ +class MultiCoreCrossLink { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) -public: - MultiCoreCrossLink() - { - if (get_core_num() == 0) - { - queue_init(&_eventQueue[0], sizeof(EventItem), EVENT_STACK_SIZE); - queue_init(&_eventQueue[1], sizeof(EventItem), EVENT_STACK_SIZE); - queue_init(&_configEventQueue, sizeof(ConfigEventItem), EVENT_STACK_SIZE); - } + public: + MultiCoreCrossLink() { + if (get_core_num() == 0) { + queue_init(&_eventQueue[0], sizeof(EventItem), EVENT_STACK_SIZE); + queue_init(&_eventQueue[1], sizeof(EventItem), EVENT_STACK_SIZE); + queue_init(&_configEventQueue, sizeof(ConfigEventItem), EVENT_STACK_SIZE); } + } - ~MultiCoreCrossLink(){}; + ~MultiCoreCrossLink(){}; - void pushEvent(Event *event) - { - QueuedEvent queuedEvent; - queuedEvent.sourceId = event->sourceId; - queuedEvent.eventId = event->eventId; - queuedEvent.value = event->value; - queuedEvent.localFast = event->localFast; + void pushEvent(Event *event) { + QueuedEvent queuedEvent; + queuedEvent.sourceId = event->sourceId; + queuedEvent.eventId = event->eventId; + queuedEvent.value = event->value; + queuedEvent.localFast = event->localFast; - queue_add_blocking(&_eventQueue[get_core_num() ^ 1], &queuedEvent); - } + queue_add_blocking(&_eventQueue[get_core_num() ^ 1], &queuedEvent); + } - Event *popEvent() - { - QueuedEvent queuedEvent; - queue_remove_blocking(&_eventQueue[get_core_num()], &queuedEvent); + Event *popEvent() { + QueuedEvent queuedEvent; + queue_remove_blocking(&_eventQueue[get_core_num()], &queuedEvent); - return new Event(queuedEvent.sourceId, queuedEvent.eventId, queuedEvent.value, queuedEvent.localFast); - } + return new Event(queuedEvent.sourceId, queuedEvent.eventId, + queuedEvent.value, queuedEvent.localFast); + } - int eventAvailable() - { - return queue_get_level(&_eventQueue[get_core_num()]); - } + int eventAvailable() { return queue_get_level(&_eventQueue[get_core_num()]); } - void pushConfigEvent(ConfigEvent *event) - { - if (get_core_num() == 0) - { - QueuedConfigEvent queuedConfigEvent; - queuedConfigEvent.boardId = event->boardId; - queuedConfigEvent.topic = event->topic; - queuedConfigEvent.index = event->index; - queuedConfigEvent.key = event->key; - queuedConfigEvent.value = event->value; - - queue_add_blocking(&_configEventQueue, &queuedConfigEvent); - } + void pushConfigEvent(ConfigEvent *event) { + if (get_core_num() == 0) { + QueuedConfigEvent queuedConfigEvent; + queuedConfigEvent.boardId = event->boardId; + queuedConfigEvent.topic = event->topic; + queuedConfigEvent.index = event->index; + queuedConfigEvent.key = event->key; + queuedConfigEvent.value = event->value; + + queue_add_blocking(&_configEventQueue, &queuedConfigEvent); } + } - ConfigEvent *popConfigEvent() - { - QueuedConfigEvent queuedConfigEvent; - queue_remove_blocking(&_configEventQueue, &queuedConfigEvent); + ConfigEvent *popConfigEvent() { + QueuedConfigEvent queuedConfigEvent; + queue_remove_blocking(&_configEventQueue, &queuedConfigEvent); - return new ConfigEvent(queuedConfigEvent.boardId, queuedConfigEvent.topic, queuedConfigEvent.index, queuedConfigEvent.key, queuedConfigEvent.value); - } + return new ConfigEvent(queuedConfigEvent.boardId, queuedConfigEvent.topic, + queuedConfigEvent.index, queuedConfigEvent.key, + queuedConfigEvent.value); + } - int configEventAvailable() - { - return get_core_num() == 1 && queue_get_level(&_configEventQueue); - } + int configEventAvailable() { + return get_core_num() == 1 && queue_get_level(&_configEventQueue); + } -private: - queue_t _eventQueue[2]; - queue_t _configEventQueue; + private: + queue_t _eventQueue[2]; + queue_t _configEventQueue; #endif }; diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 315ecdd..893ae76 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -1,199 +1,172 @@ #include "IOBoardController.h" -IOBoardController::IOBoardController(int cT) -{ - _eventDispatcher = new EventDispatcher(); - _eventDispatcher->addListener(this, EVENT_CONFIGURATION); - _eventDispatcher->addListener(this, EVENT_PING); - _eventDispatcher->addListener(this, EVENT_RUN); - _eventDispatcher->addListener(this, EVENT_RESET); - - controllerType = cT; - - if (controllerType == CONTROLLER_16_8_1) - { - // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 -> 58.46 to 935.3 - boardId = 16 - ((int)((analogRead(28) + 29.23) / 58.46)); - _eventDispatcher->setRS485ModePin(2); - _eventDispatcher->setBoard(boardId); - _eventDispatcher->setCrossLinkSerial(Serial1); +IOBoardController::IOBoardController(int cT) { + _eventDispatcher = new EventDispatcher(); + _eventDispatcher->addListener(this, EVENT_CONFIGURATION); + _eventDispatcher->addListener(this, EVENT_PING); + _eventDispatcher->addListener(this, EVENT_RUN); + _eventDispatcher->addListener(this, EVENT_RESET); + + controllerType = cT; + + if (controllerType == CONTROLLER_16_8_1) { + // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 -> 58.46 + // to 935.3 + boardId = 16 - ((int)((analogRead(28) + 29.23) / 58.46)); + _eventDispatcher->setRS485ModePin(2); + _eventDispatcher->setBoard(boardId); + _eventDispatcher->setCrossLinkSerial(Serial1); #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - _multiCoreCrossLink = new MultiCoreCrossLink(); - _eventDispatcher->setMultiCoreCrossLink(_multiCoreCrossLink); + _multiCoreCrossLink = new MultiCoreCrossLink(); + _eventDispatcher->setMultiCoreCrossLink(_multiCoreCrossLink); #endif - _pwmDevices = new PwmDevices(_eventDispatcher); - _switches = new Switches(boardId, _eventDispatcher); - _switchMatrix = new SwitchMatrix(boardId, _eventDispatcher); - } + _pwmDevices = new PwmDevices(_eventDispatcher); + _switches = new Switches(boardId, _eventDispatcher); + _switchMatrix = new SwitchMatrix(boardId, _eventDispatcher); + } } -void IOBoardController::update() -{ - if (running) - { - if (activeSwitches) - { - switches()->update(); - } - if (activeSwitchMatrix) - { - switchMatrix()->update(); - } - if (activePwmDevices) - { - pwmDevices()->update(); - } +void IOBoardController::update() { + if (running) { + if (activeSwitches) { + switches()->update(); } + if (activeSwitchMatrix) { + switchMatrix()->update(); + } + if (activePwmDevices) { + pwmDevices()->update(); + } + } - eventDispatcher()->update(); + eventDispatcher()->update(); } -void IOBoardController::handleEvent(Event *event) -{ - switch (event->sourceId) - { +void IOBoardController::handleEvent(Event *event) { + switch (event->sourceId) { case EVENT_PING: - _eventDispatcher->dispatch(new Event(EVENT_PONG, 1, boardId)); - break; + _eventDispatcher->dispatch(new Event(EVENT_PONG, 1, boardId)); + break; case EVENT_RUN: - running = (bool)event->value; - break; + running = (bool)event->value; + break; case EVENT_RESET: - // @todo clear all configurations or reboot the device. - break; - } + // @todo clear all configurations or reboot the device. + break; + } } -void IOBoardController::handleEvent(ConfigEvent *event) -{ - if (event->boardId == boardId) - { - switch (event->topic) - { - case CONFIG_TOPIC_SWITCHES: - switch (event->key) - { - case CONFIG_TOPIC_PORT: - port = event->value; - break; - case CONFIG_TOPIC_NUMBER: - _switches->registerSwitch((byte)port, event->value); - activeSwitches = true; - break; - } +void IOBoardController::handleEvent(ConfigEvent *event) { + if (event->boardId == boardId) { + switch (event->topic) { + case CONFIG_TOPIC_SWITCHES: + switch (event->key) { + case CONFIG_TOPIC_PORT: + port = event->value; break; + case CONFIG_TOPIC_NUMBER: + _switches->registerSwitch((byte)port, event->value); + activeSwitches = true; + break; + } + break; - case CONFIG_TOPIC_SWITCH_MATRIX: - switch (event->key) - { - case CONFIG_TOPIC_ACTIVE_LOW: - if (event->value) - { - _switchMatrix->setActiveLow(); - } - break; - case CONFIG_TOPIC_MAX_PULSE_TIME: - _switchMatrix->setPulseTime((byte)event->value); - break; - case CONFIG_TOPIC_TYPE: - type = event->value; - number = 0; - port = 0; - break; - case CONFIG_TOPIC_NUMBER: - number = event->value; - break; - case CONFIG_TOPIC_PORT: - port = event->value; - if (MATRIX_TYPE_COLUMN == type) - { - _switchMatrix->registerColumn(port, number); - } - else - { - _switchMatrix->registerRow(port, number); - } - activeSwitchMatrix = true; - break; + case CONFIG_TOPIC_SWITCH_MATRIX: + switch (event->key) { + case CONFIG_TOPIC_ACTIVE_LOW: + if (event->value) { + _switchMatrix->setActiveLow(); } - break; + case CONFIG_TOPIC_MAX_PULSE_TIME: + _switchMatrix->setPulseTime((byte)event->value); + break; + case CONFIG_TOPIC_TYPE: + type = event->value; + number = 0; + port = 0; + break; + case CONFIG_TOPIC_NUMBER: + number = event->value; + break; + case CONFIG_TOPIC_PORT: + port = event->value; + if (MATRIX_TYPE_COLUMN == type) { + _switchMatrix->registerColumn(port, number); + } else { + _switchMatrix->registerRow(port, number); + } + activeSwitchMatrix = true; + break; + } - case CONFIG_TOPIC_PWM: - switch (event->key) - { - case CONFIG_TOPIC_PORT: - port = event->value; - number = 0; - power = 0; - minPulseTime = 0; - maxPulseTime = 0; - holdPower = 0; - holdPowerActivationTime = 0; - fastSwitch = 0; - break; - case CONFIG_TOPIC_NUMBER: - number = event->value; - break; - case CONFIG_TOPIC_POWER: - power = event->value; - break; - case CONFIG_TOPIC_MIN_PULSE_TIME: - minPulseTime = event->value; - break; - case CONFIG_TOPIC_MAX_PULSE_TIME: - maxPulseTime = event->value; - break; - case CONFIG_TOPIC_HOLD_POWER: - holdPower = event->value; - break; - case CONFIG_TOPIC_HOLD_POWER_ACTIVATION_TIME: - holdPowerActivationTime = event->value; - break; - case CONFIG_TOPIC_FAST_SWITCH: - fastSwitch = event->value; - break; - case CONFIG_TOPIC_TYPE: - switch (event->value) - { - case PWM_TYPE_SOLENOID: // Coil - _pwmDevices->registerSolenoid((byte)port, number, power, minPulseTime, maxPulseTime, holdPower, holdPowerActivationTime, fastSwitch); - activePwmDevices = true; - break; - case PWM_TYPE_FLASHER: // Flasher - _pwmDevices->registerFlasher((byte)port, number, power); - activePwmDevices = true; - break; - case PWM_TYPE_LAMP: // Lamp - _pwmDevices->registerLamp((byte)port, number, power); - activePwmDevices = true; - break; - } + break; + + case CONFIG_TOPIC_PWM: + switch (event->key) { + case CONFIG_TOPIC_PORT: + port = event->value; + number = 0; + power = 0; + minPulseTime = 0; + maxPulseTime = 0; + holdPower = 0; + holdPowerActivationTime = 0; + fastSwitch = 0; + break; + case CONFIG_TOPIC_NUMBER: + number = event->value; + break; + case CONFIG_TOPIC_POWER: + power = event->value; + break; + case CONFIG_TOPIC_MIN_PULSE_TIME: + minPulseTime = event->value; + break; + case CONFIG_TOPIC_MAX_PULSE_TIME: + maxPulseTime = event->value; + break; + case CONFIG_TOPIC_HOLD_POWER: + holdPower = event->value; + break; + case CONFIG_TOPIC_HOLD_POWER_ACTIVATION_TIME: + holdPowerActivationTime = event->value; + break; + case CONFIG_TOPIC_FAST_SWITCH: + fastSwitch = event->value; + break; + case CONFIG_TOPIC_TYPE: + switch (event->value) { + case PWM_TYPE_SOLENOID: // Coil + _pwmDevices->registerSolenoid( + (byte)port, number, power, minPulseTime, maxPulseTime, + holdPower, holdPowerActivationTime, fastSwitch); + activePwmDevices = true; + break; + case PWM_TYPE_FLASHER: // Flasher + _pwmDevices->registerFlasher((byte)port, number, power); + activePwmDevices = true; + break; + case PWM_TYPE_LAMP: // Lamp + _pwmDevices->registerLamp((byte)port, number, power); + activePwmDevices = true; break; } break; } + break; } + } } -PwmDevices *IOBoardController::pwmDevices() -{ - return _pwmDevices; -} +PwmDevices *IOBoardController::pwmDevices() { return _pwmDevices; } -Switches *IOBoardController::switches() -{ - return _switches; -} +Switches *IOBoardController::switches() { return _switches; } -SwitchMatrix *IOBoardController::switchMatrix() -{ - return _switchMatrix; -} +SwitchMatrix *IOBoardController::switchMatrix() { return _switchMatrix; } -EventDispatcher *IOBoardController::eventDispatcher() -{ - return _eventDispatcher; +EventDispatcher *IOBoardController::eventDispatcher() { + return _eventDispatcher; } diff --git a/src/IOBoardController.h b/src/IOBoardController.h index 7032d42..961fed0 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -14,59 +14,57 @@ #ifndef IOBOARDCONTROLLER_h #define IOBOARDCONTROLLER_h -#include "PPUC.h" - #include "EventDispatcher/Event.h" #include "EventDispatcher/EventDispatcher.h" #include "EventDispatcher/MultiCoreCrossLink.h" #include "IODevices/PwmDevices.h" -#include "IODevices/Switches.h" #include "IODevices/SwitchMatrix.h" +#include "IODevices/Switches.h" +#include "PPUC.h" -class IOBoardController : public EventListener -{ -public: - IOBoardController(int controllerType); +class IOBoardController : public EventListener { + public: + IOBoardController(int controllerType); - PwmDevices *pwmDevices(); + PwmDevices *pwmDevices(); - Switches *switches(); + Switches *switches(); - SwitchMatrix *switchMatrix(); + SwitchMatrix *switchMatrix(); - EventDispatcher *eventDispatcher(); + EventDispatcher *eventDispatcher(); - void handleEvent(Event *event); + void handleEvent(Event *event); - void handleEvent(ConfigEvent *event); + void handleEvent(ConfigEvent *event); - void update(); + void update(); -private: - PwmDevices *_pwmDevices; - Switches *_switches; - SwitchMatrix *_switchMatrix; + private: + PwmDevices *_pwmDevices; + Switches *_switches; + SwitchMatrix *_switchMatrix; - bool running = false; - bool activePwmDevices = false; - bool activeSwitches = false; - bool activeSwitchMatrix = false; + bool running = false; + bool activePwmDevices = false; + bool activeSwitches = false; + bool activeSwitchMatrix = false; - int controllerType; - byte boardId; - byte port = 0; - byte number = 0; - byte power = 0; - byte minPulseTime = 0; - byte maxPulseTime = 0; - byte holdPower = 0; - byte holdPowerActivationTime = 0; - byte fastSwitch = 0; - byte type = 0; + int controllerType; + byte boardId; + byte port = 0; + byte number = 0; + byte power = 0; + byte minPulseTime = 0; + byte maxPulseTime = 0; + byte holdPower = 0; + byte holdPowerActivationTime = 0; + byte fastSwitch = 0; + byte type = 0; - EventDispatcher *_eventDispatcher; + EventDispatcher *_eventDispatcher; #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - MultiCoreCrossLink *_multiCoreCrossLink; + MultiCoreCrossLink *_multiCoreCrossLink; #endif }; diff --git a/src/IODevices/PwmDevices.cpp b/src/IODevices/PwmDevices.cpp index 0675063..64859a5 100644 --- a/src/IODevices/PwmDevices.cpp +++ b/src/IODevices/PwmDevices.cpp @@ -1,156 +1,131 @@ #include "PwmDevices.h" -void PwmDevices::registerSolenoid(byte p, byte n, byte pow, byte minPT, byte maxPT, byte hP, byte hPAT, byte fS) -{ - if (last < MAX_PWM_OUTPUTS) - { - port[last] = p; - number[last] = n; - power[last] = pow; - minPulseTime[last] = minPT; - maxPulseTime[last] = maxPT; - holdPower[last] = hP; - holdPowerActivationTime[last] = hPAT; - fastSwitch[last] = fS; +void PwmDevices::registerSolenoid(byte p, byte n, byte pow, byte minPT, + byte maxPT, byte hP, byte hPAT, byte fS) { + if (last < MAX_PWM_OUTPUTS) { + port[last] = p; + number[last] = n; + power[last] = pow; + minPulseTime[last] = minPT; + maxPulseTime[last] = maxPT; + holdPower[last] = hP; + holdPowerActivationTime[last] = hPAT; + fastSwitch[last] = fS; - pinMode(p, OUTPUT); - analogWrite(p, 0); - type[last++] = PWM_TYPE_SOLENOID; - } + pinMode(p, OUTPUT); + analogWrite(p, 0); + type[last++] = PWM_TYPE_SOLENOID; + } } -void PwmDevices::registerFlasher(byte p, byte n, byte pow) -{ - if (last < MAX_PWM_OUTPUTS) - { - port[last] = p; - number[last] = n; - power[last] = pow; +void PwmDevices::registerFlasher(byte p, byte n, byte pow) { + if (last < MAX_PWM_OUTPUTS) { + port[last] = p; + number[last] = n; + power[last] = pow; - pinMode(p, OUTPUT); - analogWrite(p, 0); - type[last++] = PWM_TYPE_FLASHER; - } + pinMode(p, OUTPUT); + analogWrite(p, 0); + type[last++] = PWM_TYPE_FLASHER; + } } -void PwmDevices::registerLamp(byte p, byte n, byte pow) -{ - if (last < MAX_PWM_OUTPUTS) - { - port[last] = p; - number[last] = n; - power[last] = pow; +void PwmDevices::registerLamp(byte p, byte n, byte pow) { + if (last < MAX_PWM_OUTPUTS) { + port[last] = p; + number[last] = n; + power[last] = pow; - pinMode(p, OUTPUT); - analogWrite(p, 0); - type[last++] = PWM_TYPE_LAMP; - } + pinMode(p, OUTPUT); + analogWrite(p, 0); + type[last++] = PWM_TYPE_LAMP; + } } -void PwmDevices::update() -{ - _ms = millis(); +void PwmDevices::update() { + _ms = millis(); - // Iterate over all outputs. - for (byte i = 0; i < last; i++) - { - if (activated[i] > 0) - { - // The output is active. - if ( - (scheduled[i] && ((_ms - activated[i]) > minPulseTime[i])) || - ((maxPulseTime[i] > 0) && ((_ms - activated[i]) > maxPulseTime[i]))) - { - // Deactivate the output if it is scheduled for delayed deactivation and the minimum pulse time is reached. - // Deactivate the output if the maximum pulse time is reached. - analogWrite(port[i], 0); - activated[i] = 0; - scheduled[i] = false; - } - else if ((holdPowerActivationTime[i] > 0) && ((_ms - activated[i]) > holdPowerActivationTime[i])) - { - // Reduce the power of the activated output if the hold power activation time pased since the activation. - analogWrite(port[i], holdPower[i]); - } - } + // Iterate over all outputs. + for (byte i = 0; i < last; i++) { + if (activated[i] > 0) { + // The output is active. + if ((scheduled[i] && ((_ms - activated[i]) > minPulseTime[i])) || + ((maxPulseTime[i] > 0) && ((_ms - activated[i]) > maxPulseTime[i]))) { + // Deactivate the output if it is scheduled for delayed deactivation and + // the minimum pulse time is reached. Deactivate the output if the + // maximum pulse time is reached. + analogWrite(port[i], 0); + activated[i] = 0; + scheduled[i] = false; + } else if ((holdPowerActivationTime[i] > 0) && + ((_ms - activated[i]) > holdPowerActivationTime[i])) { + // Reduce the power of the activated output if the hold power activation + // time pased since the activation. + analogWrite(port[i], holdPower[i]); + } } + } } -void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) -{ - _ms = millis(); +void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) { + _ms = millis(); - if (targetState && !activated[i]) - { - // Event received to activate the output and output isn't activated already. - // Activate it! - analogWrite(port[i], power[i]); - // Rememebr whin it got activated. - activated[i] = _ms; - } - else if (!targetState && activated[i]) - { - // Event received to deactivate the output. - // Check if a minimum pulse time is configured for this output. - if (minPulseTime[i] > 0 && (_ms - activated[i]) < minPulseTime[i]) - { - // A minimum pulse time is configured for this output. - // Don't deactivate it immediately but schedule its later deactivation. - scheduled[i] = true; - } - else - { - // Deactivate the output. - analogWrite(port[i], 0); - // Mark the output as deactivated. - activated[i] = 0; - } + if (targetState && !activated[i]) { + // Event received to activate the output and output isn't activated already. + // Activate it! + analogWrite(port[i], power[i]); + // Rememebr whin it got activated. + activated[i] = _ms; + } else if (!targetState && activated[i]) { + // Event received to deactivate the output. + // Check if a minimum pulse time is configured for this output. + if (minPulseTime[i] > 0 && (_ms - activated[i]) < minPulseTime[i]) { + // A minimum pulse time is configured for this output. + // Don't deactivate it immediately but schedule its later deactivation. + scheduled[i] = true; + } else { + // Deactivate the output. + analogWrite(port[i], 0); + // Mark the output as deactivated. + activated[i] = 0; } + } } -void PwmDevices::handleEvent(Event *event) -{ - _ms = millis(); +void PwmDevices::handleEvent(Event *event) { + _ms = millis(); - switch (event->eventId) - { + switch (event->eventId) { case EVENT_SOURCE_SOLENOID: - for (byte i = 0; i < last; i++) - { - if ((type[i] == PWM_TYPE_SOLENOID || type[i] == PWM_TYPE_FLASHER) && number[i] == (byte)event->eventId) - { - updateSolenoidOrFlasher((bool)event->value, i); - } + for (byte i = 0; i < last; i++) { + if ((type[i] == PWM_TYPE_SOLENOID || type[i] == PWM_TYPE_FLASHER) && + number[i] == (byte)event->eventId) { + updateSolenoidOrFlasher((bool)event->value, i); } - break; + } + break; case EVENT_SOURCE_SWITCH: - // A switch event was triggered or received. Activate or deactivate any output - // that is configured as "fastSwitch" for that switch. - for (byte i = 0; i < last; i++) - { - if (type[i] == PWM_TYPE_SOLENOID && fastSwitch[i] == (byte)event->eventId) - { - updateSolenoidOrFlasher((bool)event->value, i); - } + // A switch event was triggered or received. Activate or deactivate any + // output that is configured as "fastSwitch" for that switch. + for (byte i = 0; i < last; i++) { + if (type[i] == PWM_TYPE_SOLENOID && + fastSwitch[i] == (byte)event->eventId) { + updateSolenoidOrFlasher((bool)event->value, i); } - break; + } + break; case EVENT_SOURCE_LIGHT: - for (byte i = 0; i < last; i++) - { - if (type[i] == PWM_TYPE_LAMP && number[i] == (byte)event->eventId) - { - if (event->value) - { - analogWrite(port[i], power[i]); - } - else if (activated[i]) - { - analogWrite(port[i], 0); - } - } + for (byte i = 0; i < last; i++) { + if (type[i] == PWM_TYPE_LAMP && number[i] == (byte)event->eventId) { + if (event->value) { + analogWrite(port[i], power[i]); + } else if (activated[i]) { + analogWrite(port[i], 0); + } } - break; - } + } + break; + } } \ No newline at end of file diff --git a/src/IODevices/PwmDevices.h b/src/IODevices/PwmDevices.h index bbcc45e..e2bda2b 100644 --- a/src/IODevices/PwmDevices.h +++ b/src/IODevices/PwmDevices.h @@ -16,44 +16,43 @@ #define MAX_PWM_OUTPUTS 16 #endif -class PwmDevices : public EventListener -{ -public: - // Constructor - PwmDevices(EventDispatcher *eventDispatcher) - { - eventDispatcher->addListener(this, EVENT_SOURCE_LIGHT); - eventDispatcher->addListener(this, EVENT_SOURCE_SOLENOID); - eventDispatcher->addListener(this, EVENT_SOURCE_SWITCH); - } - - void registerSolenoid(byte p, byte n, byte pow, byte minPT, byte maxPT, byte hP, byte hPAT, byte fS); - void registerFlasher(byte p, byte n, byte pow); - void registerLamp(byte p, byte n, byte pow); - - void update(); - - void handleEvent(Event *event); - - void handleEvent(ConfigEvent *event) {} - -private: - unsigned long _ms; - - byte port[MAX_PWM_OUTPUTS] = {0}; - byte number[MAX_PWM_OUTPUTS] = {0}; - byte power[MAX_PWM_OUTPUTS] = {0}; - byte minPulseTime[MAX_PWM_OUTPUTS] = {0}; - byte maxPulseTime[MAX_PWM_OUTPUTS] = {0}; - byte holdPower[MAX_PWM_OUTPUTS] = {0}; - byte holdPowerActivationTime[MAX_PWM_OUTPUTS] = {0}; - byte fastSwitch[MAX_PWM_OUTPUTS] = {0}; - byte type[MAX_PWM_OUTPUTS] = {0}; - unsigned long activated[MAX_PWM_OUTPUTS] = {0}; - bool scheduled[MAX_PWM_OUTPUTS] = {0}; - byte last = 0; - - void updateSolenoidOrFlasher(bool targetState, byte i); +class PwmDevices : public EventListener { + public: + // Constructor + PwmDevices(EventDispatcher *eventDispatcher) { + eventDispatcher->addListener(this, EVENT_SOURCE_LIGHT); + eventDispatcher->addListener(this, EVENT_SOURCE_SOLENOID); + eventDispatcher->addListener(this, EVENT_SOURCE_SWITCH); + } + + void registerSolenoid(byte p, byte n, byte pow, byte minPT, byte maxPT, + byte hP, byte hPAT, byte fS); + void registerFlasher(byte p, byte n, byte pow); + void registerLamp(byte p, byte n, byte pow); + + void update(); + + void handleEvent(Event *event); + + void handleEvent(ConfigEvent *event) {} + + private: + unsigned long _ms; + + byte port[MAX_PWM_OUTPUTS] = {0}; + byte number[MAX_PWM_OUTPUTS] = {0}; + byte power[MAX_PWM_OUTPUTS] = {0}; + byte minPulseTime[MAX_PWM_OUTPUTS] = {0}; + byte maxPulseTime[MAX_PWM_OUTPUTS] = {0}; + byte holdPower[MAX_PWM_OUTPUTS] = {0}; + byte holdPowerActivationTime[MAX_PWM_OUTPUTS] = {0}; + byte fastSwitch[MAX_PWM_OUTPUTS] = {0}; + byte type[MAX_PWM_OUTPUTS] = {0}; + unsigned long activated[MAX_PWM_OUTPUTS] = {0}; + bool scheduled[MAX_PWM_OUTPUTS] = {0}; + byte last = 0; + + void updateSolenoidOrFlasher(bool targetState, byte i); }; #endif diff --git a/src/IODevices/SwitchMatrix.cpp b/src/IODevices/SwitchMatrix.cpp index 69fb1fe..577390d 100644 --- a/src/IODevices/SwitchMatrix.cpp +++ b/src/IODevices/SwitchMatrix.cpp @@ -1,129 +1,98 @@ #include "SwitchMatrix.h" -void SwitchMatrix::setActiveLow() -{ - activeLow = true; -} +void SwitchMatrix::setActiveLow() { activeLow = true; } -void SwitchMatrix::setPulseTime(byte pT) -{ - pulseTime = pT; -} +void SwitchMatrix::setPulseTime(byte pT) { pulseTime = pT; } -void SwitchMatrix::registerColumn(byte p, byte n) -{ - if (n > 0 && n < MAX_COLUMNS) - { - columns[n - 1] = p; - pinMode(p, OUTPUT); - } +void SwitchMatrix::registerColumn(byte p, byte n) { + if (n > 0 && n < MAX_COLUMNS) { + columns[n - 1] = p; + pinMode(p, OUTPUT); + } } -void SwitchMatrix::registerRow(byte p, byte n) -{ - if (n > 0 && n < MAX_ROWS) - { - rows[n - 1] = p; - pinMode(p, INPUT); - - } +void SwitchMatrix::registerRow(byte p, byte n) { + if (n > 0 && n < MAX_ROWS) { + rows[n - 1] = p; + pinMode(p, INPUT); + } } -void SwitchMatrix::update() -{ - unsigned long ms = millis(); - if (active) - { - if (ms > (_ms + (int)(pulseTime / 2))) - { - for (int row = 0; row < MAX_ROWS; row++) - { - if (rows[row] != -1 && !toggled[column][row]) - { - bool new_state = digitalRead(rows[row]); - if (new_state != state[column][row]) - { - state[column][row] = new_state; - toggled[column][row] = true; +void SwitchMatrix::update() { + unsigned long ms = millis(); + if (active) { + if (ms > (_ms + (int)(pulseTime / 2))) { + for (int row = 0; row < MAX_ROWS; row++) { + if (rows[row] != -1 && !toggled[column][row]) { + bool new_state = digitalRead(rows[row]); + if (new_state != state[column][row]) { + state[column][row] = new_state; + toggled[column][row] = true; - word number = (column + 1) * (row + 1); - if (platform != PLATFORM_DATA_EAST) - { - number = ((column + 1) * 10) + (row + 1); - } - // Dispatch all switch events as "local fast". - // If a PWM output registered to it, we have "fast flip". Useful for flippers, kick backs, jets and - // sling shots. - _eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, number, state[column][row], true)); - } - } + word number = (column + 1) * (row + 1); + if (platform != PLATFORM_DATA_EAST) { + number = ((column + 1) * 10) + (row + 1); } + // Dispatch all switch events as "local fast". + // If a PWM output registered to it, we have "fast flip". Useful for + // flippers, kick backs, jets and sling shots. + _eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, number, + state[column][row], true)); + } } + } + } - if (ms > (_ms + pulseTime)) - { - digitalWrite(columns[column], activeLow); - active = false; - _ms = ms; - } + if (ms > (_ms + pulseTime)) { + digitalWrite(columns[column], activeLow); + active = false; + _ms = ms; + } + } else if (!active && (ms > (_ms + pauseTime))) { + column++; + if (column >= MAX_COLUMNS) { + column = 0; } - else if (!active && (ms > (_ms + pauseTime))) - { - column++; - if (column >= MAX_COLUMNS) - { - column = 0; - } - // If column is not in use (-1), the next update will increase the column. - if (columns[column] != -1) - { - digitalWrite(columns[column], !activeLow); - active = true; - _ms = ms; - } + // If column is not in use (-1), the next update will increase the column. + if (columns[column] != -1) { + digitalWrite(columns[column], !activeLow); + active = true; + _ms = ms; } + } } -void SwitchMatrix::handleEvent(Event *event) -{ - switch (event->sourceId) - { +void SwitchMatrix::handleEvent(Event *event) { + switch (event->sourceId) { case EVENT_POLL_EVENTS: - if (boardId == (byte)event->value) - { - // This I/O board has been polled for events, so all current switch states are transmitted. - // Reset switch toggles. - for (int col = 0; col < MAX_COLUMNS; col++) - { - for (int row = 0; row < MAX_ROWS; row++) - { - toggled[col][row] = false; - } - } + if (boardId == (byte)event->value) { + // This I/O board has been polled for events, so all current switch + // states are transmitted. Reset switch toggles. + for (int col = 0; col < MAX_COLUMNS; col++) { + for (int row = 0; row < MAX_ROWS; row++) { + toggled[col][row] = false; + } } - break; + } + break; case EVENT_READ_SWITCHES: - // The CPU requested all current states. - for (int col = 0; col < MAX_COLUMNS; col++) - { - if (columns[col] != -1) - { - for (int row = 0; row < MAX_ROWS; row++) - { - if (rows[row] != -1) - { - word number = (column + 1) * (row + 1); - if (platform != PLATFORM_DATA_EAST) - { - number = ((column + 1) * 10) + (row + 1); - } - _eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, number, state[column][row])); - } - } + // The CPU requested all current states. + for (int col = 0; col < MAX_COLUMNS; col++) { + if (columns[col] != -1) { + for (int row = 0; row < MAX_ROWS; row++) { + if (rows[row] != -1) { + word number = (column + 1) * (row + 1); + if (platform != PLATFORM_DATA_EAST) { + number = ((column + 1) * 10) + (row + 1); + } + _eventDispatcher->dispatch( + new Event(EVENT_SOURCE_SWITCH, number, state[column][row])); } + } } - break; - } + } + break; + } } diff --git a/src/IODevices/SwitchMatrix.h b/src/IODevices/SwitchMatrix.h index 5d8155a..a26d603 100644 --- a/src/IODevices/SwitchMatrix.h +++ b/src/IODevices/SwitchMatrix.h @@ -6,9 +6,9 @@ #ifndef SwitchMatrix_h #define SwitchMatrix_h -#include "../PPUC.h" #include "../EventDispatcher/Event.h" #include "../EventDispatcher/EventDispatcher.h" +#include "../PPUC.h" #ifndef MAX_COLUMNS #define MAX_COLUMNS 10 @@ -18,62 +18,58 @@ #define MAX_ROWS 8 #endif -class SwitchMatrix : public EventListener -{ -public: - SwitchMatrix(byte bId, EventDispatcher *eD) - { - boardId = bId; - platform = PLATFORM_LIBPINMAME; - pulseTime = 2; - pauseTime = 2; - activeLow = false; - active = false; - - for (int col = 0; col < MAX_COLUMNS; col++) - { - columns[col] = -1; - } - for (int row = 0; row < MAX_ROWS; row++) - { - rows[row] = -1; - } - - _ms = millis(); - _eventDispatcher = eD; - _eventDispatcher->addListener(this, EVENT_POLL_EVENTS); - _eventDispatcher->addListener(this, EVENT_READ_SWITCHES); +class SwitchMatrix : public EventListener { + public: + SwitchMatrix(byte bId, EventDispatcher *eD) { + boardId = bId; + platform = PLATFORM_LIBPINMAME; + pulseTime = 2; + pauseTime = 2; + activeLow = false; + active = false; + + for (int col = 0; col < MAX_COLUMNS; col++) { + columns[col] = -1; } + for (int row = 0; row < MAX_ROWS; row++) { + rows[row] = -1; + } + + _ms = millis(); + _eventDispatcher = eD; + _eventDispatcher->addListener(this, EVENT_POLL_EVENTS); + _eventDispatcher->addListener(this, EVENT_READ_SWITCHES); + } - void registerColumn(byte p, byte n); - void registerRow(byte p, byte n); + void registerColumn(byte p, byte n); + void registerRow(byte p, byte n); - void setActiveLow(); - void setPulseTime(byte pT); + void setActiveLow(); + void setPulseTime(byte pT); - void update(); + void update(); - void handleEvent(Event *event); + void handleEvent(Event *event); - void handleEvent(ConfigEvent *event) {} + void handleEvent(ConfigEvent *event) {} -private: - byte boardId; - byte platform; - byte pulseTime; - byte pauseTime; - bool activeLow; - bool active; + private: + byte boardId; + byte platform; + byte pulseTime; + byte pauseTime; + bool activeLow; + bool active; - unsigned long _ms; + unsigned long _ms; - int columns[MAX_COLUMNS]; - int rows[MAX_ROWS]; - bool state[MAX_COLUMNS][MAX_ROWS] = {0}; - bool toggled[MAX_COLUMNS][MAX_ROWS] = {0}; - byte column = 0; + int columns[MAX_COLUMNS]; + int rows[MAX_ROWS]; + bool state[MAX_COLUMNS][MAX_ROWS] = {0}; + bool toggled[MAX_COLUMNS][MAX_ROWS] = {0}; + byte column = 0; - EventDispatcher *_eventDispatcher; + EventDispatcher *_eventDispatcher; }; #endif diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index 85553b4..e934089 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -1,85 +1,73 @@ #include "Switches.h" -void Switches::registerSwitch(byte p, byte n) -{ - if (last < (MAX_SWITCHES - 1)) - { - if (p >= 15 && p <= 18) - { - // Set mid power output as input. - pinMode(p, OUTPUT); - digitalWrite(p, HIGH); - delayMicroseconds(10); - digitalWrite(p, LOW); - } - - pinMode(p, INPUT); - delayMicroseconds(10); - port[++last] = p; - number[last] = n; - toggled[last] = false; - state[last] = !digitalRead(p); +void Switches::registerSwitch(byte p, byte n) { + if (last < (MAX_SWITCHES - 1)) { + if (p >= 15 && p <= 18) { + // Set mid power output as input. + pinMode(p, OUTPUT); + digitalWrite(p, HIGH); + delayMicroseconds(10); + digitalWrite(p, LOW); } + + pinMode(p, INPUT); + delayMicroseconds(10); + port[++last] = p; + number[last] = n; + toggled[last] = false; + state[last] = !digitalRead(p); + } } -void Switches::update() -{ - // Wait for SWITCH_DEBOUNCE milliseconds to debounce the switches. That covers the edge case that a switch was hit - // right before the last polling of events. After SWITCH_DEBOUNCE milliseconds every switch is allowed to toggle - // once until the events get polled again. - if (millis() - _ms >= SWITCH_DEBOUNCE) - { - for (int i = 0; i <= last; i++) - { - if (!toggled[i]) - { - bool new_state = !digitalRead(port[i]); - if (new_state != state[i]) - { - state[i] = new_state; - toggled[i] = true; - // Dispatch all switch events as "local fast". - // If a PWM output registered to it, we have "fast flip". Useful for flippers, kick backs, jets and - // sling shots. - _eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), state[i], true)); - } - } +void Switches::update() { + // Wait for SWITCH_DEBOUNCE milliseconds to debounce the switches. That covers + // the edge case that a switch was hit right before the last polling of + // events. After SWITCH_DEBOUNCE milliseconds every switch is allowed to + // toggle once until the events get polled again. + if (millis() - _ms >= SWITCH_DEBOUNCE) { + for (int i = 0; i <= last; i++) { + if (!toggled[i]) { + bool new_state = !digitalRead(port[i]); + if (new_state != state[i]) { + state[i] = new_state; + toggled[i] = true; + // Dispatch all switch events as "local fast". + // If a PWM output registered to it, we have "fast flip". Useful for + // flippers, kick backs, jets and sling shots. + _eventDispatcher->dispatch(new Event( + EVENT_SOURCE_SWITCH, word(0, number[i]), state[i], true)); } + } } + } } -void Switches::handleEvent(Event *event) -{ - switch (event->sourceId) - { +void Switches::handleEvent(Event *event) { + switch (event->sourceId) { case EVENT_POLL_EVENTS: - if (boardId == (byte)event->value) - { - // This I/O board has been polled for events, so all current switch states are transmitted. Reset switch - // debounce timer and toggles. - _ms = millis(); - for (int i = 0; i <= last; i++) - { - toggled[i] = false; - } + if (boardId == (byte)event->value) { + // This I/O board has been polled for events, so all current switch + // states are transmitted. Reset switch debounce timer and toggles. + _ms = millis(); + for (int i = 0; i <= last; i++) { + toggled[i] = false; } - break; + } + break; case EVENT_READ_SWITCHES: - // The CPU requested all current states. - for (int i = 0; i <= last; i++) - { - // Send all states of switches that haven't been toggled since last poll (and dispatched their event already). - if (!toggled[i]) - { - _eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), state[i])); - } - else - { - toggled[i] = false; - } + // The CPU requested all current states. + for (int i = 0; i <= last; i++) { + // Send all states of switches that haven't been toggled since last poll + // (and dispatched their event already). + if (!toggled[i]) { + _eventDispatcher->dispatch( + new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), state[i])); + } else { + toggled[i] = false; } - _ms = millis(); - break; - } + } + _ms = millis(); + break; + } } diff --git a/src/IODevices/Switches.h b/src/IODevices/Switches.h index 7bdd2f7..f2a6759 100644 --- a/src/IODevices/Switches.h +++ b/src/IODevices/Switches.h @@ -22,34 +22,34 @@ #endif class Switches : public EventListener { -public: - Switches(byte bId, EventDispatcher* eD) { - boardId = bId; - _ms = millis(); - _eventDispatcher = eD; - _eventDispatcher->addListener(this, EVENT_POLL_EVENTS); - _eventDispatcher->addListener(this, EVENT_READ_SWITCHES); - } + public: + Switches(byte bId, EventDispatcher* eD) { + boardId = bId; + _ms = millis(); + _eventDispatcher = eD; + _eventDispatcher->addListener(this, EVENT_POLL_EVENTS); + _eventDispatcher->addListener(this, EVENT_READ_SWITCHES); + } - void registerSwitch(byte p, byte n); + void registerSwitch(byte p, byte n); - void update(); + void update(); - void handleEvent(Event* event); + void handleEvent(Event* event); - void handleEvent(ConfigEvent* event) {} + void handleEvent(ConfigEvent* event) {} -private: - byte boardId; - unsigned long _ms; + private: + byte boardId; + unsigned long _ms; - byte port[MAX_SWITCHES] = {0}; - byte number[MAX_SWITCHES] = {0}; - bool state[MAX_SWITCHES] = {0}; - bool toggled[MAX_SWITCHES] = {0}; - int last = -1; + byte port[MAX_SWITCHES] = {0}; + byte number[MAX_SWITCHES] = {0}; + bool state[MAX_SWITCHES] = {0}; + bool toggled[MAX_SWITCHES] = {0}; + int last = -1; - EventDispatcher* _eventDispatcher; + EventDispatcher* _eventDispatcher; }; #endif diff --git a/src/InputController.cpp b/src/InputController.cpp index cef5510..781b7a7 100644 --- a/src/InputController.cpp +++ b/src/InputController.cpp @@ -1,56 +1,44 @@ #include "InputController.h" InputController::InputController(int controllerType, byte pf) { - _eventDispatcher = new EventDispatcher(); - InputController(controllerType, pf, _eventDispatcher); + _eventDispatcher = new EventDispatcher(); + InputController(controllerType, pf, _eventDispatcher); } -InputController::InputController(int controllerType, byte pf, EventDispatcher* eventDispatcher) { - pinMode(LED_BUILTIN, OUTPUT); - - platform = pf; - _eventDispatcher = eventDispatcher; - - if (controllerType == CONTROLLER_MEGA_ALL_INPUT) { - _solenoids = new Solenoids(controllerType, _eventDispatcher); - _switchMatrix = new SwitchMatrix(_eventDispatcher, platform); - _lightMatrix = new LightMatrix(_eventDispatcher, platform); - _pin2Dmd = new PIN2DMD(_eventDispatcher); - _pupComLink = new PUPComLink(); - _testButtons = new InputControllerTestButtons(_eventDispatcher); - } - else if (controllerType == CONTROLLER_NANO_PIN2DMD_OUTPUT) { - _pin2Dmd = new PIN2DMD(_eventDispatcher); - } else { - Serial.print("Unsupported Input Controller: "); - Serial.println(controllerType); - } -} +InputController::InputController(int controllerType, byte pf, + EventDispatcher* eventDispatcher) { + pinMode(LED_BUILTIN, OUTPUT); -Solenoids* InputController::solenoids() { - return _solenoids; -} + platform = pf; + _eventDispatcher = eventDispatcher; -SwitchMatrix* InputController::switchMatrix() { - return _switchMatrix; + if (controllerType == CONTROLLER_MEGA_ALL_INPUT) { + _solenoids = new Solenoids(controllerType, _eventDispatcher); + _switchMatrix = new SwitchMatrix(_eventDispatcher, platform); + _lightMatrix = new LightMatrix(_eventDispatcher, platform); + _pin2Dmd = new PIN2DMD(_eventDispatcher); + _pupComLink = new PUPComLink(); + _testButtons = new InputControllerTestButtons(_eventDispatcher); + } else if (controllerType == CONTROLLER_NANO_PIN2DMD_OUTPUT) { + _pin2Dmd = new PIN2DMD(_eventDispatcher); + } else { + Serial.print("Unsupported Input Controller: "); + Serial.println(controllerType); + } } -LightMatrix* InputController::lightMatrix() { - return _lightMatrix; -} +Solenoids* InputController::solenoids() { return _solenoids; } -PIN2DMD* InputController::pin2Dmd() { - return _pin2Dmd; -} +SwitchMatrix* InputController::switchMatrix() { return _switchMatrix; } -PUPComLink* InputController::pupComLink() { - return _pupComLink; -} +LightMatrix* InputController::lightMatrix() { return _lightMatrix; } + +PIN2DMD* InputController::pin2Dmd() { return _pin2Dmd; } + +PUPComLink* InputController::pupComLink() { return _pupComLink; } InputControllerTestButtons* InputController::testButtons() { - return _testButtons; + return _testButtons; } -EventDispatcher* InputController::eventDispatcher() { - return _eventDispatcher; -} +EventDispatcher* InputController::eventDispatcher() { return _eventDispatcher; } diff --git a/src/InputController.h b/src/InputController.h index 3c1971b..2de9612 100644 --- a/src/InputController.h +++ b/src/InputController.h @@ -6,47 +6,47 @@ #ifndef INPUTCONTROLLER_h #define INPUTCONTROLLER_h -#include "PPUC.h" - #include "EventDispatcher/Event.h" #include "EventDispatcher/EventDispatcher.h" -#include "InputDevices/Solenoids.h" -#include "InputDevices/SwitchMatrix.h" +#include "InputDevices/InputControllerTestButtons.h" #include "InputDevices/LightMatrix.h" #include "InputDevices/PIN2DMD.h" -#include "InputDevices/InputControllerTestButtons.h" +#include "InputDevices/Solenoids.h" +#include "InputDevices/SwitchMatrix.h" +#include "PPUC.h" #include "VisualPinball/PUPComLink.h" class InputController { -public: - InputController(int controllerType, byte platform); + public: + InputController(int controllerType, byte platform); - InputController(int controllerType, byte platform, EventDispatcher* eventDispatcher); + InputController(int controllerType, byte platform, + EventDispatcher* eventDispatcher); - Solenoids* solenoids(); + Solenoids* solenoids(); - SwitchMatrix* switchMatrix(); + SwitchMatrix* switchMatrix(); - LightMatrix* lightMatrix(); + LightMatrix* lightMatrix(); - PIN2DMD* pin2Dmd(); + PIN2DMD* pin2Dmd(); - PUPComLink* pupComLink(); + PUPComLink* pupComLink(); - InputControllerTestButtons* testButtons(); + InputControllerTestButtons* testButtons(); - EventDispatcher* eventDispatcher(); + EventDispatcher* eventDispatcher(); - byte platform; + byte platform; -private: - Solenoids* _solenoids; - SwitchMatrix* _switchMatrix; - LightMatrix* _lightMatrix; - PIN2DMD* _pin2Dmd; - PUPComLink* _pupComLink; - InputControllerTestButtons* _testButtons; - EventDispatcher* _eventDispatcher; + private: + Solenoids* _solenoids; + SwitchMatrix* _switchMatrix; + LightMatrix* _lightMatrix; + PIN2DMD* _pin2Dmd; + PUPComLink* _pupComLink; + InputControllerTestButtons* _testButtons; + EventDispatcher* _eventDispatcher; }; #endif diff --git a/src/InputDevices/DistributionControllerTestButtons.cpp b/src/InputDevices/DistributionControllerTestButtons.cpp index e0d6f4a..2ed44f5 100644 --- a/src/InputDevices/DistributionControllerTestButtons.cpp +++ b/src/InputDevices/DistributionControllerTestButtons.cpp @@ -1,24 +1,26 @@ #include "DistributionControllerTestButtons.h" -DistributionControllerTestButtons::DistributionControllerTestButtons(EventDispatcher* eD) { - eventDispatcher = eD; +DistributionControllerTestButtons::DistributionControllerTestButtons( + EventDispatcher* eD) { + eventDispatcher = eD; - for (int i = 0; i <= 1; i++) { - button[i] = new Bounce2::Button(); - button[i]->attach(22 + i, INPUT_PULLUP); - button[i]->interval(10); - button[i]->setPressedState(LOW); - } + for (int i = 0; i <= 1; i++) { + button[i] = new Bounce2::Button(); + button[i]->attach(22 + i, INPUT_PULLUP); + button[i]->interval(10); + button[i]->setPressedState(LOW); + } } void DistributionControllerTestButtons::update() { - for (int i = 0; i <= 1; i++) { - button[i]->update(); - if (button[i]->pressed()) { - eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, word(0, 63 + i), 1)); - } - else if (button[i]->released()) { - eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, word(0, 63 + i), 0)); - } + for (int i = 0; i <= 1; i++) { + button[i]->update(); + if (button[i]->pressed()) { + eventDispatcher->dispatch( + new Event(EVENT_SOURCE_SWITCH, word(0, 63 + i), 1)); + } else if (button[i]->released()) { + eventDispatcher->dispatch( + new Event(EVENT_SOURCE_SWITCH, word(0, 63 + i), 0)); } + } } diff --git a/src/InputDevices/DistributionControllerTestButtons.h b/src/InputDevices/DistributionControllerTestButtons.h index c3c263b..243e8b7 100644 --- a/src/InputDevices/DistributionControllerTestButtons.h +++ b/src/InputDevices/DistributionControllerTestButtons.h @@ -15,14 +15,14 @@ #include "../EventDispatcher/EventDispatcher.h" class DistributionControllerTestButtons { -public: - DistributionControllerTestButtons(EventDispatcher* eD); + public: + DistributionControllerTestButtons(EventDispatcher* eD); - void update(); + void update(); -protected: - EventDispatcher* eventDispatcher; - Bounce2::Button* button[2]; + protected: + EventDispatcher* eventDispatcher; + Bounce2::Button* button[2]; }; #endif diff --git a/src/InputDevices/EffectControllerTestButtons.cpp b/src/InputDevices/EffectControllerTestButtons.cpp index 9a1b3f5..752a2d2 100644 --- a/src/InputDevices/EffectControllerTestButtons.cpp +++ b/src/InputDevices/EffectControllerTestButtons.cpp @@ -1,21 +1,22 @@ #include "EffectControllerTestButtons.h" EffectControllerTestButtons::EffectControllerTestButtons(EventDispatcher* eD) { - eventDispatcher = eD; + eventDispatcher = eD; - for (int i = 0; i <= 1; i++) { - button[i] = new Bounce2::Button(); - button[i]->attach(22 + i, INPUT_PULLUP); - button[i]->interval(10); - button[i]->setPressedState(LOW); - } + for (int i = 0; i <= 1; i++) { + button[i] = new Bounce2::Button(); + button[i]->attach(22 + i, INPUT_PULLUP); + button[i]->interval(10); + button[i]->setPressedState(LOW); + } } void EffectControllerTestButtons::update() { - for (int i = 0; i <= 1; i++) { - button[i]->update(); - if (button[i]->pressed()) { - eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, word(0, 201 + i))); - } + for (int i = 0; i <= 1; i++) { + button[i]->update(); + if (button[i]->pressed()) { + eventDispatcher->dispatch( + new Event(EVENT_SOURCE_SWITCH, word(0, 201 + i))); } + } } diff --git a/src/InputDevices/EffectControllerTestButtons.h b/src/InputDevices/EffectControllerTestButtons.h index c3b2fdc..17cf52f 100644 --- a/src/InputDevices/EffectControllerTestButtons.h +++ b/src/InputDevices/EffectControllerTestButtons.h @@ -15,14 +15,14 @@ #include "../EventDispatcher/EventDispatcher.h" class EffectControllerTestButtons { -public: - EffectControllerTestButtons(EventDispatcher* eD); + public: + EffectControllerTestButtons(EventDispatcher* eD); - void update(); + void update(); -protected: - EventDispatcher* eventDispatcher; - Bounce2::Button* button[2]; + protected: + EventDispatcher* eventDispatcher; + Bounce2::Button* button[2]; }; #endif diff --git a/src/InputDevices/GeneralIlluminationWPC.cpp b/src/InputDevices/GeneralIlluminationWPC.cpp index aa1ed60..7d324cb 100644 --- a/src/InputDevices/GeneralIlluminationWPC.cpp +++ b/src/InputDevices/GeneralIlluminationWPC.cpp @@ -8,149 +8,133 @@ GeneralIlluminationWPC* GeneralIlluminationWPC::giInstance = NULL; void GeneralIlluminationWPC::start() { - // initialize data - for (int i = 0; i < NUM_GI_STRINGS; i++) { - for (int k = 0; k <= NUM_BRIGHTNESS; k++) { - sBrightnessHist[i][k] = 0; - } + // initialize data + for (int i = 0; i < NUM_GI_STRINGS; i++) { + for (int k = 0; k <= NUM_BRIGHTNESS; k++) { + sBrightnessHist[i][k] = 0; } - - attachInterrupt(digitalPinToInterrupt(2), GeneralIlluminationWPC::_changeD0, RISING); - attachInterrupt(digitalPinToInterrupt(3), GeneralIlluminationWPC::_changeD1, RISING); - attachInterrupt(digitalPinToInterrupt(4), GeneralIlluminationWPC::_changeD2, RISING); - attachInterrupt(digitalPinToInterrupt(5), GeneralIlluminationWPC::_changeD3, RISING); - attachInterrupt(digitalPinToInterrupt(6), GeneralIlluminationWPC::_changeD4, RISING); - attachInterrupt(digitalPinToInterrupt(12), GeneralIlluminationWPC::_changeZC, FALLING); + } + + attachInterrupt(digitalPinToInterrupt(2), GeneralIlluminationWPC::_changeD0, + RISING); + attachInterrupt(digitalPinToInterrupt(3), GeneralIlluminationWPC::_changeD1, + RISING); + attachInterrupt(digitalPinToInterrupt(4), GeneralIlluminationWPC::_changeD2, + RISING); + attachInterrupt(digitalPinToInterrupt(5), GeneralIlluminationWPC::_changeD3, + RISING); + attachInterrupt(digitalPinToInterrupt(6), GeneralIlluminationWPC::_changeD4, + RISING); + attachInterrupt(digitalPinToInterrupt(12), GeneralIlluminationWPC::_changeZC, + FALLING); } void GeneralIlluminationWPC::stop() { - detachInterrupt(digitalPinToInterrupt(2)); - detachInterrupt(digitalPinToInterrupt(3)); - detachInterrupt(digitalPinToInterrupt(4)); - detachInterrupt(digitalPinToInterrupt(5)); - detachInterrupt(digitalPinToInterrupt(6)); - detachInterrupt(digitalPinToInterrupt(12)); + detachInterrupt(digitalPinToInterrupt(2)); + detachInterrupt(digitalPinToInterrupt(3)); + detachInterrupt(digitalPinToInterrupt(4)); + detachInterrupt(digitalPinToInterrupt(5)); + detachInterrupt(digitalPinToInterrupt(6)); + detachInterrupt(digitalPinToInterrupt(12)); } void GeneralIlluminationWPC::update() { - for (int string = 0; string < NUM_GI_STRINGS; string++) { - if (sBrightness[string] != sBrightnessTarget[string]) { - sBrightness[string] = sBrightnessTarget[string]; - eventDispatcher->dispatch(new Event(EVENT_SOURCE_GI, word(0, string + 1), sBrightness[string])); - } + for (int string = 0; string < NUM_GI_STRINGS; string++) { + if (sBrightness[string] != sBrightnessTarget[string]) { + sBrightness[string] = sBrightnessTarget[string]; + eventDispatcher->dispatch( + new Event(EVENT_SOURCE_GI, word(0, string + 1), sBrightness[string])); } + } } void GeneralIlluminationWPC::newBrightness(uint8_t string, uint8_t b) { - // Check whether the brightness has changed - if (b <= NUM_BRIGHTNESS && b != sBrightnessTarget[string]) { - // Add the current brightness value to the histogram - if (sBrightnessHist[string][b] < 255) { - sBrightnessHist[string][b]++; - } - - // Only switch when some measurements in the center of the - // brightness interval have been seen - if (sBrightnessHist[string][b] > BRIGHTNESS_SWITCH_THRESH) { - // switch to the new brightness target value - sBrightnessTarget[string] = b; - - // clear the histogram - memset((void*) &(sBrightnessHist[string][0]), 0, NUM_BRIGHTNESS + 1); - } + // Check whether the brightness has changed + if (b <= NUM_BRIGHTNESS && b != sBrightnessTarget[string]) { + // Add the current brightness value to the histogram + if (sBrightnessHist[string][b] < 255) { + sBrightnessHist[string][b]++; } -} -void GeneralIlluminationWPC::_changeD0() { - giInstance->handlePinChange(0); -} + // Only switch when some measurements in the center of the + // brightness interval have been seen + if (sBrightnessHist[string][b] > BRIGHTNESS_SWITCH_THRESH) { + // switch to the new brightness target value + sBrightnessTarget[string] = b; -void GeneralIlluminationWPC::_changeD1() { - giInstance->handlePinChange(1); + // clear the histogram + memset((void*)&(sBrightnessHist[string][0]), 0, NUM_BRIGHTNESS + 1); + } + } } -void GeneralIlluminationWPC::_changeD2() { - giInstance->handlePinChange(2); -} +void GeneralIlluminationWPC::_changeD0() { giInstance->handlePinChange(0); } -void GeneralIlluminationWPC::_changeD3() { - giInstance->handlePinChange(3); -} +void GeneralIlluminationWPC::_changeD1() { giInstance->handlePinChange(1); } -void GeneralIlluminationWPC::_changeD4() { - giInstance->handlePinChange(4); -} +void GeneralIlluminationWPC::_changeD2() { giInstance->handlePinChange(2); } + +void GeneralIlluminationWPC::_changeD3() { giInstance->handlePinChange(3); } + +void GeneralIlluminationWPC::_changeD4() { giInstance->handlePinChange(4); } void GeneralIlluminationWPC::handlePinChange(uint8_t giString) { - // Handle the new brightness value - newBrightness(giString, dtToBrightness(micros() - sZCIntTime)); + // Handle the new brightness value + newBrightness(giString, dtToBrightness(micros() - sZCIntTime)); - sInterruptsSeen |= (1 << giString); + sInterruptsSeen |= (1 << giString); } void GeneralIlluminationWPC::_changeZC() { - //Serial.println("ZC"); - - // What time is it? - giInstance->sZCIntTime = micros(); - - // All strings without interrupt in the previous interval are either fully - // on or off. So their brightness is not set by handlePinChange(). Set - // 0 (off) or NUM_BRIGHTNESS (on) here. - for (int i = 0; i < NUM_GI_STRINGS; i++) { - if ((giInstance->sInterruptsSeen & (1 << i)) == 0) { - giInstance->newBrightness(i, digitalRead(2 + i) ? 0 : NUM_BRIGHTNESS); - } - } - // Clear the interrupts mask - giInstance->sInterruptsSeen = 0; -} + // Serial.println("ZC"); -uint8_t GeneralIlluminationWPC::dtToBrightness(uint32_t dt) -{ - // This function leaves some margin at the interval borders to account for - // the fact the intervals are slightly overlapping and therefore an - // unambiguous brightness determination is not always possible. In this case - // the function returns 255. - if (dt < (1200 - BRIGHTNESS_INTERVAL_MARGIN)) { - // It seems that brightness level 7 is never used in any WPC pinball machine. - // It us selectable in the GI test, but the time is not measurable. - // The signal remains HIGH and therefore a brightness level of 8 will be - // detected. So we return 8 here as well, even if this part of the code - // should never be reached. - return NUM_BRIGHTNESS; - } - else if ((dt > (1200 + BRIGHTNESS_INTERVAL_MARGIN)) && - (dt < (2200 - BRIGHTNESS_INTERVAL_MARGIN))) - { - return 6; - } - else if ((dt > (2200 + BRIGHTNESS_INTERVAL_MARGIN)) && - (dt < (3200 - BRIGHTNESS_INTERVAL_MARGIN))) - { - return 5; - } - else if ((dt > (3200 + BRIGHTNESS_INTERVAL_MARGIN)) && - (dt < (4200 - BRIGHTNESS_INTERVAL_MARGIN))) - { - return 4; - } - else if ((dt > (4200 + BRIGHTNESS_INTERVAL_MARGIN)) && - (dt < (5200 - BRIGHTNESS_INTERVAL_MARGIN))) - { - return 3; - } - else if ((dt > (5200 + BRIGHTNESS_INTERVAL_MARGIN)) && - (dt < (6200 - BRIGHTNESS_INTERVAL_MARGIN))) - { - return 2; - } - else if ((dt > (6200 + BRIGHTNESS_INTERVAL_MARGIN)) && - (dt < (7200 - BRIGHTNESS_INTERVAL_MARGIN))) - { - return 1; + // What time is it? + giInstance->sZCIntTime = micros(); + + // All strings without interrupt in the previous interval are either fully + // on or off. So their brightness is not set by handlePinChange(). Set + // 0 (off) or NUM_BRIGHTNESS (on) here. + for (int i = 0; i < NUM_GI_STRINGS; i++) { + if ((giInstance->sInterruptsSeen & (1 << i)) == 0) { + giInstance->newBrightness(i, digitalRead(2 + i) ? 0 : NUM_BRIGHTNESS); } + } + // Clear the interrupts mask + giInstance->sInterruptsSeen = 0; +} - // invalid interval - return BRIGHTNESS_UNCERTAIN; +uint8_t GeneralIlluminationWPC::dtToBrightness(uint32_t dt) { + // This function leaves some margin at the interval borders to account for + // the fact the intervals are slightly overlapping and therefore an + // unambiguous brightness determination is not always possible. In this case + // the function returns 255. + if (dt < (1200 - BRIGHTNESS_INTERVAL_MARGIN)) { + // It seems that brightness level 7 is never used in any WPC pinball + // machine. It us selectable in the GI test, but the time is not measurable. + // The signal remains HIGH and therefore a brightness level of 8 will be + // detected. So we return 8 here as well, even if this part of the code + // should never be reached. + return NUM_BRIGHTNESS; + } else if ((dt > (1200 + BRIGHTNESS_INTERVAL_MARGIN)) && + (dt < (2200 - BRIGHTNESS_INTERVAL_MARGIN))) { + return 6; + } else if ((dt > (2200 + BRIGHTNESS_INTERVAL_MARGIN)) && + (dt < (3200 - BRIGHTNESS_INTERVAL_MARGIN))) { + return 5; + } else if ((dt > (3200 + BRIGHTNESS_INTERVAL_MARGIN)) && + (dt < (4200 - BRIGHTNESS_INTERVAL_MARGIN))) { + return 4; + } else if ((dt > (4200 + BRIGHTNESS_INTERVAL_MARGIN)) && + (dt < (5200 - BRIGHTNESS_INTERVAL_MARGIN))) { + return 3; + } else if ((dt > (5200 + BRIGHTNESS_INTERVAL_MARGIN)) && + (dt < (6200 - BRIGHTNESS_INTERVAL_MARGIN))) { + return 2; + } else if ((dt > (6200 + BRIGHTNESS_INTERVAL_MARGIN)) && + (dt < (7200 - BRIGHTNESS_INTERVAL_MARGIN))) { + return 1; + } + + // invalid interval + return BRIGHTNESS_UNCERTAIN; } diff --git a/src/InputDevices/GeneralIlluminationWPC.h b/src/InputDevices/GeneralIlluminationWPC.h index a0a564c..293423e 100644 --- a/src/InputDevices/GeneralIlluminationWPC.h +++ b/src/InputDevices/GeneralIlluminationWPC.h @@ -22,7 +22,7 @@ * | STR5_IN | D4 Data Bus | D6 | * | ZC | Zero Crossing | D12 | * +----------+---------------+------+ -*/ + */ // The WPC CPU issues a short signal to turn on the triac controlling the // AC voltage. The Triac will stay on until the next zero crossing of the @@ -44,7 +44,6 @@ // +-----------------------------+------ // 0ms 10ms - #include "../EventDispatcher/EventDispatcher.h" //------------------------------------------------------------------------------ @@ -66,48 +65,49 @@ #define BRIGHTNESS_UNCERTAIN 255 class GeneralIlluminationWPC { -public: - GeneralIlluminationWPC(EventDispatcher *eD) { - giInstance = this; - eventDispatcher = eD; - - pinMode(2, INPUT); - pinMode(3, INPUT); - pinMode(4, INPUT); - pinMode(5, INPUT); - pinMode(6, INPUT); - pinMode(12, INPUT_PULLUP); // Inverted on Adapter. - } - - void start(); - void stop(); - void update(); - - void handlePinChange(uint8_t giString); - void newBrightness(uint8_t string, uint8_t b); - - static void _changeD0(); - static void _changeD1(); - static void _changeD2(); - static void _changeD3(); - static void _changeD4(); - static void _changeZC(); - - volatile uint32_t sZCIntTime = 0; - volatile uint8_t sInterruptsSeen = 0; - volatile uint32_t sDataIntLast[NUM_GI_STRINGS] = {0}; - -protected: - uint8_t dtToBrightness(uint32_t dt); - - EventDispatcher* eventDispatcher; - - uint8_t sBrightness[NUM_GI_STRINGS] = {0}; - uint8_t sBrightnessTarget[NUM_GI_STRINGS] = {0}; - uint8_t sBrightnessHist[NUM_GI_STRINGS][NUM_BRIGHTNESS + 1]; // including 0 for 'off' - -private: - static GeneralIlluminationWPC *giInstance; + public: + GeneralIlluminationWPC(EventDispatcher *eD) { + giInstance = this; + eventDispatcher = eD; + + pinMode(2, INPUT); + pinMode(3, INPUT); + pinMode(4, INPUT); + pinMode(5, INPUT); + pinMode(6, INPUT); + pinMode(12, INPUT_PULLUP); // Inverted on Adapter. + } + + void start(); + void stop(); + void update(); + + void handlePinChange(uint8_t giString); + void newBrightness(uint8_t string, uint8_t b); + + static void _changeD0(); + static void _changeD1(); + static void _changeD2(); + static void _changeD3(); + static void _changeD4(); + static void _changeZC(); + + volatile uint32_t sZCIntTime = 0; + volatile uint8_t sInterruptsSeen = 0; + volatile uint32_t sDataIntLast[NUM_GI_STRINGS] = {0}; + + protected: + uint8_t dtToBrightness(uint32_t dt); + + EventDispatcher *eventDispatcher; + + uint8_t sBrightness[NUM_GI_STRINGS] = {0}; + uint8_t sBrightnessTarget[NUM_GI_STRINGS] = {0}; + uint8_t sBrightnessHist[NUM_GI_STRINGS] + [NUM_BRIGHTNESS + 1]; // including 0 for 'off' + + private: + static GeneralIlluminationWPC *giInstance; }; -#endif //_GENERALILLUMINATIONWPC_H +#endif //_GENERALILLUMINATIONWPC_H diff --git a/src/InputDevices/InputControllerTestButtons.cpp b/src/InputDevices/InputControllerTestButtons.cpp index 7d8519e..c6e980d 100644 --- a/src/InputDevices/InputControllerTestButtons.cpp +++ b/src/InputDevices/InputControllerTestButtons.cpp @@ -1,21 +1,22 @@ #include "InputControllerTestButtons.h" InputControllerTestButtons::InputControllerTestButtons(EventDispatcher* eD) { - eventDispatcher = eD; + eventDispatcher = eD; - for (int i = 0; i <= 1; i++) { - button[i] = new Bounce2::Button(); - button[i]->attach(52 + i, INPUT_PULLUP); - button[i]->interval(10); - button[i]->setPressedState(LOW); - } + for (int i = 0; i <= 1; i++) { + button[i] = new Bounce2::Button(); + button[i]->attach(52 + i, INPUT_PULLUP); + button[i]->interval(10); + button[i]->setPressedState(LOW); + } } void InputControllerTestButtons::update() { - for (int i = 0; i <= 1; i++) { - button[i]->update(); - if (button[i]->pressed()) { - eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, word(0, 203 + i))); - } + for (int i = 0; i <= 1; i++) { + button[i]->update(); + if (button[i]->pressed()) { + eventDispatcher->dispatch( + new Event(EVENT_SOURCE_SWITCH, word(0, 203 + i))); } + } } diff --git a/src/InputDevices/InputControllerTestButtons.h b/src/InputDevices/InputControllerTestButtons.h index b30e3f4..d00cd37 100644 --- a/src/InputDevices/InputControllerTestButtons.h +++ b/src/InputDevices/InputControllerTestButtons.h @@ -15,14 +15,14 @@ #include "../EventDispatcher/EventDispatcher.h" class InputControllerTestButtons { -public: - InputControllerTestButtons(EventDispatcher* eD); + public: + InputControllerTestButtons(EventDispatcher* eD); - void update(); + void update(); -protected: - EventDispatcher* eventDispatcher; - Bounce2::Button* button[2]; + protected: + EventDispatcher* eventDispatcher; + Bounce2::Button* button[2]; }; #endif diff --git a/src/InputDevices/LightMatrix.cpp b/src/InputDevices/LightMatrix.cpp index 02e6c03..4be6a9a 100644 --- a/src/InputDevices/LightMatrix.cpp +++ b/src/InputDevices/LightMatrix.cpp @@ -1,4 +1,4 @@ -#if defined (__AVR__) || (__avr__) || (__IMXRT1062__) +#if defined(__AVR__) || (__avr__) || (__IMXRT1062__) #include #endif @@ -8,98 +8,116 @@ LightMatrix* LightMatrix::lightMatrixInstance = NULL; void LightMatrix::start() { -#if defined (__AVR__) || (__avr__) || (__IMXRT1062__) - Timer1.attachInterrupt(LightMatrix::_readRow); +#if defined(__AVR__) || (__avr__) || (__IMXRT1062__) + Timer1.attachInterrupt(LightMatrix::_readRow); #endif } void LightMatrix::stop() { -#if defined (__AVR__) || (__avr__) || (__IMXRT1062__) - Timer1.detachInterrupt(); +#if defined(__AVR__) || (__avr__) || (__IMXRT1062__) + Timer1.detachInterrupt(); #endif } void LightMatrix::_readRow() { - // 74HC165 16bit sampling - uint16_t inData = lightMatrixInstance->sampleInput(); - byte inColMask = (inData >> 8); // LSB is col 0, MSB is col 7 - byte inRowMask = ~(byte)inData; // high means OFF, LSB is row 0, MSB is row 7 + // 74HC165 16bit sampling + uint16_t inData = lightMatrixInstance->sampleInput(); + byte inColMask = (inData >> 8); // LSB is col 0, MSB is col 7 + byte inRowMask = ~(byte)inData; // high means OFF, LSB is row 0, MSB is row 7 - // evaluate the column reading - // only one bit should be set as only one column can be active at a time - uint32_t inCol = NUM_COLS; - switch (inColMask) { - case 0x01: inCol = 0; break; - case 0x02: inCol = 1; break; - case 0x04: inCol = 2; break; - case 0x08: inCol = 3; break; - case 0x10: inCol = 4; break; - case 0x20: inCol = 5; break; - case 0x40: inCol = 6; break; - case 0x80: inCol = 7; break; - default: - // This may happen if the sample is taken in between column transition. - // Depending on the pinball ROM version the duration of this transition varies. - // On a Whitewater with Home ROM LH6 (contains anti ghosting updates) this - // gap was measured to be around 30us long. - // Machines with anti-ghosting firmware will show a gap with no column enabled - // for a while during the transition while older firmwares might have two - // columns enabled at the same time due to slow transistor deactivation. Both - // cases are caught here. - // See also https://emmytech.com/arcade/led_ghost_busting/index.html for details. - return; - } + // evaluate the column reading + // only one bit should be set as only one column can be active at a time + uint32_t inCol = NUM_COLS; + switch (inColMask) { + case 0x01: + inCol = 0; + break; + case 0x02: + inCol = 1; + break; + case 0x04: + inCol = 2; + break; + case 0x08: + inCol = 3; + break; + case 0x10: + inCol = 4; + break; + case 0x20: + inCol = 5; + break; + case 0x40: + inCol = 6; + break; + case 0x80: + inCol = 7; + break; + default: + // This may happen if the sample is taken in between column transition. + // Depending on the pinball ROM version the duration of this transition + // varies. On a Whitewater with Home ROM LH6 (contains anti ghosting + // updates) this gap was measured to be around 30us long. Machines with + // anti-ghosting firmware will show a gap with no column enabled for a + // while during the transition while older firmwares might have two + // columns enabled at the same time due to slow transistor deactivation. + // Both cases are caught here. See also + // https://emmytech.com/arcade/led_ghost_busting/index.html for details. + return; + } - // Update only with a valid input. If the input is invalid the current - // matrix state is left unchanged. - // The matrix is updated only once per original column cycle. The code - // waits for a number of consecutive consistent information before updating the matrix. - if (lightMatrixInstance->updateValid(inCol, inRowMask)) { - //Serial.print(inCol + 1); Serial.print(": "); Serial.println(inRowMask, BIN); - // update the current column - lightMatrixInstance->rows[inCol] = inRowMask; - } + // Update only with a valid input. If the input is invalid the current + // matrix state is left unchanged. + // The matrix is updated only once per original column cycle. The code + // waits for a number of consecutive consistent information before updating + // the matrix. + if (lightMatrixInstance->updateValid(inCol, inRowMask)) { + // Serial.print(inCol + 1); Serial.print(": "); Serial.println(inRowMask, + // BIN); + // update the current column + lightMatrixInstance->rows[inCol] = inRowMask; + } } uint16_t LightMatrix::sampleInput() { - // drive CLK and LOAD low - digitalWrite(6, LOW); - digitalWrite(7, LOW); + // drive CLK and LOAD low + digitalWrite(6, LOW); + digitalWrite(7, LOW); - // wait some time - uint16_t data = 0; - data += 17; - data -= 3; + // wait some time + uint16_t data = 0; + data += 17; + data -= 3; - // drive LOAD high to save pin states - digitalWrite(7, HIGH); + // drive LOAD high to save pin states + digitalWrite(7, HIGH); - // clock in all data - for (byte i = 0; i < 16; i++) { - data <<= 1; // make way for the new bit - digitalWrite(6, LOW); // CLK low - data |= digitalRead(5); // read data bit - digitalWrite(6, HIGH); // CLK high - } + // clock in all data + for (byte i = 0; i < 16; i++) { + data <<= 1; // make way for the new bit + digitalWrite(6, LOW); // CLK low + data |= digitalRead(5); // read data bit + digitalWrite(6, HIGH); // CLK high + } - return data; + return data; } bool LightMatrix::updateValid(byte inCol, byte inRowMask) { - // check if the current column has not been handled already - if (inRowMask != lastRowMask[inCol]) { - // reset the counter when the data changes - consistentSamples[inCol] = 1; - lastRowMask[inCol] = inRowMask; - } - // count number of consecutive samples with consistent data - else if (consistentSamples[inCol] < 255) { - consistentSamples[inCol]++; - } + // check if the current column has not been handled already + if (inRowMask != lastRowMask[inCol]) { + // reset the counter when the data changes + consistentSamples[inCol] = 1; + lastRowMask[inCol] = inRowMask; + } + // count number of consecutive samples with consistent data + else if (consistentSamples[inCol] < 255) { + consistentSamples[inCol]++; + } - if (consistentSamples[inCol] >= SINGLE_UPDATE_CONS) { - return true; - } + if (consistentSamples[inCol] >= SINGLE_UPDATE_CONS) { + return true; + } - return false; + return false; } diff --git a/src/InputDevices/LightMatrix.h b/src/InputDevices/LightMatrix.h index 51f929e..f9d841b 100644 --- a/src/InputDevices/LightMatrix.h +++ b/src/InputDevices/LightMatrix.h @@ -10,12 +10,12 @@ #define LightMatrix_h #include -#if defined (__AVR__) || (__avr__) || (__IMXRT1062__) +#if defined(__AVR__) || (__avr__) || (__IMXRT1062__) #include #endif -#include "Matrix.h" #include "../EventDispatcher/Event.h" +#include "Matrix.h" // Number of consistent data samples required for matrix update #define SINGLE_UPDATE_CONS 2 @@ -24,40 +24,40 @@ #define TTAG_INT_A (250) class LightMatrix : public Matrix { -public: - LightMatrix(EventDispatcher* eD, byte pf) : Matrix(eD, pf) { - lightMatrixInstance = this; + public: + LightMatrix(EventDispatcher* eD, byte pf) : Matrix(eD, pf) { + lightMatrixInstance = this; - eventSource = EVENT_SOURCE_LIGHT; - maxChangesPerRead = MAX_FIELDS_REGISTERED; + eventSource = EVENT_SOURCE_LIGHT; + maxChangesPerRead = MAX_FIELDS_REGISTERED; - pinMode(5, INPUT); - pinMode(6, OUTPUT); - pinMode(7, OUTPUT); + pinMode(5, INPUT); + pinMode(6, OUTPUT); + pinMode(7, OUTPUT); -#if defined (__AVR__) || (__avr__) || (__IMXRT1062__) - Timer1.initialize(TTAG_INT_A); +#if defined(__AVR__) || (__avr__) || (__IMXRT1062__) + Timer1.initialize(TTAG_INT_A); #endif - } + } - void start(); + void start(); - void stop(); + void stop(); - static void _readRow(); + static void _readRow(); - uint16_t sampleInput(); + uint16_t sampleInput(); - bool updateValid(byte inCol, byte inRowMask); + bool updateValid(byte inCol, byte inRowMask); - void updateCol(uint32_t col, byte rowMask); + void updateCol(uint32_t col, byte rowMask); - // remember the last row samples - volatile byte lastRowMask[8] = {0}; - volatile byte consistentSamples[8] = {0}; + // remember the last row samples + volatile byte lastRowMask[8] = {0}; + volatile byte consistentSamples[8] = {0}; -private: - static LightMatrix* lightMatrixInstance; + private: + static LightMatrix* lightMatrixInstance; }; #endif diff --git a/src/InputDevices/Matrix.cpp b/src/InputDevices/Matrix.cpp index 09b3c0b..6f7486b 100644 --- a/src/InputDevices/Matrix.cpp +++ b/src/InputDevices/Matrix.cpp @@ -1,102 +1,99 @@ #include "Matrix.h" Matrix::Matrix(EventDispatcher* eD, byte pf) { - eventDispatcher = eD; - platform = pf; + eventDispatcher = eD; + platform = pf; - setLastColToRead(8); + setLastColToRead(8); - for (int i = 0; i < lastColToRead; i++) { - rows[i] = 0b00000000; - previousRows[i] = 0b00000000; - } + for (int i = 0; i < lastColToRead; i++) { + rows[i] = 0b00000000; + previousRows[i] = 0b00000000; + } } -void Matrix::setLastColToRead(byte last) { - lastColToRead = last; -} +void Matrix::setLastColToRead(byte last) { lastColToRead = last; } void Matrix::registerFieldAsEvent(byte row, byte column, byte number) { - if (registeredFieldsCounter < (MAX_FIELDS_REGISTERED - 1)) { - registeredFieldRowCol[++registeredFieldsCounter] = word(row - 1, column - 1); - registeredFieldNum[registeredFieldsCounter] = number; - } + if (registeredFieldsCounter < (MAX_FIELDS_REGISTERED - 1)) { + registeredFieldRowCol[++registeredFieldsCounter] = + word(row - 1, column - 1); + registeredFieldNum[registeredFieldsCounter] = number; + } } void Matrix::registerAllFieldsAsEvent() { - registeredFieldsCounter = -1; + registeredFieldsCounter = -1; - if (platform == PLATFORM_WPC) { - for (byte col = 1; col <= lastColToRead; col++) { - for (byte row = 1; row <= 8; row++) { - registerFieldAsEvent(row, col, col * 10 + row); - } - } + if (platform == PLATFORM_WPC) { + for (byte col = 1; col <= lastColToRead; col++) { + for (byte row = 1; row <= 8; row++) { + registerFieldAsEvent(row, col, col * 10 + row); + } } - else if (platform == PLATFORM_DATA_EAST || platform == PLATFORM_SYS11) { - byte number = 0; - for (byte col = 1; col <= lastColToRead; col++) { - for (byte row = 1; row <= 8; row++) { - registerFieldAsEvent(row, col, ++number); - } - } + } else if (platform == PLATFORM_DATA_EAST || platform == PLATFORM_SYS11) { + byte number = 0; + for (byte col = 1; col <= lastColToRead; col++) { + for (byte row = 1; row <= 8; row++) { + registerFieldAsEvent(row, col, ++number); + } } + } } void Matrix::update() { - if (updateDelay > 0) { - uint32_t ms = millis(); - - if (nextUpdate > ms) { - return; - } + if (updateDelay > 0) { + uint32_t ms = millis(); - nextUpdate = ms + updateDelay; + if (nextUpdate > ms) { + return; } - byte fieldNum[maxChangesPerRead] = {0}; - byte value[maxChangesPerRead] = {0}; - byte counter = 0; + nextUpdate = ms + updateDelay; + } - for (int col = 0; col < lastColToRead; col++) { - for (int row = 0; row < 8; row++) { - word row_col = word(row, col); - for (byte i = 0; i <= registeredFieldsCounter; i++) { - if (row_col == registeredFieldRowCol[i]) { - byte bit = 1 << row; - if ((rows[col] & bit) != (previousRows[col] & bit)) { - if (counter < maxChangesPerRead) { - fieldNum[counter] = registeredFieldNum[i]; - value[counter++] = (rows[col] & bit) ? 1 : 0; - } - else { - // Too many changes, assume erroneous read. - return; - } - } - } + byte fieldNum[maxChangesPerRead] = {0}; + byte value[maxChangesPerRead] = {0}; + byte counter = 0; + + for (int col = 0; col < lastColToRead; col++) { + for (int row = 0; row < 8; row++) { + word row_col = word(row, col); + for (byte i = 0; i <= registeredFieldsCounter; i++) { + if (row_col == registeredFieldRowCol[i]) { + byte bit = 1 << row; + if ((rows[col] & bit) != (previousRows[col] & bit)) { + if (counter < maxChangesPerRead) { + fieldNum[counter] = registeredFieldNum[i]; + value[counter++] = (rows[col] & bit) ? 1 : 0; + } else { + // Too many changes, assume erroneous read. + return; } + } } - previousRows[col] = rows[col]; + } } + previousRows[col] = rows[col]; + } - if (counter <= maxChangesPerRead) { - for (int i = 0; i < counter; i++) { - eventDispatcher->dispatch( - new Event(eventSource, word(0, fieldNum[i]), value[i]) - ); - } + if (counter <= maxChangesPerRead) { + for (int i = 0; i < counter; i++) { + eventDispatcher->dispatch( + new Event(eventSource, word(0, fieldNum[i]), value[i])); } + } } void Matrix::print() { - Serial.print("Matrix "); Serial.println(eventSource); - Serial.println(" 8 7 6 5 4 3 2 1"); - for (int i = 0; i < lastColToRead; i++) { - Serial.print(i + 1); - for (byte mask = 0x80; mask; mask >>= 1) { - Serial.print(mask & rows[i] ? " *" : " -"); - } - Serial.println(); + Serial.print("Matrix "); + Serial.println(eventSource); + Serial.println(" 8 7 6 5 4 3 2 1"); + for (int i = 0; i < lastColToRead; i++) { + Serial.print(i + 1); + for (byte mask = 0x80; mask; mask >>= 1) { + Serial.print(mask & rows[i] ? " *" : " -"); } + Serial.println(); + } } diff --git a/src/InputDevices/Matrix.h b/src/InputDevices/Matrix.h index 9bbd7a9..9e10ee3 100644 --- a/src/InputDevices/Matrix.h +++ b/src/InputDevices/Matrix.h @@ -70,10 +70,9 @@ #ifndef Matrix_h #define Matrix_h -#include "../PPUC.h" - #include "../EventDispatcher/Event.h" #include "../EventDispatcher/EventDispatcher.h" +#include "../PPUC.h" #ifndef NUM_COLS #define NUM_COLS 9 @@ -84,43 +83,43 @@ #endif class Matrix { -public: - Matrix(EventDispatcher* eD, byte pf); + public: + Matrix(EventDispatcher* eD, byte pf); - virtual void start() = 0; + virtual void start() = 0; - virtual void stop() = 0; + virtual void stop() = 0; - void update(); + void update(); - void print(); + void print(); - void setLastColToRead(byte lastColToRead); + void setLastColToRead(byte lastColToRead); - void registerFieldAsEvent(byte row, byte column, byte number); + void registerFieldAsEvent(byte row, byte column, byte number); - void registerAllFieldsAsEvent(); + void registerAllFieldsAsEvent(); - static void _readRow() {} + static void _readRow() {} - volatile byte lastColToRead; - volatile byte rows[NUM_COLS]; + volatile byte lastColToRead; + volatile byte rows[NUM_COLS]; -protected: - EventDispatcher* eventDispatcher; + protected: + EventDispatcher* eventDispatcher; - char eventSource; - byte maxChangesPerRead = 6; - byte previousRows[NUM_COLS]; + char eventSource; + byte maxChangesPerRead = 6; + byte previousRows[NUM_COLS]; - int registeredFieldsCounter = -1; - word registeredFieldRowCol[MAX_FIELDS_REGISTERED]; - byte registeredFieldNum[MAX_FIELDS_REGISTERED]; + int registeredFieldsCounter = -1; + word registeredFieldRowCol[MAX_FIELDS_REGISTERED]; + byte registeredFieldNum[MAX_FIELDS_REGISTERED]; - byte platform; + byte platform; - byte updateDelay = 0; - uint32_t nextUpdate = 0; + byte updateDelay = 0; + uint32_t nextUpdate = 0; }; #endif diff --git a/src/InputDevices/PIN2DMD.cpp b/src/InputDevices/PIN2DMD.cpp index 216f541..7b665e8 100644 --- a/src/InputDevices/PIN2DMD.cpp +++ b/src/InputDevices/PIN2DMD.cpp @@ -1,56 +1,61 @@ #include "PIN2DMD.h" void PIN2DMD::setSerial(HardwareSerial &reference) { - hwSerial = (HardwareSerial*) &reference; - hwSerial->begin(57600); + hwSerial = (HardwareSerial *)&reference; + hwSerial->begin(57600); } void PIN2DMD::update() { - if (hwSerial->available() > 2) { - byte deviceByte = hwSerial->read(); + if (hwSerial->available() > 2) { + byte deviceByte = hwSerial->read(); + if (debug) { + Serial.println(deviceByte, DEC); + } + if (deviceByte != 0) { + byte eventByte = hwSerial->read(); + if (debug) { + Serial.println(eventByte, DEC); + } + if (eventByte != 0) { + byte nullByte = hwSerial->read(); if (debug) { - Serial.println(deviceByte, DEC); + Serial.println(nullByte, DEC); } - if (deviceByte != 0) { - byte eventByte = hwSerial->read(); - if (debug) { - Serial.println(eventByte, DEC); - } - if (eventByte != 0) { - byte nullByte = hwSerial->read(); - if (debug) { - Serial.println(nullByte, DEC); - } - if (nullByte == 0) { - // Quick explanation: - // The PUP Player understands event IDs that are 8 bits long. But we assume that nobody needs that - // much events. But more than 255, which is the maximum value of 4 bits, are exceeded. The pack for - // STTNG is already very close to this limit. On the other hand we don’t really need a device ID as - // the will be the only Device attached to PIN2DMD. But as the device must must not be "0", we - // agreed on this pattern: - // The „hundreds“ of the decimal Device ID in PIN2DMD are the actual ID. So "100" means Device 1. - // ("200" aka Device 2 is not used at the moment and therefore ignored.) The other two digits are - // added as high byte to the event ID which itself is treated as low byte. - // - // Examples of decimal values to be entered in the PIN2DMD Editor: - // 100 187 => Device 1, Event 187 - // 143 187 => Device 1, Event 11195 (43 decimal is 101011 binary, 187 is 10111011, binary 101011 10111011 is 11195 decimal) - // 200 123 => Device 2, Event 123 (Device2 is currently not used) - // 243 187 => Device 2, Event 11195 (Device2 is currently not used) - // - // 100 255 => Device 1, Event 255 - // 101 001 => Device 1, Event 257 - // - // This looks complicated, but I consider this to be the smartest solution to close the gap between - // PIN2DMD 4bit event IDs and PUPPack 8bit event IDs that remains somehow „readable“ in the PIN2DMD - // Editor. - eventDispatcher->dispatch(new Event(EVENT_SOURCE_DMD, word((deviceByte & 0b1111111) - 100, eventByte))); - } - } + if (nullByte == 0) { + // Quick explanation: + // The PUP Player understands event IDs that are 8 bits long. But we + // assume that nobody needs that much events. But more than 255, which + // is the maximum value of 4 bits, are exceeded. The pack for STTNG is + // already very close to this limit. On the other hand we don’t really + // need a device ID as the will be the only Device attached to + // PIN2DMD. But as the device must must not be "0", we agreed on this + // pattern: The „hundreds“ of the decimal Device ID in PIN2DMD are the + // actual ID. So "100" means Device 1. + // ("200" aka Device 2 is not used at the moment and therefore + // ignored.) The other two digits are added as high byte to the event + // ID which itself is treated as low byte. + // + // Examples of decimal values to be entered in the PIN2DMD Editor: + // 100 187 => Device 1, Event 187 + // 143 187 => Device 1, Event 11195 (43 decimal is 101011 binary, 187 + // is 10111011, binary 101011 10111011 is 11195 decimal) 200 123 => + // Device 2, Event 123 (Device2 is currently not used) 243 187 => + // Device 2, Event 11195 (Device2 is currently not used) + // + // 100 255 => Device 1, Event 255 + // 101 001 => Device 1, Event 257 + // + // This looks complicated, but I consider this to be the smartest + // solution to close the gap between PIN2DMD 4bit event IDs and + // PUPPack 8bit event IDs that remains somehow „readable“ in the + // PIN2DMD Editor. + eventDispatcher->dispatch( + new Event(EVENT_SOURCE_DMD, + word((deviceByte & 0b1111111) - 100, eventByte))); } + } } + } } -void PIN2DMD::setDebug(bool value) { - debug = value; -} +void PIN2DMD::setDebug(bool value) { debug = value; } diff --git a/src/InputDevices/PIN2DMD.h b/src/InputDevices/PIN2DMD.h index 817af4e..21ac6b6 100644 --- a/src/InputDevices/PIN2DMD.h +++ b/src/InputDevices/PIN2DMD.h @@ -14,24 +14,21 @@ #include "../EventDispatcher/EventDispatcher.h" class PIN2DMD { -public: - PIN2DMD(EventDispatcher* eD) { - eventDispatcher = eD; - } + public: + PIN2DMD(EventDispatcher* eD) { eventDispatcher = eD; } - void setSerial(HardwareSerial &reference); + void setSerial(HardwareSerial& reference); - void update(); + void update(); - void setDebug(bool value); + void setDebug(bool value); -private: - EventDispatcher* eventDispatcher; + private: + EventDispatcher* eventDispatcher; - HardwareSerial* hwSerial; - - bool debug = false; + HardwareSerial* hwSerial; + bool debug = false; }; #endif diff --git a/src/InputDevices/Solenoids.cpp b/src/InputDevices/Solenoids.cpp index de9bada..100479b 100644 --- a/src/InputDevices/Solenoids.cpp +++ b/src/InputDevices/Solenoids.cpp @@ -1,152 +1,209 @@ #include "Solenoids.h" Solenoids::Solenoids(int controllerType, EventDispatcher* ed) { - eventDispatcher = ed; - - if (controllerType == CONTROLLER_MEGA_ALL_INPUT) { - pins[0] = 8; - pins[1] = 9; - pins[2] = 10; - pins[3] = 11; - pins[4] = 12; - pins[5] = 13; - pins[6] = 30; - pins[7] = 31; - pins[8] = 32; - pins[9] = 33; - pins[10] = 34; - pins[11] = 35; - pins[12] = 36; - pins[13] = 37; - pins[14] = 38; - pins[15] = 39; - pins[16] = 40; - pins[17] = 41; - pins[18] = 42; - pins[19] = 43; - pins[20] = 44; - pins[21] = 45; - pins[22] = 46; - pins[23] = 47; - pins[24] = 48; - pins[25] = 49; - } - - for (int i = 0; i < NUM_PINS; i++) { - pinMode(pins[i], INPUT); - pinStates[i] = false; - previousPinStates[i] = false; - registeredNum[i] = 0; - } + eventDispatcher = ed; + + if (controllerType == CONTROLLER_MEGA_ALL_INPUT) { + pins[0] = 8; + pins[1] = 9; + pins[2] = 10; + pins[3] = 11; + pins[4] = 12; + pins[5] = 13; + pins[6] = 30; + pins[7] = 31; + pins[8] = 32; + pins[9] = 33; + pins[10] = 34; + pins[11] = 35; + pins[12] = 36; + pins[13] = 37; + pins[14] = 38; + pins[15] = 39; + pins[16] = 40; + pins[17] = 41; + pins[18] = 42; + pins[19] = 43; + pins[20] = 44; + pins[21] = 45; + pins[22] = 46; + pins[23] = 47; + pins[24] = 48; + pins[25] = 49; + } + + for (int i = 0; i < NUM_PINS; i++) { + pinMode(pins[i], INPUT); + pinStates[i] = false; + previousPinStates[i] = false; + registeredNum[i] = 0; + } } void Solenoids::update() { - for (int i = 0; i < NUM_PINS; i++) { - previousPinStates[i] = pinStates[i]; - pinStates[i] = digitalRead(pins[i]) == HIGH; - if ((registeredNum[i] != 0) && (previousPinStates[i] != pinStates[i])) { - eventDispatcher->dispatch(new Event(EVENT_SOURCE_SOLENOID, word(0, registeredNum[i]), pinStates[i])); - } + for (int i = 0; i < NUM_PINS; i++) { + previousPinStates[i] = pinStates[i]; + pinStates[i] = digitalRead(pins[i]) == HIGH; + if ((registeredNum[i] != 0) && (previousPinStates[i] != pinStates[i])) { + eventDispatcher->dispatch(new Event( + EVENT_SOURCE_SOLENOID, word(0, registeredNum[i]), pinStates[i])); } + } } void Solenoids::registerJ3(byte pin, byte number) { - if (pin == 1) { registeredNum[0] = number; } - else if (pin == 2) { registeredNum[1] = number; } - else if (pin == 3) { registeredNum[2] = number; } - else if (pin == 4) { registeredNum[3] = number; } - else if (pin == 5) { registeredNum[4] = number; } - // 6 is key - else if (pin == 7) { registeredNum[5] = number; } + if (pin == 1) { + registeredNum[0] = number; + } else if (pin == 2) { + registeredNum[1] = number; + } else if (pin == 3) { + registeredNum[2] = number; + } else if (pin == 4) { + registeredNum[3] = number; + } else if (pin == 5) { + registeredNum[4] = number; + } + // 6 is key + else if (pin == 7) { + registeredNum[5] = number; + } } void Solenoids::registerJ4(byte pin, byte number) { - if (pin == 1) { registeredNum[0] = number; } - else if (pin == 2) { registeredNum[1] = number; } - // 3 is key - else if (pin == 4) { registeredNum[3] = number; } - else if (pin == 5) { registeredNum[4] = number; } - else if (pin == 6) { registeredNum[2] = number; } - else if (pin == 7) { registeredNum[5] = number; } + if (pin == 1) { + registeredNum[0] = number; + } else if (pin == 2) { + registeredNum[1] = number; + } + // 3 is key + else if (pin == 4) { + registeredNum[3] = number; + } else if (pin == 5) { + registeredNum[4] = number; + } else if (pin == 6) { + registeredNum[2] = number; + } else if (pin == 7) { + registeredNum[5] = number; + } } void Solenoids::registerJ122(byte pin, byte number) { - if (pin == 1) { registeredNum[6] = number; } - else if (pin == 2) { registeredNum[7] = number; } - else if (pin == 3) { registeredNum[8] = number; } - else if (pin == 4) { registeredNum[9] = number; } - else if (pin == 5) { registeredNum[10] = number; } - else if (pin == 6) { registeredNum[11] = number; } - // 7 is key - else if (pin == 8) { registeredNum[12] = number; } - else if (pin == 9) { registeredNum[13] = number; } + if (pin == 1) { + registeredNum[6] = number; + } else if (pin == 2) { + registeredNum[7] = number; + } else if (pin == 3) { + registeredNum[8] = number; + } else if (pin == 4) { + registeredNum[9] = number; + } else if (pin == 5) { + registeredNum[10] = number; + } else if (pin == 6) { + registeredNum[11] = number; + } + // 7 is key + else if (pin == 8) { + registeredNum[12] = number; + } else if (pin == 9) { + registeredNum[13] = number; + } } void Solenoids::registerJ123(byte pin, byte number) { - if (pin == 1) { registeredNum[6] = number; } - // 2 is key - else if (pin == 3) { registeredNum[7] = number; } - else if (pin == 4) { registeredNum[8] = number; } - else if (pin == 5) { registeredNum[9] = number; } + if (pin == 1) { + registeredNum[6] = number; + } + // 2 is key + else if (pin == 3) { + registeredNum[7] = number; + } else if (pin == 4) { + registeredNum[8] = number; + } else if (pin == 5) { + registeredNum[9] = number; + } } void Solenoids::registerJ124(byte pin, byte number) { - if (pin == 1) { registeredNum[6] = number; } - else if (pin == 2) { registeredNum[7] = number; } - else if (pin == 3) { registeredNum[8] = number; } - // 4 is key - else if (pin == 5) { registeredNum[9] = number; } + if (pin == 1) { + registeredNum[6] = number; + } else if (pin == 2) { + registeredNum[7] = number; + } else if (pin == 3) { + registeredNum[8] = number; + } + // 4 is key + else if (pin == 5) { + registeredNum[9] = number; + } } - void Solenoids::registerJ125(byte pin, byte number) { - if (pin == 1) { registeredNum[14] = number; } - else if (pin == 2) { registeredNum[15] = number; } - else if (pin == 3) { registeredNum[16] = number; } - // 4 is key - else if (pin == 5) { registeredNum[17] = number; } - else if (pin == 6) { registeredNum[18] = number; } - else if (pin == 7) { registeredNum[19] = number; } - else if (pin == 8) { registeredNum[20] = number; } - else if (pin == 9) { registeredNum[21] = number; } + if (pin == 1) { + registeredNum[14] = number; + } else if (pin == 2) { + registeredNum[15] = number; + } else if (pin == 3) { + registeredNum[16] = number; + } + // 4 is key + else if (pin == 5) { + registeredNum[17] = number; + } else if (pin == 6) { + registeredNum[18] = number; + } else if (pin == 7) { + registeredNum[19] = number; + } else if (pin == 8) { + registeredNum[20] = number; + } else if (pin == 9) { + registeredNum[21] = number; + } } void Solenoids::registerJ126(byte pin, byte number) { - if (pin == 1) { registeredNum[14] = number; } - else if (pin == 2) { registeredNum[15] = number; } - else if (pin == 3) { registeredNum[16] = number; } - else if (pin == 4) { registeredNum[17] = number; } - else if (pin == 5) { registeredNum[18] = number; } - else if (pin == 6) { registeredNum[19] = number; } - else if (pin == 7) { registeredNum[20] = number; } - else if (pin == 8) { registeredNum[21] = number; } - // 9 is key - else if (pin == 10) { registeredNum[22] = number; } - else if (pin == 11) { registeredNum[23] = number; } - else if (pin == 12) { registeredNum[24] = number; } - else if (pin == 13) { registeredNum[25] = number; } + if (pin == 1) { + registeredNum[14] = number; + } else if (pin == 2) { + registeredNum[15] = number; + } else if (pin == 3) { + registeredNum[16] = number; + } else if (pin == 4) { + registeredNum[17] = number; + } else if (pin == 5) { + registeredNum[18] = number; + } else if (pin == 6) { + registeredNum[19] = number; + } else if (pin == 7) { + registeredNum[20] = number; + } else if (pin == 8) { + registeredNum[21] = number; + } + // 9 is key + else if (pin == 10) { + registeredNum[22] = number; + } else if (pin == 11) { + registeredNum[23] = number; + } else if (pin == 12) { + registeredNum[24] = number; + } else if (pin == 13) { + registeredNum[25] = number; + } } -void Solenoids::registerJ110(byte pin, byte number) { -} +void Solenoids::registerJ110(byte pin, byte number) {} -void Solenoids::registerJ111(byte pin, byte number) { -} +void Solenoids::registerJ111(byte pin, byte number) {} -void Solenoids::registerJ9(byte pin, byte number) { -} +void Solenoids::registerJ9(byte pin, byte number) {} -void Solenoids::registerP11(byte pin, byte number) { -} +void Solenoids::registerP11(byte pin, byte number) {} -void Solenoids::registerP12(byte pin, byte number) { -} +void Solenoids::registerP12(byte pin, byte number) {} -//helps with debugging +// helps with debugging void Solenoids::print() { - for (int i = 0; i < NUM_PINS; i++) { - Serial.print(pinStates[i]); - Serial.print(" "); - } - Serial.println(); + for (int i = 0; i < NUM_PINS; i++) { + Serial.print(pinStates[i]); + Serial.print(" "); + } + Serial.println(); } diff --git a/src/InputDevices/Solenoids.h b/src/InputDevices/Solenoids.h index a419b8b..ed29d50 100644 --- a/src/InputDevices/Solenoids.h +++ b/src/InputDevices/Solenoids.h @@ -9,47 +9,45 @@ #define NUM_PINS 26 -#include "../PPUC.h" - #include "../EventDispatcher/Event.h" #include "../EventDispatcher/EventDispatcher.h" +#include "../PPUC.h" class Solenoids { -public: - //Constructor - Solenoids(int controllerType, EventDispatcher* eD); + public: + // Constructor + Solenoids(int controllerType, EventDispatcher* eD); - // WPC - void registerJ3(byte pin, byte number); // A16100 8-Driver PCB Assembly - void registerJ4(byte pin, byte number); // A16100 8-Driver PCB Assembly - void registerJ122(byte pin, byte number); - void registerJ123(byte pin, byte number); - void registerJ124(byte pin, byte number); - void registerJ125(byte pin, byte number); - void registerJ126(byte pin, byte number); + // WPC + void registerJ3(byte pin, byte number); // A16100 8-Driver PCB Assembly + void registerJ4(byte pin, byte number); // A16100 8-Driver PCB Assembly + void registerJ122(byte pin, byte number); + void registerJ123(byte pin, byte number); + void registerJ124(byte pin, byte number); + void registerJ125(byte pin, byte number); + void registerJ126(byte pin, byte number); - // WPC95 - void registerJ110(byte pin, byte number); - void registerJ111(byte pin, byte number); + // WPC95 + void registerJ110(byte pin, byte number); + void registerJ111(byte pin, byte number); - // Sega - void registerJ9(byte pin, byte number); - void registerP11(byte pin, byte number); - void registerP12(byte pin, byte number); + // Sega + void registerJ9(byte pin, byte number); + void registerP11(byte pin, byte number); + void registerP12(byte pin, byte number); - void update(); + void update(); - void print(); + void print(); -private: - EventDispatcher* eventDispatcher; + private: + EventDispatcher* eventDispatcher; - int pins[NUM_PINS]; - bool pinStates[NUM_PINS]; - byte previousPinStates[NUM_PINS]; + int pins[NUM_PINS]; + bool pinStates[NUM_PINS]; + byte previousPinStates[NUM_PINS]; - byte registeredNum[NUM_PINS]; + byte registeredNum[NUM_PINS]; }; - #endif diff --git a/src/InputDevices/SwitchMatrix.cpp b/src/InputDevices/SwitchMatrix.cpp index 0501d20..404c5dc 100644 --- a/src/InputDevices/SwitchMatrix.cpp +++ b/src/InputDevices/SwitchMatrix.cpp @@ -4,72 +4,73 @@ SwitchMatrix* SwitchMatrix::switchMatrixInstance = NULL; void SwitchMatrix::start() { - attachInterrupt(digitalPinToInterrupt(CS_ODD), SwitchMatrix::_readRowForOddColumn, RISING); + attachInterrupt(digitalPinToInterrupt(CS_ODD), + SwitchMatrix::_readRowForOddColumn, RISING); } void SwitchMatrix::stop() { - detachInterrupt(digitalPinToInterrupt(CS_ODD)); - detachInterrupt(digitalPinToInterrupt(CS_EVEN)); + detachInterrupt(digitalPinToInterrupt(CS_ODD)); + detachInterrupt(digitalPinToInterrupt(CS_EVEN)); } void SwitchMatrix::_readRowForOddColumn() { - //Serial.println("CS_ODD"); - switchMatrixInstance->readRow(CS_ODD); + // Serial.println("CS_ODD"); + switchMatrixInstance->readRow(CS_ODD); } void SwitchMatrix::_readRowForEvenColumn() { - //Serial.println("CS_EVEN"); - switchMatrixInstance->readRow(CS_EVEN); + // Serial.println("CS_EVEN"); + switchMatrixInstance->readRow(CS_EVEN); } void SwitchMatrix::readRow(int pin) { - // Immediately turn off further interrupts. - detachInterrupt(digitalPinToInterrupt(pin)); + // Immediately turn off further interrupts. + detachInterrupt(digitalPinToInterrupt(pin)); - delayMicroseconds(rowReadDelay); + delayMicroseconds(rowReadDelay); - if (pin == CS_ODD && digitalRead(CS_X) == LOW) { - //Serial.println("CS_X"); - columnCounter = 0; - } + if (pin == CS_ODD && digitalRead(CS_X) == LOW) { + // Serial.println("CS_X"); + columnCounter = 0; + } - if (columnCounter >= 0 && columnCounter < lastColToRead) { - //Serial.println(switchMatrixInstance->columnCounter, DEC); + if (columnCounter >= 0 && columnCounter < lastColToRead) { + // Serial.println(switchMatrixInstance->columnCounter, DEC); -#if defined (__AVR_ATmega2560__) - // Read row return at PIN 22 - 29 three times and use the majority of bits. - byte a = PINA; - delayMicroseconds(4); - byte b = PINA; - delayMicroseconds(4); - byte c = PINA; +#if defined(__AVR_ATmega2560__) + // Read row return at PIN 22 - 29 three times and use the majority of bits. + byte a = PINA; + delayMicroseconds(4); + byte b = PINA; + delayMicroseconds(4); + byte c = PINA; #else - // The Switch Matrix adapter currently requires an Arduino. - byte a = 0; - byte b = 0; - byte c = 0; + // The Switch Matrix adapter currently requires an Arduino. + byte a = 0; + byte b = 0; + byte c = 0; #endif - if (columnCounter > 0 || - // The first column is only valid, if CS_X is still LOW. Otherwise it's noise. - (columnCounter == 0 && digitalRead(CS_X) == LOW) - ) { - //Serial.println("READ"); - rows[columnCounter++] |= ((a & b) | (b & c) | (c & a)) ^ 0b11111111; - } - else { - columnCounter = 255; - } + if (columnCounter > 0 || + // The first column is only valid, if CS_X is still LOW. Otherwise it's + // noise. + (columnCounter == 0 && digitalRead(CS_X) == LOW)) { + // Serial.println("READ"); + rows[columnCounter++] |= ((a & b) | (b & c) | (c & a)) ^ 0b11111111; + } else { + columnCounter = 255; } + } - if (columnCounter >= lastColToRead) { - columnCounter = 255; - } + if (columnCounter >= lastColToRead) { + columnCounter = 255; + } - if (pin == CS_ODD && columnCounter >= 0 && columnCounter < lastColToRead) { - attachInterrupt(digitalPinToInterrupt(CS_EVEN), SwitchMatrix::_readRowForEvenColumn, RISING); - } - else { - attachInterrupt(digitalPinToInterrupt(CS_ODD), SwitchMatrix::_readRowForOddColumn, RISING); - } + if (pin == CS_ODD && columnCounter >= 0 && columnCounter < lastColToRead) { + attachInterrupt(digitalPinToInterrupt(CS_EVEN), + SwitchMatrix::_readRowForEvenColumn, RISING); + } else { + attachInterrupt(digitalPinToInterrupt(CS_ODD), + SwitchMatrix::_readRowForOddColumn, RISING); + } } diff --git a/src/InputDevices/SwitchMatrix.h b/src/InputDevices/SwitchMatrix.h index 76ffa3e..497c3af 100644 --- a/src/InputDevices/SwitchMatrix.h +++ b/src/InputDevices/SwitchMatrix.h @@ -10,65 +10,64 @@ #include -#include "Matrix.h" #include "../EventDispatcher/Event.h" #include "../EventDispatcher/EventDispatcher.h" +#include "Matrix.h" -#define CS_ODD 3 +#define CS_ODD 3 #define CS_EVEN 2 -#define CS_X 4 +#define CS_X 4 class SwitchMatrix : public Matrix { -public: - SwitchMatrix(EventDispatcher* eD, byte pf) : Matrix(eD, pf) { - switchMatrixInstance = this; - - eventSource = EVENT_SOURCE_SWITCH; - - if (platform == PLATFORM_WPC) { - // Read rows some micro seconds after column strobe signal. - rowReadDelay = 4; - - // On WPC the switches are read every 2ms. Ensure that we have a complete read before sending next events. - updateDelay = 3; - } - else if (platform == PLATFORM_DATA_EAST) { - // @todo - } - else if (platform == PLATFORM_SYS11) { - // @todo - } - - maxChangesPerRead = 3; - - pinMode(CS_ODD, INPUT); - pinMode(CS_EVEN, INPUT); - pinMode(CS_X, INPUT); - - pinMode(22, INPUT); - pinMode(23, INPUT); - pinMode(24, INPUT); - pinMode(25, INPUT); - pinMode(26, INPUT); - pinMode(27, INPUT); - pinMode(28, INPUT); - pinMode(29, INPUT); + public: + SwitchMatrix(EventDispatcher* eD, byte pf) : Matrix(eD, pf) { + switchMatrixInstance = this; + + eventSource = EVENT_SOURCE_SWITCH; + + if (platform == PLATFORM_WPC) { + // Read rows some micro seconds after column strobe signal. + rowReadDelay = 4; + + // On WPC the switches are read every 2ms. Ensure that we have a complete + // read before sending next events. + updateDelay = 3; + } else if (platform == PLATFORM_DATA_EAST) { + // @todo + } else if (platform == PLATFORM_SYS11) { + // @todo } - void start(); + maxChangesPerRead = 3; + + pinMode(CS_ODD, INPUT); + pinMode(CS_EVEN, INPUT); + pinMode(CS_X, INPUT); + + pinMode(22, INPUT); + pinMode(23, INPUT); + pinMode(24, INPUT); + pinMode(25, INPUT); + pinMode(26, INPUT); + pinMode(27, INPUT); + pinMode(28, INPUT); + pinMode(29, INPUT); + } + + void start(); - void stop(); + void stop(); - void readRow(int pin); - static void _readRowForOddColumn(); - static void _readRowForEvenColumn(); + void readRow(int pin); + static void _readRowForOddColumn(); + static void _readRowForEvenColumn(); -protected: - byte columnCounter = 255; - int rowReadDelay = 0; + protected: + byte columnCounter = 255; + int rowReadDelay = 0; -private: - static SwitchMatrix* switchMatrixInstance; + private: + static SwitchMatrix* switchMatrixInstance; }; #endif diff --git a/src/PPUC.h b/src/PPUC.h index fa12c33..d26133a 100644 --- a/src/PPUC.h +++ b/src/PPUC.h @@ -7,6 +7,7 @@ #define PPUC_h #include + #include "PPUCPlatforms.h" #define CONTROLLER_MEGA_ALL_INPUT 1 diff --git a/src/VisualPinball/PUPComLink.cpp b/src/VisualPinball/PUPComLink.cpp index 319b6df..42ae5cd 100644 --- a/src/VisualPinball/PUPComLink.cpp +++ b/src/VisualPinball/PUPComLink.cpp @@ -1,62 +1,61 @@ #include "PUPComLink.h" -void PUPComLink::setSerial(HardwareSerial &reference) { - hwSerial = (HardwareSerial*) &reference; - hwSerial->begin(115200, SERIAL_8N1); +void PUPComLink::setSerial(HardwareSerial& reference) { + hwSerial = (HardwareSerial*)&reference; + hwSerial->begin(115200, SERIAL_8N1); } void PUPComLink::handleEvent(Event* event) { - write(PUP_POST_EVENT_COMMAND, event->sourceId, event->eventId, event->value); + write(PUP_POST_EVENT_COMMAND, event->sourceId, event->eventId, event->value); } void PUPComLink::postEvent(char msgtype, int msgindex, int msgvalue) { - write(PUP_POST_EVENT_COMMAND, msgtype, word(msgindex), word(msgvalue)); + write(PUP_POST_EVENT_COMMAND, msgtype, word(msgindex), word(msgvalue)); } void PUPComLink::customCommand(char msgtype, int msgindex, int msgvalue) { - write(PUP_CUSTOM_COMMAND, msgtype, word(msgindex), word(msgvalue)); + write(PUP_CUSTOM_COMMAND, msgtype, word(msgindex), word(msgvalue)); } void PUPComLink::setVolume(int volume) { - write(PUP_CUSTOM_COMMAND, PUP_CUSTOM_VOLUME, word(0), word(volume)); + write(PUP_CUSTOM_COMMAND, PUP_CUSTOM_VOLUME, word(0), word(volume)); } void PUPComLink::startBatch(int id) { - write(PUP_CUSTOM_COMMAND, PUP_CUSTOM_BATCH, word(0), word(id)); + write(PUP_CUSTOM_COMMAND, PUP_CUSTOM_BATCH, word(0), word(id)); } void PUPComLink::restart() { - write(PUP_CUSTOM_COMMAND, PUP_CUSTOM_RESTART, word(0), word(1)); + write(PUP_CUSTOM_COMMAND, PUP_CUSTOM_RESTART, word(0), word(1)); } void PUPComLink::shutdown() { - write(PUP_CUSTOM_COMMAND, PUP_CUSTOM_SHUTDOWN, word(0), word(1)); -} - -int PUPComLink::available() { - return hwSerial->available(); -} - -byte PUPComLink::read() { - return hwSerial->read(); -} - -void PUPComLink::write(byte command, char msgtype, word msgindex, word msgvalue) { - // Send to PUP Com Link. But only if there's room left in write buffer. Otherwise the program will be blocked. The - // buffer gets full if the data is not fetched by PUP Com Link for any reason. - // @todo Possible optimization to check hwSerial->availableForWrite() >= 8 failed on Arduino for unknown reason. - //if (hwSerial->availableForWrite() >= 8) { - byte msg[8]; - - msg[0] = command; - msg[1] = msgtype; - msg[2] = highByte(msgindex); - msg[3] = lowByte(msgindex); - msg[4] = highByte(msgvalue); - msg[5] = lowByte(msgvalue); - msg[6] = msg[0] ^ msg[1] ^ msg[2] ^ msg[3] ^ msg[4] ^ msg[5]; - msg[7] = PUP_EOF; - - hwSerial->write(msg, 8); - //} + write(PUP_CUSTOM_COMMAND, PUP_CUSTOM_SHUTDOWN, word(0), word(1)); +} + +int PUPComLink::available() { return hwSerial->available(); } + +byte PUPComLink::read() { return hwSerial->read(); } + +void PUPComLink::write(byte command, char msgtype, word msgindex, + word msgvalue) { + // Send to PUP Com Link. But only if there's room left in write buffer. + // Otherwise the program will be blocked. The buffer gets full if the data is + // not fetched by PUP Com Link for any reason. + // @todo Possible optimization to check hwSerial->availableForWrite() >= 8 + // failed on Arduino for unknown reason. + // if (hwSerial->availableForWrite() >= 8) { + byte msg[8]; + + msg[0] = command; + msg[1] = msgtype; + msg[2] = highByte(msgindex); + msg[3] = lowByte(msgindex); + msg[4] = highByte(msgvalue); + msg[5] = lowByte(msgvalue); + msg[6] = msg[0] ^ msg[1] ^ msg[2] ^ msg[3] ^ msg[4] ^ msg[5]; + msg[7] = PUP_EOF; + + hwSerial->write(msg, 8); + //} } diff --git a/src/VisualPinball/PUPComLink.h b/src/VisualPinball/PUPComLink.h index 727e8e2..e894328 100644 --- a/src/VisualPinball/PUPComLink.h +++ b/src/VisualPinball/PUPComLink.h @@ -13,48 +13,48 @@ #include "../EventDispatcher/Event.h" #include "../EventDispatcher/EventDispatcher.h" -#define PUP_POST_EVENT_COMMAND 80 // "P" -#define PUP_CUSTOM_COMMAND 67 // "C" +#define PUP_POST_EVENT_COMMAND 80 // "P" +#define PUP_CUSTOM_COMMAND 67 // "C" #define PUP_EOF 13 #define PUP_VALUE_ON 1 -#define PUP_CUSTOM_VOLUME 86 // "V" -#define PUP_CUSTOM_BATCH 66 // "B" -#define PUP_CUSTOM_RESTART 82 // "R" -#define PUP_CUSTOM_SHUTDOWN 83 // "S" +#define PUP_CUSTOM_VOLUME 86 // "V" +#define PUP_CUSTOM_BATCH 66 // "B" +#define PUP_CUSTOM_RESTART 82 // "R" +#define PUP_CUSTOM_SHUTDOWN 83 // "S" class PUPComLink : public EventListener { -public: - PUPComLink() {} + public: + PUPComLink() {} - void setSerial(HardwareSerial &reference); + void setSerial(HardwareSerial& reference); - void handleEvent(Event* event); + void handleEvent(Event* event); - void handleEvent(ConfigEvent* event) {} + void handleEvent(ConfigEvent* event) {} - void postEvent(char msgtype, int msgindex, int msgvalue); + void postEvent(char msgtype, int msgindex, int msgvalue); - void customCommand(char msgtype, int msgindex, int msgvalue); + void customCommand(char msgtype, int msgindex, int msgvalue); - void setVolume(int volume); + void setVolume(int volume); - /** - * Starts "id".bat in the "pinupsystem\launch" folder - */ - void startBatch(int id); + /** + * Starts "id".bat in the "pinupsystem\launch" folder + */ + void startBatch(int id); - void restart(); + void restart(); - void shutdown(); + void shutdown(); - int available(); + int available(); - byte read(); + byte read(); -protected: - void write(byte command, char msgtype, word msgindex, word msgvalue); + protected: + void write(byte command, char msgtype, word msgindex, word msgvalue); - HardwareSerial* hwSerial; + HardwareSerial* hwSerial; }; #endif diff --git a/src/VisualPinball/VPXComLink.cpp b/src/VisualPinball/VPXComLink.cpp index 7d70e96..19fbe2e 100644 --- a/src/VisualPinball/VPXComLink.cpp +++ b/src/VisualPinball/VPXComLink.cpp @@ -1,51 +1,52 @@ -#if defined(__IMXRT1062__) // Teensy 4.1 +#if defined(__IMXRT1062__) // Teensy 4.1 #include #endif #include "VPXComLink.h" void VPXComLink::update() { - if (Serial.available() >= 6) { - byte startByte = Serial.read(); - if (startByte == 255) { - byte sourceId = Serial.read(); - if (sourceId != 0) { - word eventId = word(Serial.read(), Serial.read()); - if (eventId != 0) { - byte value = Serial.read(); - byte stopByte = Serial.read(); - if (stopByte == 255) { - eventDispatcher->dispatch(new Event((char) sourceId, eventId, value)); - } - } - } + if (Serial.available() >= 6) { + byte startByte = Serial.read(); + if (startByte == 255) { + byte sourceId = Serial.read(); + if (sourceId != 0) { + word eventId = word(Serial.read(), Serial.read()); + if (eventId != 0) { + byte value = Serial.read(); + byte stopByte = Serial.read(); + if (stopByte == 255) { + eventDispatcher->dispatch( + new Event((char)sourceId, eventId, value)); + } } + } } + } } void VPXComLink::handleEvent(Event* event) { - // Add this to platformio.ini to get a Keyboard: - // build_flags = -D USB_SERIAL_HID + // Add this to platformio.ini to get a Keyboard: + // build_flags = -D USB_SERIAL_HID #ifdef Keyboard - if (event->sourceId == EVENT_SOURCE_SWITCH) { - if (platform == PLATFORM_SYS11) { - switch (event->eventId) { - case 63: - if (event->value) { - Keyboard.press(KEY_END); - } else { - Keyboard.release(KEY_END); - } - break; - case 64: - if (event->value) { - Keyboard.press(KEY_PAGE_UP); - } else { - Keyboard.release(KEY_PAGE_UP); - } - break; - } - } + if (event->sourceId == EVENT_SOURCE_SWITCH) { + if (platform == PLATFORM_SYS11) { + switch (event->eventId) { + case 63: + if (event->value) { + Keyboard.press(KEY_END); + } else { + Keyboard.release(KEY_END); + } + break; + case 64: + if (event->value) { + Keyboard.press(KEY_PAGE_UP); + } else { + Keyboard.release(KEY_PAGE_UP); + } + break; + } } + } #endif } diff --git a/src/VisualPinball/VPXComLink.h b/src/VisualPinball/VPXComLink.h index 6fff299..c3a3b90 100644 --- a/src/VisualPinball/VPXComLink.h +++ b/src/VisualPinball/VPXComLink.h @@ -15,23 +15,22 @@ #include "../EventDispatcher/EventListener.h" class VPXComLink : public EventListener { -public: - VPXComLink(EventDispatcher* eD, byte pf) { - eventDispatcher = eD; - platform = pf; - } + public: + VPXComLink(EventDispatcher* eD, byte pf) { + eventDispatcher = eD; + platform = pf; + } - void update(); + void update(); - void handleEvent(Event* event); + void handleEvent(Event* event); - void handleEvent(ConfigEvent* event) {} + void handleEvent(ConfigEvent* event) {} -private: - EventDispatcher* eventDispatcher; - - byte platform; + private: + EventDispatcher* eventDispatcher; + byte platform; }; #endif diff --git a/test/IOBoardController/src/main.cpp b/test/IOBoardController/src/main.cpp index c7d2b45..4ea1fb1 100644 --- a/test/IOBoardController/src/main.cpp +++ b/test/IOBoardController/src/main.cpp @@ -2,24 +2,21 @@ #include -#include "IOBoardController.h" #include "EffectsController.h" +#include "IOBoardController.h" IOBoardController ioBoardController(CONTROLLER_16_8_1); EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_LIBPINMAME); void setup() { - ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); + ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); } -void setup1() { -} +void setup1() {} void loop() { - ioBoardController.update(); - //Serial.println(16 - ((int) (analogRead(28) + 30) / 60)); + ioBoardController.update(); + // Serial.println(16 - ((int) (analogRead(28) + 30) / 60)); } -void loop1() { - effectsController.update(); -} +void loop1() { effectsController.update(); } diff --git a/test/IO_16_8_1/src/main.cpp b/test/IO_16_8_1/src/main.cpp index f0e55e4..f827f14 100644 --- a/test/IO_16_8_1/src/main.cpp +++ b/test/IO_16_8_1/src/main.cpp @@ -2,9 +2,9 @@ #include -#include "IOBoardController.h" #include "EffectsController.h" #include "EventDispatcher/CrossLinkDebugger.h" +#include "IOBoardController.h" IOBoardController ioBoardController(CONTROLLER_16_8_1); // Platform will be adjusted by ConfigEvent. @@ -19,100 +19,87 @@ bool core_0_initilized = false; // same MultiCoreCrosslink to send and receive events between // both cores. -void setup() -{ - uint32_t timeout = millis() + 2000; - - Serial.begin(115200); - // The Pico implements USB itself so special care must be taken. Use while(!Serial){} in the setup() code before printing anything so that it waits for the USB connection to be established. - // https://community.platformio.org/t/serial-monitor-not-working/1512/25 - while (!Serial && millis() < timeout) - { - } - - if (Serial) - { - usb_debugging = true; - delay(10); - ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); - } - - core_0_initilized = true; - rp2040.restartCore1(); - - Serial1.setTX(0); - Serial1.setRX(1); - Serial1.setFIFOSize(128); // @todo find the right size. - Serial1.begin(115200); - // The Pico implements USB itself so special care must be taken. Use while(!Serial){} in the setup() code before printing anything so that it waits for the USB connection to be established. - // https://community.platformio.org/t/serial-monitor-not-working/1512/25 - while (!Serial1) - { - } +void setup() { + uint32_t timeout = millis() + 2000; + + Serial.begin(115200); + // The Pico implements USB itself so special care must be taken. Use + // while(!Serial){} in the setup() code before printing anything so that it + // waits for the USB connection to be established. + // https://community.platformio.org/t/serial-monitor-not-working/1512/25 + while (!Serial && millis() < timeout) { + } + + if (Serial) { + usb_debugging = true; + delay(10); + ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); + } + + core_0_initilized = true; + rp2040.restartCore1(); + + Serial1.setTX(0); + Serial1.setRX(1); + Serial1.setFIFOSize(128); // @todo find the right size. + Serial1.begin(115200); + // The Pico implements USB itself so special care must be taken. Use + // while(!Serial){} in the setup() code before printing anything so that it + // waits for the USB connection to be established. + // https://community.platformio.org/t/serial-monitor-not-working/1512/25 + while (!Serial1) { + } } -void setup1() -{ - while (!core_0_initilized) - { - } - - if (usb_debugging) - { - delay(10); - effectsController.eventDispatcher()->addListener(new CrossLinkDebugger()); - } - - effectsController.eventDispatcher()->setMultiCoreCrossLink( - ioBoardController.eventDispatcher()->getMultiCoreCrossLink()); - - effectsController.ledBuiltInDevice()->off(); - - effectsController.addEffect( - new LedOnEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_LIGHT, 11, 1), - 1, // priority - 0, // repeat, -1 means endless - 0 // mode - ); - - effectsController.addEffect( - new NullEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_LIGHT, 11, 0), - 1, // priority - 0, // repeat, -1 means endless - 0 // mode - ); - - effectsController.addEffect( - new LedBlinkEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_ERROR, 1, /* board ID */ 0), - 2, // priority - -1, // repeat, -1 means endless - 0 // mode - ); - - effectsController.addEffect( - new NullEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_NO_ERROR, 1, /* board ID */ 0), - 3, // priority - 0, // repeat - 0 // mode - ); - - effectsController.start(); +void setup1() { + while (!core_0_initilized) { + } + + if (usb_debugging) { + delay(10); + effectsController.eventDispatcher()->addListener(new CrossLinkDebugger()); + } + + effectsController.eventDispatcher()->setMultiCoreCrossLink( + ioBoardController.eventDispatcher()->getMultiCoreCrossLink()); + + effectsController.ledBuiltInDevice()->off(); + + effectsController.addEffect(new LedOnEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_SOURCE_LIGHT, 11, 1), + 1, // priority + 0, // repeat, -1 means endless + 0 // mode + ); + + effectsController.addEffect(new NullEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_SOURCE_LIGHT, 11, 0), + 1, // priority + 0, // repeat, -1 means endless + 0 // mode + ); + + effectsController.addEffect(new LedBlinkEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_ERROR, 1, /* board ID */ 0), + 2, // priority + -1, // repeat, -1 means endless + 0 // mode + ); + + effectsController.addEffect(new NullEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_NO_ERROR, 1, /* board ID */ 0), + 3, // priority + 0, // repeat + 0 // mode + ); + + effectsController.start(); } -void loop() -{ - ioBoardController.update(); -} +void loop() { ioBoardController.update(); } -void loop1() -{ - effectsController.update(); -} +void loop1() { effectsController.update(); } diff --git a/test/InputController/src/main.cpp b/test/InputController/src/main.cpp index e66a237..b2c9739 100644 --- a/test/InputController/src/main.cpp +++ b/test/InputController/src/main.cpp @@ -1,58 +1,65 @@ // Markus Kalkbrenner 2022 -#include -#include #include +#include +#include InputController inputController(CONTROLLER_MEGA_ALL_INPUT, PLATFORM_WPC); void setup() { - inputController.pupComLink()->setSerial(Serial); - inputController.pin2Dmd()->setSerial(Serial1); - inputController.eventDispatcher()->setCrossLinkSerial(Serial3); - - //inputController.switchMatrix()->setLastColToRead(9); - inputController.switchMatrix()->registerFieldAsEvent(3, 1, 13); // Start Button - inputController.switchMatrix()->registerFieldAsEvent(7, 2, 27); // Ball Shooter - inputController.switchMatrix()->registerFieldAsEvent(8, 2, 28); // Rocket Kicker - inputController.switchMatrix()->registerFieldAsEvent(1, 3, 31); // Bumper - inputController.switchMatrix()->registerFieldAsEvent(2, 3, 32); // Bumper - inputController.switchMatrix()->registerFieldAsEvent(3, 3, 33); // Bumper - inputController.switchMatrix()->registerFieldAsEvent(1, 6, 61); // Lower Skill - inputController.switchMatrix()->registerFieldAsEvent(2, 6, 62); // Center Skill - inputController.switchMatrix()->registerFieldAsEvent(3, 6, 63); // Upper Skill - - inputController.lightMatrix()->registerAllFieldsAsEvent(); - - inputController.solenoids()->registerJ125(1, 17); // Flasher Bumpers - inputController.solenoids()->registerJ125(2, 18); // Flasher Power Payoff - inputController.solenoids()->registerJ125(3, 19); // Flasher Mini-Playfield - inputController.solenoids()->registerJ125(5, 20); // Flasher Upper Left Ramp - inputController.solenoids()->registerJ125(6, 21); // Flasher Left Magnet - inputController.solenoids()->registerJ125(8, 23); // Flasher Lower Right Magnet - inputController.solenoids()->registerJ125(9, 24); // Flasher Gumball Motor - - inputController.solenoids()->registerJ124(1, 25); // Left Mini Magnet - inputController.solenoids()->registerJ124(2, 26); // Right Mini Magnet - inputController.solenoids()->registerJ124(3, 27); // Left Ramp Diverter - inputController.solenoids()->registerJ124(5, 28); // Inside Ramp - - - inputController.eventDispatcher()->addListener(new CrossLinkDebugger()); - inputController.eventDispatcher()->addListener(inputController.pupComLink(), EVENT_SOURCE_ANY); - - inputController.switchMatrix()->start(); - inputController.lightMatrix()->start(); + inputController.pupComLink()->setSerial(Serial); + inputController.pin2Dmd()->setSerial(Serial1); + inputController.eventDispatcher()->setCrossLinkSerial(Serial3); + + // inputController.switchMatrix()->setLastColToRead(9); + inputController.switchMatrix()->registerFieldAsEvent(3, 1, + 13); // Start Button + inputController.switchMatrix()->registerFieldAsEvent(7, 2, + 27); // Ball Shooter + inputController.switchMatrix()->registerFieldAsEvent(8, 2, + 28); // Rocket Kicker + inputController.switchMatrix()->registerFieldAsEvent(1, 3, 31); // Bumper + inputController.switchMatrix()->registerFieldAsEvent(2, 3, 32); // Bumper + inputController.switchMatrix()->registerFieldAsEvent(3, 3, 33); // Bumper + inputController.switchMatrix()->registerFieldAsEvent(1, 6, + 61); // Lower Skill + inputController.switchMatrix()->registerFieldAsEvent(2, 6, + 62); // Center Skill + inputController.switchMatrix()->registerFieldAsEvent(3, 6, + 63); // Upper Skill + + inputController.lightMatrix()->registerAllFieldsAsEvent(); + + inputController.solenoids()->registerJ125(1, 17); // Flasher Bumpers + inputController.solenoids()->registerJ125(2, 18); // Flasher Power Payoff + inputController.solenoids()->registerJ125(3, 19); // Flasher Mini-Playfield + inputController.solenoids()->registerJ125(5, 20); // Flasher Upper Left Ramp + inputController.solenoids()->registerJ125(6, 21); // Flasher Left Magnet + inputController.solenoids()->registerJ125(8, + 23); // Flasher Lower Right Magnet + inputController.solenoids()->registerJ125(9, 24); // Flasher Gumball Motor + + inputController.solenoids()->registerJ124(1, 25); // Left Mini Magnet + inputController.solenoids()->registerJ124(2, 26); // Right Mini Magnet + inputController.solenoids()->registerJ124(3, 27); // Left Ramp Diverter + inputController.solenoids()->registerJ124(5, 28); // Inside Ramp + + inputController.eventDispatcher()->addListener(new CrossLinkDebugger()); + inputController.eventDispatcher()->addListener(inputController.pupComLink(), + EVENT_SOURCE_ANY); + + inputController.switchMatrix()->start(); + inputController.lightMatrix()->start(); } void loop() { - // read data - inputController.pin2Dmd()->update(); - inputController.switchMatrix()->update(); - inputController.lightMatrix()->update(); - inputController.solenoids()->update(); - inputController.testButtons()->update(); - - // handle data - inputController.eventDispatcher()->update(); + // read data + inputController.pin2Dmd()->update(); + inputController.switchMatrix()->update(); + inputController.lightMatrix()->update(); + inputController.solenoids()->update(); + inputController.testButtons()->update(); + + // handle data + inputController.eventDispatcher()->update(); } diff --git a/test/NanoController/src/main.cpp b/test/NanoController/src/main.cpp index 3294ffd..0eee5e2 100644 --- a/test/NanoController/src/main.cpp +++ b/test/NanoController/src/main.cpp @@ -8,49 +8,48 @@ #define PPUC_NUM_LEDS_1 40 #define PPUC_LED_TYPE_1 WS2812_GRB -#include #include +#include EffectsController effectsController(PPUC_CONTROLLER, PLATFORM_DATA_EAST); -InputController inputController(PPUC_CONTROLLER, PLATFORM_DATA_EAST, effectsController.eventDispatcher()); +InputController inputController(PPUC_CONTROLLER, PLATFORM_DATA_EAST, + effectsController.eventDispatcher()); void setup() { - inputController.pin2Dmd()->setSerial(Serial); + inputController.pin2Dmd()->setSerial(Serial); - effectsController.createCombinedGiAndLightMatrixWs2812FXDevice(1); - //effectsController.setBrightness(1, 128); + effectsController.createCombinedGiAndLightMatrixWs2812FXDevice(1); + // effectsController.setBrightness(1, 128); - effectsController.attachBrightnessControl(1, 1); + effectsController.attachBrightnessControl(1, 1); - effectsController.giAndLightMatrix(1)->setHeatUp(40); - effectsController.giAndLightMatrix(1)->setAfterGlow(280); + effectsController.giAndLightMatrix(1)->setHeatUp(40); + effectsController.giAndLightMatrix(1)->setAfterGlow(280); - effectsController.giAndLightMatrix(1)->assignLedRangeToGiString(1, 0, 39); + effectsController.giAndLightMatrix(1)->assignLedRangeToGiString(1, 0, 39); - effectsController.addEffect( - new WS2812FXEffect(FX_MODE_STATIC, WHITE, 0, 0), - effectsController.giAndLightMatrix(1), - new Event(EVENT_SOURCE_EFFECT, 1, 255), - 1, // priority - 0, // repeat - -1 // mode - ); + effectsController.addEffect(new WS2812FXEffect(FX_MODE_STATIC, WHITE, 0, 0), + effectsController.giAndLightMatrix(1), + new Event(EVENT_SOURCE_EFFECT, 1, 255), + 1, // priority + 0, // repeat + -1 // mode + ); - effectsController.addEffect( - new LedBlinkEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_EFFECT, 1, 255), - 1, // priority - 50, // repeat - -1 // mode - ); + effectsController.addEffect(new LedBlinkEffect(), + effectsController.ledBuiltInDevice(), + new Event(EVENT_SOURCE_EFFECT, 1, 255), + 1, // priority + 50, // repeat + -1 // mode + ); - effectsController.start(); + effectsController.start(); } void loop() { - inputController.pin2Dmd()->update(); + inputController.pin2Dmd()->update(); - // The effectController also calls update() on the eventDispatcher. - effectsController.update(); + // The effectController also calls update() on the eventDispatcher. + effectsController.update(); } From d4c16c8dde89f2317bc2fe32a0950637db4a021b Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 13 Jan 2024 20:03:30 +0100 Subject: [PATCH 031/102] fixed PWM device event handling --- src/EventDispatcher/Event.h | 2 + src/EventDispatcher/EventDispatcher.cpp | 68 ++++++++++++++---------- src/IOBoardController.cpp | 2 +- src/IOBoardController.h | 3 ++ src/IODevices/PwmDevices.cpp | 12 ++--- src/IODevices/PwmDevices.h | 5 ++ test/IO_16_8_1/platformio.ini | 1 + test/IO_16_8_1/src/main.cpp | 8 +-- test/IO_16_8_1_ouput_test/platformio.ini | 18 +++++++ test/IO_16_8_1_ouput_test/src/main.cpp | 31 +++++++++++ 10 files changed, 112 insertions(+), 38 deletions(-) create mode 100644 test/IO_16_8_1_ouput_test/platformio.ini create mode 100644 test/IO_16_8_1_ouput_test/src/main.cpp diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index a5bbab8..866bd24 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -6,6 +6,8 @@ #ifndef EVENT_h #define EVENT_h +#include + #define EVENT_SOURCE_ANY 42 // "*" #define EVENT_SOURCE_DEBUG 66 // "B" Debug #define EVENT_CONFIGURATION 67 // "C" Configure I/O diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index b8fc6af..f172498 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -96,14 +96,16 @@ void EventDispatcher::callListeners(Event *event, int sender, bool flush) { } #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Sent event: sourceId "); - Serial.print(event->sourceId); - Serial.print(", eventId "); - Serial.print(event->eventId, DEC); - Serial.print(", value "); - Serial.println(event->value, DEC); - rp2040.resumeOtherCore(); + if (false && Serial) { + rp2040.idleOtherCore(); + Serial.print("Sent event: sourceId "); + Serial.print(event->sourceId); + Serial.print(", eventId "); + Serial.print(event->eventId, DEC); + Serial.print(", value "); + Serial.println(event->value, DEC); + rp2040.resumeOtherCore(); + } #endif } } @@ -246,43 +248,53 @@ void EventDispatcher::update() { } } else { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Received wrong second stop byte "); - Serial.println(stopByte, DEC); - rp2040.resumeOtherCore(); + if (Serial) { + rp2040.idleOtherCore(); + Serial.print("Received wrong second stop byte "); + Serial.println(stopByte, DEC); + rp2040.resumeOtherCore(); + } #endif } } else { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Received wrong first stop byte "); - Serial.println(stopByte, DEC); - rp2040.resumeOtherCore(); + if (Serial) { + rp2040.idleOtherCore(); + Serial.print("Received wrong first stop byte "); + Serial.println(stopByte, DEC); + rp2040.resumeOtherCore(); + } #endif } } else { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Received invalid event id "); - Serial.println(eventId, DEC); - rp2040.resumeOtherCore(); + if (Serial) { + rp2040.idleOtherCore(); + Serial.print("Received invalid event id "); + Serial.println(eventId, DEC); + rp2040.resumeOtherCore(); + } #endif } } } else { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Received invalid source id "); - Serial.println(sourceId, DEC); - rp2040.resumeOtherCore(); + if (Serial) { + rp2040.idleOtherCore(); + Serial.print("Received invalid source id "); + Serial.println(sourceId, DEC); + rp2040.resumeOtherCore(); + } #endif } } else { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) - rp2040.idleOtherCore(); - Serial.print("Received wrong start byte "); - Serial.println(startByte, DEC); - rp2040.resumeOtherCore(); + if (Serial) { + rp2040.idleOtherCore(); + Serial.print("Received wrong start byte "); + Serial.println(startByte, DEC); + rp2040.resumeOtherCore(); + } #endif // We didn't receive a start byte. Fake "success" to start over with the // next byte. diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 893ae76..ac00440 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -45,7 +45,7 @@ void IOBoardController::update() { void IOBoardController::handleEvent(Event *event) { switch (event->sourceId) { case EVENT_PING: - _eventDispatcher->dispatch(new Event(EVENT_PONG, 1, boardId)); + _eventDispatcher->dispatch(new Event(EVENT_PONG, m_debug ? 99 : 1, boardId)); break; case EVENT_RUN: diff --git a/src/IOBoardController.h b/src/IOBoardController.h index 961fed0..bfa26a9 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -40,6 +40,8 @@ class IOBoardController : public EventListener { void update(); + void debug() { m_debug = true; } + private: PwmDevices *_pwmDevices; Switches *_switches; @@ -49,6 +51,7 @@ class IOBoardController : public EventListener { bool activePwmDevices = false; bool activeSwitches = false; bool activeSwitchMatrix = false; + bool m_debug = false; int controllerType; byte boardId; diff --git a/src/IODevices/PwmDevices.cpp b/src/IODevices/PwmDevices.cpp index 64859a5..56c31f0 100644 --- a/src/IODevices/PwmDevices.cpp +++ b/src/IODevices/PwmDevices.cpp @@ -13,7 +13,7 @@ void PwmDevices::registerSolenoid(byte p, byte n, byte pow, byte minPT, fastSwitch[last] = fS; pinMode(p, OUTPUT); - analogWrite(p, 0); + digitalWrite(p, 0); type[last++] = PWM_TYPE_SOLENOID; } } @@ -70,22 +70,22 @@ void PwmDevices::update() { void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) { _ms = millis(); - if (targetState && !activated[i]) { + if (targetState && activated[i] == 0) { // Event received to activate the output and output isn't activated already. // Activate it! analogWrite(port[i], power[i]); // Rememebr whin it got activated. activated[i] = _ms; - } else if (!targetState && activated[i]) { + } else if (!targetState && activated[i] > 0) { // Event received to deactivate the output. // Check if a minimum pulse time is configured for this output. - if (minPulseTime[i] > 0 && (_ms - activated[i]) < minPulseTime[i]) { + if (_ms > activated[i] && minPulseTime[i] > 0 && (_ms - activated[i]) < minPulseTime[i]) { // A minimum pulse time is configured for this output. // Don't deactivate it immediately but schedule its later deactivation. scheduled[i] = true; } else { // Deactivate the output. - analogWrite(port[i], 0); + digitalWrite(port[i], 0); // Mark the output as deactivated. activated[i] = 0; } @@ -95,7 +95,7 @@ void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) { void PwmDevices::handleEvent(Event *event) { _ms = millis(); - switch (event->eventId) { + switch (event->sourceId) { case EVENT_SOURCE_SOLENOID: for (byte i = 0; i < last; i++) { if ((type[i] == PWM_TYPE_SOLENOID || type[i] == PWM_TYPE_FLASHER) && diff --git a/src/IODevices/PwmDevices.h b/src/IODevices/PwmDevices.h index e2bda2b..12274f6 100644 --- a/src/IODevices/PwmDevices.h +++ b/src/IODevices/PwmDevices.h @@ -23,6 +23,11 @@ class PwmDevices : public EventListener { eventDispatcher->addListener(this, EVENT_SOURCE_LIGHT); eventDispatcher->addListener(this, EVENT_SOURCE_SOLENOID); eventDispatcher->addListener(this, EVENT_SOURCE_SWITCH); + + // Adjust PWM properties if needed. + //analogWriteFreq(5000); + //analogWriteRange(65535); + //analogWriteResolution(16); } void registerSolenoid(byte p, byte n, byte pow, byte minPT, byte maxPT, diff --git a/test/IO_16_8_1/platformio.ini b/test/IO_16_8_1/platformio.ini index 6694b43..647bd04 100644 --- a/test/IO_16_8_1/platformio.ini +++ b/test/IO_16_8_1/platformio.ini @@ -7,6 +7,7 @@ board = pico framework = arduino board_build.core = earlephilhower board_build.filesystem_size = 0.5m +monitor_speed = 115200 build_flags = -D PICO_STDIO_USB ; enable stdio over USB lib_extra_dirs = diff --git a/test/IO_16_8_1/src/main.cpp b/test/IO_16_8_1/src/main.cpp index f827f14..2d7dcf4 100644 --- a/test/IO_16_8_1/src/main.cpp +++ b/test/IO_16_8_1/src/main.cpp @@ -32,16 +32,18 @@ void setup() { if (Serial) { usb_debugging = true; + ioBoardController.debug(); delay(10); - ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); + //ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); } core_0_initilized = true; rp2040.restartCore1(); + // RS485 connection. Serial1.setTX(0); Serial1.setRX(1); - Serial1.setFIFOSize(128); // @todo find the right size. + Serial1.setFIFOSize(1024); // @todo find the right size. Serial1.begin(115200); // The Pico implements USB itself so special care must be taken. Use // while(!Serial){} in the setup() code before printing anything so that it @@ -57,7 +59,7 @@ void setup1() { if (usb_debugging) { delay(10); - effectsController.eventDispatcher()->addListener(new CrossLinkDebugger()); + //effectsController.eventDispatcher()->addListener(new CrossLinkDebugger()); } effectsController.eventDispatcher()->setMultiCoreCrossLink( diff --git a/test/IO_16_8_1_ouput_test/platformio.ini b/test/IO_16_8_1_ouput_test/platformio.ini new file mode 100644 index 0000000..647bd04 --- /dev/null +++ b/test/IO_16_8_1_ouput_test/platformio.ini @@ -0,0 +1,18 @@ +[platformio] +default_envs = pico + +[env:pico] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +board = pico +framework = arduino +board_build.core = earlephilhower +board_build.filesystem_size = 0.5m +monitor_speed = 115200 +build_flags = + -D PICO_STDIO_USB ; enable stdio over USB +lib_extra_dirs = + ../.. +lib_deps = + mkalkbrenner/WavePWM + kitesurfer1404/WS2812FX + Bounce2 diff --git a/test/IO_16_8_1_ouput_test/src/main.cpp b/test/IO_16_8_1_ouput_test/src/main.cpp new file mode 100644 index 0000000..67eb0e4 --- /dev/null +++ b/test/IO_16_8_1_ouput_test/src/main.cpp @@ -0,0 +1,31 @@ +// Markus Kalkbrenner 2023 + +#include + +bool state = 0; + +void setup() { + pinMode(19, OUTPUT); + pinMode(20, OUTPUT); + pinMode(21, OUTPUT); + pinMode(22, OUTPUT); + pinMode(23, OUTPUT); + pinMode(24, OUTPUT); + pinMode(26, OUTPUT); + pinMode(27, OUTPUT); +} + +void loop() { + digitalWrite(19, state); + digitalWrite(20, state); + digitalWrite(21, state); + digitalWrite(22, state); + digitalWrite(23, state); + digitalWrite(24, state); + digitalWrite(26, state); + digitalWrite(27, state); + + state = !state; + + delay(1000); +} From cfdc4bda1246ed92b11d059e642fcfeb62e70d3a Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 14 Jan 2024 22:29:55 +0100 Subject: [PATCH 032/102] implemented device reset --- src/IOBoardController.cpp | 9 ++++++++- src/IODevices/PwmDevices.cpp | 29 ++++++++++++++++++++++++++--- src/IODevices/PwmDevices.h | 1 + src/IODevices/SwitchMatrix.cpp | 17 +++++++++++++++++ src/IODevices/SwitchMatrix.h | 18 +++++------------- src/IODevices/Switches.cpp | 11 +++++++++++ src/IODevices/Switches.h | 1 + 7 files changed, 69 insertions(+), 17 deletions(-) diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index ac00440..cc58d09 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -45,6 +45,7 @@ void IOBoardController::update() { void IOBoardController::handleEvent(Event *event) { switch (event->sourceId) { case EVENT_PING: + // In case that serial debugging is active, send 99 as PING response, otherwise 1. _eventDispatcher->dispatch(new Event(EVENT_PONG, m_debug ? 99 : 1, boardId)); break; @@ -53,7 +54,13 @@ void IOBoardController::handleEvent(Event *event) { break; case EVENT_RESET: - // @todo clear all configurations or reboot the device. + // Clear all configurations or reboot the device. + _pwmDevices->reset(); + _switches->reset(); + _switchMatrix->reset(); + activePwmDevices = false; + activeSwitches = false; + activeSwitchMatrix = false; break; } } diff --git a/src/IODevices/PwmDevices.cpp b/src/IODevices/PwmDevices.cpp index 56c31f0..6e40f3a 100644 --- a/src/IODevices/PwmDevices.cpp +++ b/src/IODevices/PwmDevices.cpp @@ -42,6 +42,28 @@ void PwmDevices::registerLamp(byte p, byte n, byte pow) { } } +void PwmDevices::reset() { + for (uint8_t i = 0; i < MAX_PWM_OUTPUTS; i++) { + if (i < last) { + // Turn off PWM output. + digitalWrite(port[i], 0); + } + port[i] = 0; + number[i] = 0; + power[i] = 0; + minPulseTime[i] = 0; + maxPulseTime[i] = 0; + holdPower[i] = 0; + holdPowerActivationTime[i] = 0; + fastSwitch[i] = 0; + type[i] = 0; + activated[i] = 0; + scheduled[i] = 0; + } + + last = 0; +} + void PwmDevices::update() { _ms = millis(); @@ -54,7 +76,7 @@ void PwmDevices::update() { // Deactivate the output if it is scheduled for delayed deactivation and // the minimum pulse time is reached. Deactivate the output if the // maximum pulse time is reached. - analogWrite(port[i], 0); + digitalWrite(port[i], 0); activated[i] = 0; scheduled[i] = false; } else if ((holdPowerActivationTime[i] > 0) && @@ -74,12 +96,13 @@ void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) { // Event received to activate the output and output isn't activated already. // Activate it! analogWrite(port[i], power[i]); - // Rememebr whin it got activated. + // Rememebr when it got activated. activated[i] = _ms; } else if (!targetState && activated[i] > 0) { // Event received to deactivate the output. // Check if a minimum pulse time is configured for this output. - if (_ms > activated[i] && minPulseTime[i] > 0 && (_ms - activated[i]) < minPulseTime[i]) { + if (_ms > activated[i] && minPulseTime[i] > 0 && + (_ms - activated[i]) < minPulseTime[i]) { // A minimum pulse time is configured for this output. // Don't deactivate it immediately but schedule its later deactivation. scheduled[i] = true; diff --git a/src/IODevices/PwmDevices.h b/src/IODevices/PwmDevices.h index 12274f6..db75e3c 100644 --- a/src/IODevices/PwmDevices.h +++ b/src/IODevices/PwmDevices.h @@ -36,6 +36,7 @@ class PwmDevices : public EventListener { void registerLamp(byte p, byte n, byte pow); void update(); + void reset(); void handleEvent(Event *event); diff --git a/src/IODevices/SwitchMatrix.cpp b/src/IODevices/SwitchMatrix.cpp index 577390d..ecf466b 100644 --- a/src/IODevices/SwitchMatrix.cpp +++ b/src/IODevices/SwitchMatrix.cpp @@ -18,6 +18,23 @@ void SwitchMatrix::registerRow(byte p, byte n) { } } +void SwitchMatrix::reset() { + pulseTime = 2; + pauseTime = 2; + activeLow = false; + active = false; + column = 0; + + for (uint8_t col = 0; col < MAX_COLUMNS; col++) { + columns[col] = -1; + for (uint8_t row = 0; row < MAX_ROWS; row++) { + rows[row] = -1; + state[col][row] = 0; + toggled[col][row] = 0; + } + } +} + void SwitchMatrix::update() { unsigned long ms = millis(); if (active) { diff --git a/src/IODevices/SwitchMatrix.h b/src/IODevices/SwitchMatrix.h index a26d603..221a8c8 100644 --- a/src/IODevices/SwitchMatrix.h +++ b/src/IODevices/SwitchMatrix.h @@ -23,17 +23,8 @@ class SwitchMatrix : public EventListener { SwitchMatrix(byte bId, EventDispatcher *eD) { boardId = bId; platform = PLATFORM_LIBPINMAME; - pulseTime = 2; - pauseTime = 2; - activeLow = false; - active = false; - - for (int col = 0; col < MAX_COLUMNS; col++) { - columns[col] = -1; - } - for (int row = 0; row < MAX_ROWS; row++) { - rows[row] = -1; - } + + reset(); _ms = millis(); _eventDispatcher = eD; @@ -48,6 +39,7 @@ class SwitchMatrix : public EventListener { void setPulseTime(byte pT); void update(); + void reset(); void handleEvent(Event *event); @@ -63,8 +55,8 @@ class SwitchMatrix : public EventListener { unsigned long _ms; - int columns[MAX_COLUMNS]; - int rows[MAX_ROWS]; + int8_t columns[MAX_COLUMNS]; + int8_t rows[MAX_ROWS]; bool state[MAX_COLUMNS][MAX_ROWS] = {0}; bool toggled[MAX_COLUMNS][MAX_ROWS] = {0}; byte column = 0; diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index e934089..5d156c0 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -19,6 +19,17 @@ void Switches::registerSwitch(byte p, byte n) { } } +void Switches::reset() { + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { + port[i] = 0; + number[i] = 0; + state[i] = 0; + toggled[i] = 0; + } + + last = -1; +} + void Switches::update() { // Wait for SWITCH_DEBOUNCE milliseconds to debounce the switches. That covers // the edge case that a switch was hit right before the last polling of diff --git a/src/IODevices/Switches.h b/src/IODevices/Switches.h index f2a6759..e4fcfd4 100644 --- a/src/IODevices/Switches.h +++ b/src/IODevices/Switches.h @@ -34,6 +34,7 @@ class Switches : public EventListener { void registerSwitch(byte p, byte n); void update(); + void reset(); void handleEvent(Event* event); From 3f6eeaad92624d6aceafffa079670d51194be1f6 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 15 Jan 2024 18:30:10 +0100 Subject: [PATCH 033/102] fixed minPulseTime and holdTime --- src/EventDispatcher/EventDispatcher.cpp | 6 +++--- src/IOBoardController.h | 6 +++--- src/IODevices/PwmDevices.cpp | 10 ++++++---- src/IODevices/PwmDevices.h | 16 ++++++++-------- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index f172498..3e43a56 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -191,9 +191,9 @@ void EventDispatcher::update() { byte topic = hwSerial[i]->read(); byte index = hwSerial[i]->read(); byte key = hwSerial[i]->read(); - int value = (hwSerial[i]->read() << 24) + - (hwSerial[i]->read() << 16) + - (hwSerial[i]->read() << 8) + hwSerial[i]->read(); + uint32_t value = (((uint32_t)hwSerial[i]->read()) << 24) + + (((uint32_t)hwSerial[i]->read()) << 16) + + (((uint32_t)hwSerial[i]->read()) << 8) + hwSerial[i]->read(); byte stopByte = hwSerial[i]->read(); if (stopByte == 0b10101010) { stopByte = hwSerial[i]->read(); diff --git a/src/IOBoardController.h b/src/IOBoardController.h index bfa26a9..24c4bc2 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -58,10 +58,10 @@ class IOBoardController : public EventListener { byte port = 0; byte number = 0; byte power = 0; - byte minPulseTime = 0; - byte maxPulseTime = 0; + uint16_t minPulseTime = 0; + uint16_t maxPulseTime = 0; byte holdPower = 0; - byte holdPowerActivationTime = 0; + uint16_t holdPowerActivationTime = 0; byte fastSwitch = 0; byte type = 0; diff --git a/src/IODevices/PwmDevices.cpp b/src/IODevices/PwmDevices.cpp index 6e40f3a..a79c320 100644 --- a/src/IODevices/PwmDevices.cpp +++ b/src/IODevices/PwmDevices.cpp @@ -1,7 +1,8 @@ #include "PwmDevices.h" -void PwmDevices::registerSolenoid(byte p, byte n, byte pow, byte minPT, - byte maxPT, byte hP, byte hPAT, byte fS) { +void PwmDevices::registerSolenoid(byte p, byte n, byte pow, uint16_t minPT, + uint16_t maxPT, byte hP, uint16_t hPAT, + byte fS) { if (last < MAX_PWM_OUTPUTS) { port[last] = p; number[last] = n; @@ -71,7 +72,8 @@ void PwmDevices::update() { for (byte i = 0; i < last; i++) { if (activated[i] > 0) { // The output is active. - if ((scheduled[i] && ((_ms - activated[i]) > minPulseTime[i])) || + if ((scheduled[i] && (minPulseTime[i] > 0) && + ((_ms - activated[i]) > minPulseTime[i])) || ((maxPulseTime[i] > 0) && ((_ms - activated[i]) > maxPulseTime[i]))) { // Deactivate the output if it is scheduled for delayed deactivation and // the minimum pulse time is reached. Deactivate the output if the @@ -101,7 +103,7 @@ void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) { } else if (!targetState && activated[i] > 0) { // Event received to deactivate the output. // Check if a minimum pulse time is configured for this output. - if (_ms > activated[i] && minPulseTime[i] > 0 && + if ((_ms >= activated[i]) && (minPulseTime[i] > 0) && (_ms - activated[i]) < minPulseTime[i]) { // A minimum pulse time is configured for this output. // Don't deactivate it immediately but schedule its later deactivation. diff --git a/src/IODevices/PwmDevices.h b/src/IODevices/PwmDevices.h index db75e3c..f7d034a 100644 --- a/src/IODevices/PwmDevices.h +++ b/src/IODevices/PwmDevices.h @@ -25,13 +25,13 @@ class PwmDevices : public EventListener { eventDispatcher->addListener(this, EVENT_SOURCE_SWITCH); // Adjust PWM properties if needed. - //analogWriteFreq(5000); - //analogWriteRange(65535); - //analogWriteResolution(16); + // analogWriteFreq(5000); + // analogWriteRange(65535); + // analogWriteResolution(16); } - void registerSolenoid(byte p, byte n, byte pow, byte minPT, byte maxPT, - byte hP, byte hPAT, byte fS); + void registerSolenoid(byte p, byte n, byte pow, uint16_t minPT, + uint16_t maxPT, byte hP, uint16_t hPAT, byte fS); void registerFlasher(byte p, byte n, byte pow); void registerLamp(byte p, byte n, byte pow); @@ -48,10 +48,10 @@ class PwmDevices : public EventListener { byte port[MAX_PWM_OUTPUTS] = {0}; byte number[MAX_PWM_OUTPUTS] = {0}; byte power[MAX_PWM_OUTPUTS] = {0}; - byte minPulseTime[MAX_PWM_OUTPUTS] = {0}; - byte maxPulseTime[MAX_PWM_OUTPUTS] = {0}; + uint16_t minPulseTime[MAX_PWM_OUTPUTS] = {0}; + uint16_t maxPulseTime[MAX_PWM_OUTPUTS] = {0}; byte holdPower[MAX_PWM_OUTPUTS] = {0}; - byte holdPowerActivationTime[MAX_PWM_OUTPUTS] = {0}; + uint16_t holdPowerActivationTime[MAX_PWM_OUTPUTS] = {0}; byte fastSwitch[MAX_PWM_OUTPUTS] = {0}; byte type[MAX_PWM_OUTPUTS] = {0}; unsigned long activated[MAX_PWM_OUTPUTS] = {0}; From 82fc736f8476467703406c57e1a9bd7c5c5fed7d Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 19 Jun 2024 17:33:23 +0200 Subject: [PATCH 034/102] 0.3.0 --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index eba1bca..084730e 100644 --- a/library.json +++ b/library.json @@ -6,7 +6,7 @@ "name": "Markus Kalkbrenner", "url": "https://github.com/mkalkbrenner/PPUC" }, - "version": "0.2.2", + "version": "0.3.0", "downloadUrl": "https://github.com/mkalkbrenner/PPUC/archive/main.zip", "frameworks": "arduino", "platforms": ["atmelavr", "teensy"], From 662b699f0d9f902cf6de5d6537cd67aec3e72e59 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 19 Jun 2024 17:35:01 +0200 Subject: [PATCH 035/102] fixed URLs --- library.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 084730e..654fddf 100644 --- a/library.json +++ b/library.json @@ -4,7 +4,7 @@ "keywords": "pinball", "authors": { "name": "Markus Kalkbrenner", - "url": "https://github.com/mkalkbrenner/PPUC" + "url": "https://github.com/PPUC" }, "version": "0.3.0", "downloadUrl": "https://github.com/mkalkbrenner/PPUC/archive/main.zip", @@ -12,7 +12,7 @@ "platforms": ["atmelavr", "teensy"], "repository": { "type": "git", - "url": "https://github.com/mkalkbrenner/PPUC.git" + "url": "https://github.com/PPUC/io-boards.git" }, "license": "GPL-3.0-or-later", "export": { From fceed713081788e4c46c7372627cde1c529396a2 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 19 Jun 2024 17:36:51 +0200 Subject: [PATCH 036/102] Updated name --- library.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 654fddf..64eab09 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { - "name": "PPUC", - "description": "Pinball Power-Up Controller", + "name": "PPUC/io-boards", + "description": "Pinball Power-Up Controller IO Boards Library", "keywords": "pinball", "authors": { "name": "Markus Kalkbrenner", From 9bbdc71c0971dc23d0218dea76366bedf5f92d4d Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Fri, 20 Sep 2024 14:21:54 +0200 Subject: [PATCH 037/102] added Williams System 4 platform --- src/PPUCPlatforms.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/PPUCPlatforms.h b/src/PPUCPlatforms.h index 745bb48..24dab31 100644 --- a/src/PPUCPlatforms.h +++ b/src/PPUCPlatforms.h @@ -8,7 +8,8 @@ #define PLATFORM_WPC 1 #define PLATFORM_DATA_EAST 2 -#define PLATFORM_SYS11 3 +#define PLATFORM_SYS4 4 +#define PLATFORM_SYS11 11 #define PLATFORM_LIBPINMAME 100 #endif From 330c449c02a6621868da61f57618a266cb31e97e Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Fri, 20 Sep 2024 16:48:36 +0200 Subject: [PATCH 038/102] fixed initial switch states, closes #5 --- src/IODevices/Switches.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index 5d156c0..ae897a0 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -15,7 +15,9 @@ void Switches::registerSwitch(byte p, byte n) { port[++last] = p; number[last] = n; toggled[last] = false; - state[last] = !digitalRead(p); + // Set the inverted value as initial state to let update() send the initial state on game start. + // Note, we have active LOW! + state[last] = digitalRead(p); } } @@ -24,7 +26,7 @@ void Switches::reset() { port[i] = 0; number[i] = 0; state[i] = 0; - toggled[i] = 0; + toggled[i] = false; } last = -1; @@ -38,6 +40,7 @@ void Switches::update() { if (millis() - _ms >= SWITCH_DEBOUNCE) { for (int i = 0; i <= last; i++) { if (!toggled[i]) { + // Note, we have active LOW! bool new_state = !digitalRead(port[i]); if (new_state != state[i]) { state[i] = new_state; From 5803310aa54874c884301be204b0ee04c394d319 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Fri, 20 Sep 2024 17:15:17 +0200 Subject: [PATCH 039/102] handle mid power ports used as stateful switches. closes #2 closes #6 --- src/IOBoardController.cpp | 2 +- src/IODevices/Switches.cpp | 21 ++++++++++++++------- src/IODevices/Switches.h | 5 ++++- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index cc58d09..a9ee896 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -74,7 +74,7 @@ void IOBoardController::handleEvent(ConfigEvent *event) { port = event->value; break; case CONFIG_TOPIC_NUMBER: - _switches->registerSwitch((byte)port, event->value); + _switches->registerSwitch((byte)port, event->value, (controllerType == CONTROLLER_16_8_1 && port >= 15 && port <= 18)); activeSwitches = true; break; } diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index ae897a0..e536d0b 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -1,13 +1,9 @@ #include "Switches.h" -void Switches::registerSwitch(byte p, byte n) { +void Switches::registerSwitch(byte p, byte n, bool stateful) { if (last < (MAX_SWITCHES - 1)) { - if (p >= 15 && p <= 18) { - // Set mid power output as input. - pinMode(p, OUTPUT); - digitalWrite(p, HIGH); - delayMicroseconds(10); - digitalWrite(p, LOW); + if (stateful) { + resetStatefulPort(p); } pinMode(p, INPUT); @@ -21,6 +17,16 @@ void Switches::registerSwitch(byte p, byte n) { } } +void Switches::resetStatefulPort(byte p) { + // Set mid power output as input. + pinMode(p, OUTPUT); + digitalWrite(p, HIGH); + delayMicroseconds(10); + digitalWrite(p, LOW); + delayMicroseconds(10); + pinMode(p, INPUT); +} + void Switches::reset() { for (uint8_t i = 0; i < MAX_SWITCHES; i++) { port[i] = 0; @@ -50,6 +56,7 @@ void Switches::update() { // flippers, kick backs, jets and sling shots. _eventDispatcher->dispatch(new Event( EVENT_SOURCE_SWITCH, word(0, number[i]), state[i], true)); + if (stateful[i]) resetStatefulPort(i); } } } diff --git a/src/IODevices/Switches.h b/src/IODevices/Switches.h index e4fcfd4..6d4262b 100644 --- a/src/IODevices/Switches.h +++ b/src/IODevices/Switches.h @@ -31,7 +31,7 @@ class Switches : public EventListener { _eventDispatcher->addListener(this, EVENT_READ_SWITCHES); } - void registerSwitch(byte p, byte n); + void registerSwitch(byte p, byte n, bool stateful = false); void update(); void reset(); @@ -41,6 +41,8 @@ class Switches : public EventListener { void handleEvent(ConfigEvent* event) {} private: + void resetStatefulPort(byte p); + byte boardId; unsigned long _ms; @@ -48,6 +50,7 @@ class Switches : public EventListener { byte number[MAX_SWITCHES] = {0}; bool state[MAX_SWITCHES] = {0}; bool toggled[MAX_SWITCHES] = {0}; + bool stateful[MAX_SWITCHES] = {0}; int last = -1; EventDispatcher* _eventDispatcher; From ef6a91392393e8100e3da633d17a16c8b62aa1c8 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 22 Sep 2024 00:43:47 +0200 Subject: [PATCH 040/102] fixed lamp string position --- ...CombinedGiAndLightMatrixWS2812FXDevice.cpp | 8 +++-- src/EffectsController.cpp | 2 +- src/EventDispatcher/EventDispatcher.cpp | 2 +- test/IO_16_8_1/src/main.cpp | 34 ------------------- 4 files changed, 7 insertions(+), 39 deletions(-) diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp index 4b0ff17..5830a50 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp @@ -76,7 +76,7 @@ void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE( if (ledLightMatrixPositions[number][i] == -1) { ledLightMatrixPositions[number][i] = led; ledLightMatrixColors[number][i] = color; - break; + return; } } } @@ -90,10 +90,9 @@ void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToFlasher( if (ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + offset][i] == -1) { ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + offset][i] = led; ledLightMatrixColors[_LIGHT_MATRIX_SIZE + offset][i] = color; - break; + return; } } - return; } } @@ -208,6 +207,7 @@ void CombinedGiAndLightMatrixWS2812FXDevice::handleEvent(Event *event) { number = ((column - 1) * 8) + row; } + // We start at "0", not "1". --number; } else { number = 255; @@ -337,6 +337,7 @@ void CombinedGiAndLightMatrixWS2812FXDevice::updateAfterGlow() { ledLightMatrixColors[number][i]); } } + continue; } else { glowBrightness = wavePWMHeatUp->getExponentialValue(millis() - heatUp[number]); @@ -350,6 +351,7 @@ void CombinedGiAndLightMatrixWS2812FXDevice::updateAfterGlow() { RGBW_BLACK); } } + continue; } else { glowBrightness = wavePWMAfterGlow->getExponentialValue( millis() - afterGlow[number] + msAfterGlow); diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 0cdbe17..b4eccf8 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -224,7 +224,7 @@ void EffectsController::handleEvent(ConfigEvent *event) { } else { ((CombinedGiAndLightMatrixWS2812FXDevice *) ws2812FXDevices[0][0]) - ->assignLedToLightMatrix( + ->assignLedToLightMatrixDE( config_number, config_ledNumber, config_color); } break; diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index 3e43a56..32acb3d 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -136,7 +136,7 @@ void EventDispatcher::callListeners(ConfigEvent *event, int sender) { msg[3] = event->topic; msg[4] = event->index; msg[5] = event->key; - msg[6] = event->value >> 24; + msg[6] = (event->value >> 24) & 0xff; msg[7] = (event->value >> 16) & 0xff; msg[8] = (event->value >> 8) & 0xff; msg[9] = event->value & 0xff; diff --git a/test/IO_16_8_1/src/main.cpp b/test/IO_16_8_1/src/main.cpp index 2d7dcf4..c8f669f 100644 --- a/test/IO_16_8_1/src/main.cpp +++ b/test/IO_16_8_1/src/main.cpp @@ -65,40 +65,6 @@ void setup1() { effectsController.eventDispatcher()->setMultiCoreCrossLink( ioBoardController.eventDispatcher()->getMultiCoreCrossLink()); - effectsController.ledBuiltInDevice()->off(); - - effectsController.addEffect(new LedOnEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_LIGHT, 11, 1), - 1, // priority - 0, // repeat, -1 means endless - 0 // mode - ); - - effectsController.addEffect(new NullEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_LIGHT, 11, 0), - 1, // priority - 0, // repeat, -1 means endless - 0 // mode - ); - - effectsController.addEffect(new LedBlinkEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_ERROR, 1, /* board ID */ 0), - 2, // priority - -1, // repeat, -1 means endless - 0 // mode - ); - - effectsController.addEffect(new NullEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_NO_ERROR, 1, /* board ID */ 0), - 3, // priority - 0, // repeat - 0 // mode - ); - effectsController.start(); } From 8f014269869f22572a90efe574594ac3bbdc4d56 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 23 Sep 2024 18:21:07 +0200 Subject: [PATCH 041/102] fixe LED assignment, added debug funtion --- src/EffectsController.cpp | 13 +++++------ src/EffectsController.h | 2 +- src/EventDispatcher/CrossLinkDebugger.cpp | 27 +++++++++++++++++++++++ src/EventDispatcher/CrossLinkDebugger.h | 6 +++-- src/EventDispatcher/Event.h | 1 + src/IODevices/PwmDevices.cpp | 3 +++ test/IO_16_8_1/src/main.cpp | 4 ++-- 7 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index b4eccf8..55ad0ea 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -139,12 +139,12 @@ void EffectsController::handleEvent(ConfigEvent *event) { switch (event->key) { case CONFIG_TOPIC_PORT: config_port = event->value; - config_type = 0; + config_neoPixelType = 0; config_amount = 0; config_afterGlow = 0; break; case CONFIG_TOPIC_TYPE: - config_type = event->value; + config_neoPixelType = (neoPixelType)event->value; break; case CONFIG_TOPIC_AMOUNT_LEDS: config_amount = event->value; @@ -157,8 +157,9 @@ void EffectsController::handleEvent(ConfigEvent *event) { if (!ws2812FXDevices[0][0]) { ws2812FXDevices[0][0] = new CombinedGiAndLightMatrixWS2812FXDevice( - new WS2812FX(config_amount, config_port, config_type), 0, - config_amount - 1, 0, 0, _eventDispatcher); + new WS2812FX(config_amount, config_port, + config_neoPixelType), + 0, config_amount - 1, 0, 0, _eventDispatcher); ws2812FXDevices[0][0]->getWS2812FX()->init(); ws2812FXDeviceCounters[0] = 1; @@ -191,7 +192,6 @@ void EffectsController::handleEvent(ConfigEvent *event) { config_type = 0; config_number = 0; config_ledNumber = 0; - config_brightness = 0; config_color = 0; break; case CONFIG_TOPIC_TYPE: @@ -203,9 +203,6 @@ void EffectsController::handleEvent(ConfigEvent *event) { case CONFIG_TOPIC_LED_NUMBER: config_ledNumber = event->value; break; - case CONFIG_TOPIC_BRIGHTNESS: - config_brightness = event->value; - break; case CONFIG_TOPIC_COLOR: config_color = event->value; switch (config_type) { diff --git a/src/EffectsController.h b/src/EffectsController.h index 28aadc4..0f7aee7 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -411,12 +411,12 @@ class EffectsController : public EventListener { byte boardId = 255; byte config_port = 0; byte config_type = 0; + neoPixelType config_neoPixelType = 0; byte config_amount = 0; byte config_afterGlow = 0; byte config_heatUp = 0; byte config_number = 0; byte config_ledNumber = 0; - byte config_brightness = 0; uint32_t config_color = 0; unsigned long ws2812UpdateInterval = 0; diff --git a/src/EventDispatcher/CrossLinkDebugger.cpp b/src/EventDispatcher/CrossLinkDebugger.cpp index 42d004b..ae26d0c 100644 --- a/src/EventDispatcher/CrossLinkDebugger.cpp +++ b/src/EventDispatcher/CrossLinkDebugger.cpp @@ -1,5 +1,7 @@ #include "CrossLinkDebugger.h" +bool CrossLinkDebugger::active = false; + CrossLinkDebugger::CrossLinkDebugger() { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) if (get_core_num() == 0) { @@ -21,6 +23,8 @@ CrossLinkDebugger::CrossLinkDebugger() { rp2040.resumeOtherCore(); } #endif + + CrossLinkDebugger::active = true; } void CrossLinkDebugger::handleEvent(Event *event) { @@ -64,3 +68,26 @@ void CrossLinkDebugger::handleEvent(ConfigEvent *event) { rp2040.resumeOtherCore(); #endif } + +void CrossLinkDebugger::debug(const char *format, ...) { + if (CrossLinkDebugger::active) { + char buffer[1024]; + + va_list args; + va_start(args, format); + vsnprintf(buffer, sizeof(buffer), format, args); + va_end(args); + +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) + rp2040.idleOtherCore(); + Serial.print("Core "); + Serial.print(get_core_num(), DEC); + Serial.print(" "); +#endif + Serial.print("debug: "); + Serial.println(buffer); +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) + rp2040.resumeOtherCore(); +#endif + } +} diff --git a/src/EventDispatcher/CrossLinkDebugger.h b/src/EventDispatcher/CrossLinkDebugger.h index 5a4103c..ee21079 100644 --- a/src/EventDispatcher/CrossLinkDebugger.h +++ b/src/EventDispatcher/CrossLinkDebugger.h @@ -9,6 +9,7 @@ #define CROSSLINKDEBUGGER_h #include +#include #include "Event.h" #include "EventListener.h" @@ -20,8 +21,9 @@ class CrossLinkDebugger : public EventListener { void handleEvent(Event *event); void handleEvent(ConfigEvent *event); - private: - static bool lock; + static void debug(const char *format, ...); + + static bool active; }; #endif diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 866bd24..8a6333d 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -62,6 +62,7 @@ #define PWM_TYPE_SOLENOID 1 // Coil #define PWM_TYPE_FLASHER 2 // Flasher #define PWM_TYPE_LAMP 3 // Lamp +#define PWM_TYPE_SHAKER 4 // Shaker #define LED_TYPE_GI 1 // GI #define LED_TYPE_FLASHER 2 // Flasher diff --git a/src/IODevices/PwmDevices.cpp b/src/IODevices/PwmDevices.cpp index a79c320..aabd1b9 100644 --- a/src/IODevices/PwmDevices.cpp +++ b/src/IODevices/PwmDevices.cpp @@ -1,5 +1,7 @@ #include "PwmDevices.h" +#include "EventDispatcher/CrossLinkDebugger.h" + void PwmDevices::registerSolenoid(byte p, byte n, byte pow, uint16_t minPT, uint16_t maxPT, byte hP, uint16_t hPAT, byte fS) { @@ -100,6 +102,7 @@ void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) { analogWrite(port[i], power[i]); // Rememebr when it got activated. activated[i] = _ms; + CrossLinkDebugger::debug("Activated PWM device on port %d", port[i] + 1); } else if (!targetState && activated[i] > 0) { // Event received to deactivate the output. // Check if a minimum pulse time is configured for this output. diff --git a/test/IO_16_8_1/src/main.cpp b/test/IO_16_8_1/src/main.cpp index c8f669f..adfcc1e 100644 --- a/test/IO_16_8_1/src/main.cpp +++ b/test/IO_16_8_1/src/main.cpp @@ -34,7 +34,7 @@ void setup() { usb_debugging = true; ioBoardController.debug(); delay(10); - //ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); + ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); } core_0_initilized = true; @@ -59,7 +59,7 @@ void setup1() { if (usb_debugging) { delay(10); - //effectsController.eventDispatcher()->addListener(new CrossLinkDebugger()); + effectsController.eventDispatcher()->addListener(new CrossLinkDebugger()); } effectsController.eventDispatcher()->setMultiCoreCrossLink( From e2f6d0ee51c135946fead7fa59f4669172bf926a Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Tue, 24 Sep 2024 20:40:19 +0200 Subject: [PATCH 042/102] implemented reset support, GI for non WPC games, blinking internal LED after game start --- src/EffectDevices/WS2812FXDevice.h | 8 ++++ src/Effects/EffectContainer.h | 5 ++ src/EffectsController.cpp | 61 ++++++++++++++++--------- src/EffectsController.h | 8 +++- src/EventDispatcher/Event.h | 2 +- src/EventDispatcher/EventDispatcher.cpp | 13 +++++- src/IOBoardController.cpp | 32 ++++++++++--- src/IOBoardController.h | 1 + src/IODevices/PwmDevices.cpp | 5 ++ src/IODevices/Switches.cpp | 2 + 10 files changed, 107 insertions(+), 30 deletions(-) diff --git a/src/EffectDevices/WS2812FXDevice.h b/src/EffectDevices/WS2812FXDevice.h index e011599..caad481 100644 --- a/src/EffectDevices/WS2812FXDevice.h +++ b/src/EffectDevices/WS2812FXDevice.h @@ -28,6 +28,14 @@ class WS2812FXDevice : public EffectDevice { this->lastSegment = lastSegment; } + ~WS2812FXDevice() { + reset(); + + if (ws2812FX) { + delete ws2812FX; + } + } + virtual void on(); virtual void off(); diff --git a/src/Effects/EffectContainer.h b/src/Effects/EffectContainer.h index 64d538d..2a8c925 100644 --- a/src/Effects/EffectContainer.h +++ b/src/Effects/EffectContainer.h @@ -47,6 +47,11 @@ struct EffectContainer { repeat = r; mode = m; } + + ~EffectContainer() { + if (effect) delete effect; + if (event) delete event; + } }; #endif diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 55ad0ea..0760a02 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -100,31 +100,50 @@ void EffectsController::setBrightness(byte port, byte brightness) { } void EffectsController::handleEvent(Event *event) { - for (int i = 0; i <= stackCounter; i++) { - if (event->sourceId == stackEffectContainers[i]->event->sourceId && - event->eventId == stackEffectContainers[i]->event->eventId && - event->value == stackEffectContainers[i]->event->value && - (mode == stackEffectContainers[i]->mode || - -1 == stackEffectContainers[i]->mode // -1 means any mode - )) { - for (int k = 0; k <= stackCounter; k++) { - if (stackEffectContainers[i]->device == - stackEffectContainers[k]->device && - stackEffectContainers[k]->effect->isRunning()) { - if (stackEffectContainers[i]->priority > - stackEffectContainers[k]->priority) { - stackEffectContainers[k]->effect->terminate(); - stackEffectContainers[i]->effect->start( - stackEffectContainers[i]->repeat); + switch (event->sourceId) { + case EVENT_RESET: + if (_shakerPWMDevice) _shakerPWMDevice->reset(); + if (_ledPWMDevice) _ledPWMDevice->reset(); + + for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) { + if (ws2812FXstates[i]) { + for (int k = ws2812FXDeviceCounters[i] - 1; k >= 0; k--) { + if (ws2812FXDevices[i][k]) { + delete ws2812FXDevices[i][k]; + } } - break; } - if (k == stackCounter) { - stackEffectContainers[i]->effect->start( - stackEffectContainers[i]->repeat); + } + + break; + + default: + for (int i = 0; i <= stackCounter; i++) { + if (event->sourceId == stackEffectContainers[i]->event->sourceId && + event->eventId == stackEffectContainers[i]->event->eventId && + event->value == stackEffectContainers[i]->event->value && + (mode == stackEffectContainers[i]->mode || + -1 == stackEffectContainers[i]->mode // -1 means any mode + )) { + for (int k = 0; k <= stackCounter; k++) { + if (stackEffectContainers[i]->device == + stackEffectContainers[k]->device && + stackEffectContainers[k]->effect->isRunning()) { + if (stackEffectContainers[i]->priority > + stackEffectContainers[k]->priority) { + stackEffectContainers[k]->effect->terminate(); + stackEffectContainers[i]->effect->start( + stackEffectContainers[i]->repeat); + } + break; + } + if (k == stackCounter) { + stackEffectContainers[i]->effect->start( + stackEffectContainers[i]->repeat); + } + } } } - } } } diff --git a/src/EffectsController.h b/src/EffectsController.h index 0f7aee7..9adabbf 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -307,6 +307,12 @@ class EffectsController : public EventListener { _ledBuiltInDevice = new LedBuiltInDevice(); _ledBuiltInDevice->on(); + + addEffect(new LedBlinkEffect(), _ledBuiltInDevice, new Event(EVENT_RUN), + 1, // priority + -1, // repeat + 0 // mode + ); } else { Serial.print("Unsupported Effects Controller: "); Serial.println(controllerType); @@ -394,7 +400,7 @@ class EffectsController : public EventListener { int ws2812FXDeviceCounters[PPUC_MAX_WS2812FX_DEVICES] = {0}; bool ws2812FXstates[PPUC_MAX_WS2812FX_DEVICES] = {0}; bool ws2812FXrunning[PPUC_MAX_WS2812FX_DEVICES] = {0}; - bool ws2812FXbrightness[PPUC_MAX_WS2812FX_DEVICES] = {0}; + byte ws2812FXbrightness[PPUC_MAX_WS2812FX_DEVICES] = {0}; #if defined(__IMXRT1062__) // Teensy 4.1 WS2812Serial* ws2812Serial[PPUC_MAX_WS2812FX_DEVICES]; #endif diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 8a6333d..c36b259 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -15,7 +15,7 @@ #define EVENT_SOURCE_EVENT \ 69 // "E" VPX/DOF/PUP common event from different system, like #define EVENT_SOURCE_EFFECT 70 // "F" custom event from running Effect -#define EVENT_SOURCE_GI 71 // "G" WPC GI +#define EVENT_SOURCE_GI 71 // "G" GI #define EVENT_SOURCE_LIGHT \ 76 // "L" VPX/DOF/PUP lights, mainly playfield inserts #define EVENT_NULL 78 // "N" NULL event diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index 32acb3d..a8363a5 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -46,6 +46,16 @@ void EventDispatcher::addListener(EventListener *eventListener, char sourceId) { } void EventDispatcher::dispatch(Event *event) { + if (EVENT_RESET == event->sourceId) { + // Force immediate handling of the reset event. Forget about the others. + for (int i = 0; i <= stackCounter; i++) { + if (stackEvents[i]) { + delete stackEvents[i]; + } + } + stackCounter = -1; + } + if (stackCounter < (EVENT_STACK_SIZE - 1)) { stackEvents[++stackCounter] = event; @@ -193,7 +203,8 @@ void EventDispatcher::update() { byte key = hwSerial[i]->read(); uint32_t value = (((uint32_t)hwSerial[i]->read()) << 24) + (((uint32_t)hwSerial[i]->read()) << 16) + - (((uint32_t)hwSerial[i]->read()) << 8) + hwSerial[i]->read(); + (((uint32_t)hwSerial[i]->read()) << 8) + + hwSerial[i]->read(); byte stopByte = hwSerial[i]->read(); if (stopByte == 0b10101010) { stopByte = hwSerial[i]->read(); diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index a9ee896..b29ba8b 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -1,5 +1,7 @@ #include "IOBoardController.h" +#include "EventDispatcher/CrossLinkDebugger.h" + IOBoardController::IOBoardController(int cT) { _eventDispatcher = new EventDispatcher(); _eventDispatcher->addListener(this, EVENT_CONFIGURATION); @@ -39,14 +41,28 @@ void IOBoardController::update() { } } + if (resetTimer > 0 && resetTimer < millis()) { + if (!m_debug) { +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) + rp2040.reboot(); +#endif + } else { + resetTimer = 0; + CrossLinkDebugger::debug( + "Skipped reset to keep USB debugging connection alive."); + } + } + eventDispatcher()->update(); } void IOBoardController::handleEvent(Event *event) { switch (event->sourceId) { case EVENT_PING: - // In case that serial debugging is active, send 99 as PING response, otherwise 1. - _eventDispatcher->dispatch(new Event(EVENT_PONG, m_debug ? 99 : 1, boardId)); + // In case that serial debugging is active, send 99 as PING response, + // otherwise 1. + _eventDispatcher->dispatch( + new Event(EVENT_PONG, m_debug ? 99 : 1, boardId)); break; case EVENT_RUN: @@ -58,9 +74,11 @@ void IOBoardController::handleEvent(Event *event) { _pwmDevices->reset(); _switches->reset(); _switchMatrix->reset(); - activePwmDevices = false; - activeSwitches = false; - activeSwitchMatrix = false; + + // Issue a reset of the board in 3 seconds. + // Core 1 should have enough time to rest it's devices. + resetTimer = millis() + 3000; + break; } } @@ -74,7 +92,9 @@ void IOBoardController::handleEvent(ConfigEvent *event) { port = event->value; break; case CONFIG_TOPIC_NUMBER: - _switches->registerSwitch((byte)port, event->value, (controllerType == CONTROLLER_16_8_1 && port >= 15 && port <= 18)); + _switches->registerSwitch((byte)port, event->value, + (controllerType == CONTROLLER_16_8_1 && + port >= 15 && port <= 18)); activeSwitches = true; break; } diff --git a/src/IOBoardController.h b/src/IOBoardController.h index 24c4bc2..421f852 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -64,6 +64,7 @@ class IOBoardController : public EventListener { uint16_t holdPowerActivationTime = 0; byte fastSwitch = 0; byte type = 0; + uint32_t resetTimer = 0; EventDispatcher *_eventDispatcher; #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) diff --git a/src/IODevices/PwmDevices.cpp b/src/IODevices/PwmDevices.cpp index aabd1b9..9942b86 100644 --- a/src/IODevices/PwmDevices.cpp +++ b/src/IODevices/PwmDevices.cpp @@ -83,6 +83,9 @@ void PwmDevices::update() { digitalWrite(port[i], 0); activated[i] = 0; scheduled[i] = false; + CrossLinkDebugger::debug( + "Performed scheduled deactivation of PWM device on port %d", + port[i] + 1); } else if ((holdPowerActivationTime[i] > 0) && ((_ms - activated[i]) > holdPowerActivationTime[i])) { // Reduce the power of the activated output if the hold power activation @@ -116,6 +119,8 @@ void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) { digitalWrite(port[i], 0); // Mark the output as deactivated. activated[i] = 0; + CrossLinkDebugger::debug("Deactivated PWM device on port %d", + port[i] + 1); } } } diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index e536d0b..8c78aa2 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -33,6 +33,8 @@ void Switches::reset() { number[i] = 0; state[i] = 0; toggled[i] = false; + if (stateful[i]) resetStatefulPort(i); + stateful[i] = false; } last = -1; From e807f4a56318aeca23fa4923621ac6e0cb3bb784 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 26 Sep 2024 16:02:17 +0200 Subject: [PATCH 043/102] added high power turn off based on coin door closed switch and game on solenoid --- src/HighPowerOffAware.h | 76 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/HighPowerOffAware.h diff --git a/src/HighPowerOffAware.h b/src/HighPowerOffAware.h new file mode 100644 index 0000000..96f681a --- /dev/null +++ b/src/HighPowerOffAware.h @@ -0,0 +1,76 @@ +#ifndef HIGHPOWEROFFAWARE_h +#define HIGHPOWEROFFAWARE_h + +#include + +#include "EventDispatcher/Event.h" +#include "EventDispatcher/EventDispatcher.h" + +class HighPowerOffAware : public EventListener { + public: + HighPowerOffAware() {} + + HighPowerOffAware(EventDispatcher *eventDispatcher) { + eventDispatcher->addListener(this, EVENT_CONFIGURATION); + eventDispatcher->addListener(this, EVENT_RUN); + eventDispatcher->addListener(this, EVENT_SOURCE_SOLENOID); + eventDispatcher->addListener(this, EVENT_SOURCE_SWITCH); + } + + void handleEvent(Event *event) { + powerToggled = false; + + if (coinDoorSwitch > 0 && event->sourceId == EVENT_SOURCE_SWITCH && + (byte)event->eventId == coinDoorSwitch) { + coinDoorClosed = (bool)event->value; + powerToggled = true; + } + + if (gameOnSolenoid > 0 && event->sourceId == EVENT_SOURCE_SOLENOID && + (byte)event->eventId == gameOnSolenoid) { + powerOn = (bool)event->value; + powerToggled = true; + } + + if (event->sourceId == EVENT_RUN) { + // Fake coin door switch and gome on solenoid if not present in the + // current game. + if ((bool)event->value) { + if (0 == coinDoorSwitch) coinDoorClosed = true; + if (0 == gameOnSolenoid) powerOn = true; + } else { + powerOn = false; + powerToggled = true; + } + } + } + + void handleEvent(ConfigEvent *event) { + switch (event->topic) { + case CONFIG_TOPIC_COIN_DOOR_CLOSED_SWITCH: + switch (event->key) { + case CONFIG_TOPIC_NUMBER: + coinDoorClosed = event->value; + break; + } + break; + + case CONFIG_TOPIC_GAME_ON_SOLENOID: + switch (event->key) { + case CONFIG_TOPIC_NUMBER: + gameOnSolenoid = event->value; + break; + } + break; + } + } + + protected: + byte coinDoorSwitch = 0; + byte gameOnSolenoid = 0; + bool coinDoorClosed = false; + bool powerOn = false; + bool powerToggled = false; +}; + +#endif From 2354b1b711e08886ef34f253a71d8c8c2b0d0d00 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 26 Sep 2024 16:03:13 +0200 Subject: [PATCH 044/102] added high power turn off based on coin door closed switch and game on solenoid --- src/EffectDevices/WavePWMDevice.cpp | 17 +++++- src/EffectDevices/WavePWMDevice.h | 12 +++- src/EffectsController.h | 4 +- src/EventDispatcher/Event.h | 16 +++--- src/IODevices/PwmDevices.cpp | 89 +++++++++++++++++------------ src/IODevices/PwmDevices.h | 11 +--- 6 files changed, 94 insertions(+), 55 deletions(-) diff --git a/src/EffectDevices/WavePWMDevice.cpp b/src/EffectDevices/WavePWMDevice.cpp index 870d272..eee23df 100644 --- a/src/EffectDevices/WavePWMDevice.cpp +++ b/src/EffectDevices/WavePWMDevice.cpp @@ -1,14 +1,29 @@ #include "WavePWMDevice.h" +#include "../EventDispatcher/CrossLinkDebugger.h" + void WavePWMDevice::on() { reset(); } void WavePWMDevice::reset() { setPWM(0); } void WavePWMDevice::setPWM(uint8_t pwm) { - analogWrite(pin, pwm); + if (powerOn && coinDoorClosed) { + analogWrite(pin, pwm); + } currentPWM = pwm; } uint8_t WavePWMDevice::getPWM() { return currentPWM; } WavePWM* WavePWMDevice::getWavePWM() { return wavePWM; } + +void WavePWMDevice::handleEvent(Event* event) { + HighPowerOffAware::handleEvent(event); + + if (!(powerOn && coinDoorClosed) && powerToggled) { + // Deactivate the output. + digitalWrite(pin, 0); + powerOn = false; + CrossLinkDebugger::debug("Deactivated PWM device on port %d", pin); + } +} \ No newline at end of file diff --git a/src/EffectDevices/WavePWMDevice.h b/src/EffectDevices/WavePWMDevice.h index 6933cf5..44133a1 100644 --- a/src/EffectDevices/WavePWMDevice.h +++ b/src/EffectDevices/WavePWMDevice.h @@ -11,9 +11,10 @@ #include #include +#include "../HighPowerOffAware.h" #include "EffectDevice.h" -class WavePWMDevice : public EffectDevice { +class WavePWMDevice : public EffectDevice, public HighPowerOffAware { public: WavePWMDevice(int pin) { this->wavePWM = new WavePWM(); @@ -21,6 +22,13 @@ class WavePWMDevice : public EffectDevice { pinMode(pin, OUTPUT); } + WavePWMDevice(int pin, EventDispatcher* eventDispatcher) + : HighPowerOffAware(eventDispatcher) { + this->wavePWM = new WavePWM(); + this->pin = pin; + pinMode(pin, OUTPUT); + } + void on(); void reset(); @@ -31,6 +39,8 @@ class WavePWMDevice : public EffectDevice { WavePWM* getWavePWM(); + void handleEvent(Event* event); + protected: WavePWM* wavePWM; diff --git a/src/EffectsController.h b/src/EffectsController.h index 9adabbf..392f694 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -118,7 +118,7 @@ class EffectsController : public EventListener { _ledBuiltInDevice->on(); _nullDevice = new NullDevice(); _testButtons = new EffectControllerTestButtons(_eventDispatcher); - _shakerPWMDevice = new WavePWMDevice(36); + _shakerPWMDevice = new WavePWMDevice(36, _eventDispatcher); _shakerPWMDevice->off(); _ledPWMDevice = new WavePWMDevice(37); _ledPWMDevice->off(); @@ -285,7 +285,7 @@ class EffectsController : public EventListener { _ledBuiltInDevice = new LedBuiltInDevice(); _ledBuiltInDevice->on(); _nullDevice = new NullDevice(); - _shakerPWMDevice = new WavePWMDevice(9); + _shakerPWMDevice = new WavePWMDevice(9, _eventDispatcher); _shakerPWMDevice->off(); #if defined(PIN_A0) brightnessControlBasePin = PIN_A0; diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index c36b259..77cc52d 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -32,13 +32,15 @@ #define EVENT_NO_ERROR 98 // NO ERROR #define EVENT_ERROR 99 // ERROR -#define CONFIG_TOPIC_PLATFORM 102 // "f" -#define CONFIG_TOPIC_LED_STRING 103 // "g" -#define CONFIG_TOPIC_LAMPS 108 // "l" -#define CONFIG_TOPIC_MECHS 109 // "m" -#define CONFIG_TOPIC_PWM 112 // "p" -#define CONFIG_TOPIC_SWITCHES 115 // "s" -#define CONFIG_TOPIC_SWITCH_MATRIX 120 // "x" +#define CONFIG_TOPIC_PLATFORM 102 // "f" +#define CONFIG_TOPIC_LED_STRING 103 // "g" +#define CONFIG_TOPIC_LAMPS 108 // "l" +#define CONFIG_TOPIC_MECHS 109 // "m" +#define CONFIG_TOPIC_PWM 112 // "p" +#define CONFIG_TOPIC_COIN_DOOR_CLOSED_SWITCH 113 // "q" +#define CONFIG_TOPIC_GAME_ON_SOLENOID 114 // "r" +#define CONFIG_TOPIC_SWITCHES 115 // "s" +#define CONFIG_TOPIC_SWITCH_MATRIX 120 // "x" #define CONFIG_TOPIC_HOLD_POWER_ACTIVATION_TIME 65 // "A" #define CONFIG_TOPIC_BRIGHTNESS 66 // "B" diff --git a/src/IODevices/PwmDevices.cpp b/src/IODevices/PwmDevices.cpp index 9942b86..fce5d6f 100644 --- a/src/IODevices/PwmDevices.cpp +++ b/src/IODevices/PwmDevices.cpp @@ -74,9 +74,10 @@ void PwmDevices::update() { for (byte i = 0; i < last; i++) { if (activated[i] > 0) { // The output is active. + uint16_t timePassed = _ms - activated[i]; if ((scheduled[i] && (minPulseTime[i] > 0) && - ((_ms - activated[i]) > minPulseTime[i])) || - ((maxPulseTime[i] > 0) && ((_ms - activated[i]) > maxPulseTime[i]))) { + (timePassed > minPulseTime[i])) || + ((maxPulseTime[i] > 0) && (timePassed > maxPulseTime[i]))) { // Deactivate the output if it is scheduled for delayed deactivation and // the minimum pulse time is reached. Deactivate the output if the // maximum pulse time is reached. @@ -84,13 +85,17 @@ void PwmDevices::update() { activated[i] = 0; scheduled[i] = false; CrossLinkDebugger::debug( - "Performed scheduled deactivation of PWM device on port %d", - port[i] + 1); + "Performed scheduled deactivation of PWM device on port %d after " + "%dms", + port[i], timePassed); } else if ((holdPowerActivationTime[i] > 0) && - ((_ms - activated[i]) > holdPowerActivationTime[i])) { + (timePassed > holdPowerActivationTime[i])) { // Reduce the power of the activated output if the hold power activation // time pased since the activation. analogWrite(port[i], holdPower[i]); + CrossLinkDebugger::debug( + "Reduced power of PWM device on port %d after %dms", port[i], + timePassed); } } } @@ -105,7 +110,7 @@ void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) { analogWrite(port[i], power[i]); // Rememebr when it got activated. activated[i] = _ms; - CrossLinkDebugger::debug("Activated PWM device on port %d", port[i] + 1); + CrossLinkDebugger::debug("Activated PWM device on port %d", port[i]); } else if (!targetState && activated[i] > 0) { // Event received to deactivate the output. // Check if a minimum pulse time is configured for this output. @@ -119,46 +124,58 @@ void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) { digitalWrite(port[i], 0); // Mark the output as deactivated. activated[i] = 0; - CrossLinkDebugger::debug("Deactivated PWM device on port %d", - port[i] + 1); + CrossLinkDebugger::debug("Deactivated PWM device on port %d", port[i]); } } } void PwmDevices::handleEvent(Event *event) { + HighPowerOffAware::handleEvent(event); + _ms = millis(); - switch (event->sourceId) { - case EVENT_SOURCE_SOLENOID: - for (byte i = 0; i < last; i++) { - if ((type[i] == PWM_TYPE_SOLENOID || type[i] == PWM_TYPE_FLASHER) && - number[i] == (byte)event->eventId) { - updateSolenoidOrFlasher((bool)event->value, i); + if (powerOn && coinDoorClosed) { + switch (event->sourceId) { + case EVENT_SOURCE_SOLENOID: + for (byte i = 0; i < last; i++) { + if ((type[i] == PWM_TYPE_SOLENOID || type[i] == PWM_TYPE_FLASHER) && + number[i] == (byte)event->eventId) { + updateSolenoidOrFlasher((bool)event->value, i); + } } - } - break; - - case EVENT_SOURCE_SWITCH: - // A switch event was triggered or received. Activate or deactivate any - // output that is configured as "fastSwitch" for that switch. - for (byte i = 0; i < last; i++) { - if (type[i] == PWM_TYPE_SOLENOID && - fastSwitch[i] == (byte)event->eventId) { - updateSolenoidOrFlasher((bool)event->value, i); + break; + + case EVENT_SOURCE_SWITCH: + // A switch event was triggered or received. Activate or deactivate any + // output that is configured as "fastSwitch" for that switch. + for (byte i = 0; i < last; i++) { + if (type[i] == PWM_TYPE_SOLENOID && + fastSwitch[i] == (byte)event->eventId) { + updateSolenoidOrFlasher((bool)event->value, i); + } } - } - break; - - case EVENT_SOURCE_LIGHT: - for (byte i = 0; i < last; i++) { - if (type[i] == PWM_TYPE_LAMP && number[i] == (byte)event->eventId) { - if (event->value) { - analogWrite(port[i], power[i]); - } else if (activated[i]) { - analogWrite(port[i], 0); + break; + + case EVENT_SOURCE_LIGHT: + for (byte i = 0; i < last; i++) { + if (type[i] == PWM_TYPE_LAMP && number[i] == (byte)event->eventId) { + if (event->value) { + analogWrite(port[i], power[i]); + } else if (activated[i]) { + analogWrite(port[i], 0); + } } } - } - break; + break; + } + } else if (powerToggled) { + for (byte i = 0; i < last; i++) { + // Deactivate the output. + digitalWrite(port[i], 0); + // Mark the output as deactivated. + activated[i] = 0; + powerOn = false; + CrossLinkDebugger::debug("Deactivated PWM device on port %d", port[i]); + } } } \ No newline at end of file diff --git a/src/IODevices/PwmDevices.h b/src/IODevices/PwmDevices.h index f7d034a..ddf4ea7 100644 --- a/src/IODevices/PwmDevices.h +++ b/src/IODevices/PwmDevices.h @@ -9,20 +9,17 @@ #include -#include "../EventDispatcher/Event.h" -#include "../EventDispatcher/EventDispatcher.h" +#include "../HighPowerOffAware.h" #ifndef MAX_PWM_OUTPUTS #define MAX_PWM_OUTPUTS 16 #endif -class PwmDevices : public EventListener { +class PwmDevices : public HighPowerOffAware { public: // Constructor - PwmDevices(EventDispatcher *eventDispatcher) { + PwmDevices(EventDispatcher *eventDispatcher): HighPowerOffAware(eventDispatcher) { eventDispatcher->addListener(this, EVENT_SOURCE_LIGHT); - eventDispatcher->addListener(this, EVENT_SOURCE_SOLENOID); - eventDispatcher->addListener(this, EVENT_SOURCE_SWITCH); // Adjust PWM properties if needed. // analogWriteFreq(5000); @@ -40,8 +37,6 @@ class PwmDevices : public EventListener { void handleEvent(Event *event); - void handleEvent(ConfigEvent *event) {} - private: unsigned long _ms; From 90a807c0dbaf8ef3fd1815a91254ae323f3e788d Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Fri, 27 Sep 2024 11:44:58 +0200 Subject: [PATCH 045/102] fixed flashers and added support for custom LEDs --- ...CombinedGiAndLightMatrixWS2812FXDevice.cpp | 33 ++++-- .../CombinedGiAndLightMatrixWS2812FXDevice.h | 109 ++++++++++-------- src/EffectsController.cpp | 10 +- 3 files changed, 89 insertions(+), 63 deletions(-) diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp index 5830a50..11cbb22 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp @@ -81,15 +81,26 @@ void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE( } } +void CombinedGiAndLightMatrixWS2812FXDevice::assignCustomLed(uint8_t number, + int16_t led, + uint32_t color) { + // Custom LEDs have numbers >= 100. + // Attch them right behind the original matrix. + assignLedToLightMatrixDE(number - 100 + _LIGHT_MATRIX_SIZE, led, color); +} + void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToFlasher( uint8_t number, int16_t led, uint32_t color) { for (int offset = 0; offset < _MAX_FLASHERS; offset++) { if (flasherNumber[offset] == number) { // Flasher already registered, add another LED to it. for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { - if (ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + offset][i] == -1) { - ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + offset][i] = led; - ledLightMatrixColors[_LIGHT_MATRIX_SIZE + offset][i] = color; + if (ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + + offset][i] == -1) { + ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + + offset][i] = led; + ledLightMatrixColors[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + offset] + [i] = color; return; } } @@ -98,12 +109,12 @@ void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToFlasher( } // Flasher not yet registered, find a free slot. - for (int f = _MAX_LEDS_PER_LIGHT; f < _MAX_LEDS_PER_LIGHT + _MAX_FLASHERS; - f++) { + for (int f = _LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS; + f < (_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + _MAX_FLASHERS); f++) { if (ledLightMatrixPositions[f][0] == -1) { ledLightMatrixPositions[f][0] = led; ledLightMatrixColors[f][0] = color; - flasherNumber[_MAX_LEDS_PER_LIGHT - f] = number; + flasherNumber[f - (_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS)] = number; return; } } @@ -210,16 +221,15 @@ void CombinedGiAndLightMatrixWS2812FXDevice::handleEvent(Event *event) { // We start at "0", not "1". --number; } else { - number = 255; for (int offset = 0; offset < _MAX_FLASHERS; offset++) { if (flasherNumber[offset] == number) { - number = _LIGHT_MATRIX_SIZE + offset; + number = _LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + offset; break; } } - if (number == 255) { - // The solenoid isn't a registered falsher. + if (number < (_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS)) { + // The solenoid isn't a registered flasher. return; } } @@ -325,7 +335,8 @@ void CombinedGiAndLightMatrixWS2812FXDevice::updateAfterGlow() { } } - for (uint8_t number = 0; number < _LIGHT_MATRIX_SIZE + _MAX_FLASHERS; + for (uint8_t number = 0; + number < _LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + _MAX_FLASHERS; number++) { uint8_t glowBrightness; if (heatUp[number] > 0) { diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h index 7305620..29b5ce6 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h @@ -1,48 +1,56 @@ /* CombinedGiAndLightMatrixWS2812FXDevice.h - Created by Markus Kalkbrenner, 2021 - 2023. + Created by Markus Kalkbrenner, 2021 - 2024. + + WPC matrix numbering: + + | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 + ---+----+----+----+----+----+----+----+---- + R1 | 11 | 21 | 31 | 41 | 51 | 61 | 71 | 81 + ---+----+----+----+----+----+----+----+---- + R2 | 12 | 22 | 32 | 42 | 52 | 62 | 72 | 82 + ---+----+----+----+----+----+----+----+---- + R3 | 13 | 23 | 33 | 43 | 53 | 63 | 73 | 83 + ---+----+----+----+----+----+----+----+---- + R4 | 14 | 24 | 34 | 44 | 54 | 64 | 74 | 84 + ---+----+----+----+----+----+----+----+---- + R5 | 15 | 25 | 35 | 45 | 55 | 65 | 75 | 85 + ---+----+----+----+----+----+----+----+---- + R6 | 16 | 26 | 36 | 46 | 56 | 66 | 76 | 86 + ---+----+----+----+----+----+----+----+---- + R7 | 17 | 27 | 37 | 47 | 57 | 67 | 77 | 87 + ---+----+----+----+----+----+----+----+---- + R8 | 18 | 28 | 38 | 48 | 58 | 68 | 78 | 88 + + DE and SYS4-SYS11 matrix numbering: + + | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 + ---+----+----+----+----+----+----+----+---- + R1 | 1 | 9 | 17 | 25 | 33 | 41 | 49 | 57 + ---+----+----+----+----+----+----+----+---- + R2 | 2 | 10 | 18 | 26 | 34 | 42 | 50 | 58 + ---+----+----+----+----+----+----+----+---- + R3 | 3 | 11 | 19 | 27 | 35 | 43 | 51 | 59 + ---+----+----+----+----+----+----+----+---- + R4 | 4 | 12 | 20 | 28 | 36 | 44 | 52 | 60 + ---+----+----+----+----+----+----+----+---- + R5 | 5 | 13 | 21 | 29 | 37 | 45 | 53 | 61 + ---+----+----+----+----+----+----+----+---- + R6 | 6 | 14 | 22 | 30 | 38 | 46 | 54 | 62 + ---+----+----+----+----+----+----+----+---- + R7 | 7 | 15 | 23 | 31 | 39 | 47 | 55 | 63 + ---+----+----+----+----+----+----+----+---- + R8 | 8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 + + In order to ease the AfterGlow handling and to avoid long iterations across + arrays and to reduce the numer of addressable LED strings, we extend the + original Lamp Matrix. + The internal numbering of any matrix is 0 to 63. Starting at position 64 we + add custom LEDs which are added to the playfield and which are not part of the + original matrix. The amount of custom LEDs is limited by _MAX_CUSTOM_LEDS. + Flashers are added to the matrix at position (63 + _MAX_CUSTOM_LEDS). */ -// WPC matrix numbering: -// -// | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 -// ---+----+----+----+----+----+----+----+---- -// R1 | 11 | 21 | 31 | 41 | 51 | 61 | 71 | 81 -// ---+----+----+----+----+----+----+----+---- -// R2 | 12 | 22 | 32 | 42 | 52 | 62 | 72 | 82 -// ---+----+----+----+----+----+----+----+---- -// R3 | 13 | 23 | 33 | 43 | 53 | 63 | 73 | 83 -// ---+----+----+----+----+----+----+----+---- -// R4 | 14 | 24 | 34 | 44 | 54 | 64 | 74 | 84 -// ---+----+----+----+----+----+----+----+---- -// R5 | 15 | 25 | 35 | 45 | 55 | 65 | 75 | 85 -// ---+----+----+----+----+----+----+----+---- -// R6 | 16 | 26 | 36 | 46 | 56 | 66 | 76 | 86 -// ---+----+----+----+----+----+----+----+---- -// R7 | 17 | 27 | 37 | 47 | 57 | 67 | 77 | 87 -// ---+----+----+----+----+----+----+----+---- -// R8 | 18 | 28 | 38 | 48 | 58 | 68 | 78 | 88 - -// DE and SYS11 matrix numbering: -// -// | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 -// ---+----+----+----+----+----+----+----+---- -// R1 | 1 | 9 | 17 | 25 | 33 | 41 | 49 | 57 -// ---+----+----+----+----+----+----+----+---- -// R2 | 2 | 10 | 18 | 26 | 34 | 42 | 50 | 58 -// ---+----+----+----+----+----+----+----+---- -// R3 | 3 | 11 | 19 | 27 | 35 | 43 | 51 | 59 -// ---+----+----+----+----+----+----+----+---- -// R4 | 4 | 12 | 20 | 28 | 36 | 44 | 52 | 60 -// ---+----+----+----+----+----+----+----+---- -// R5 | 5 | 13 | 21 | 29 | 37 | 45 | 53 | 61 -// ---+----+----+----+----+----+----+----+---- -// R6 | 6 | 14 | 22 | 30 | 38 | 46 | 54 | 62 -// ---+----+----+----+----+----+----+----+---- -// R7 | 7 | 15 | 23 | 31 | 39 | 47 | 55 | 63 -// ---+----+----+----+----+----+----+----+---- -// R8 | 8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 - #ifndef CombinedGiAndLightMatrixWS2812FXDevice_h #define CombinedGiAndLightMatrixWS2812FXDevice_h @@ -58,6 +66,7 @@ #define _MAX_LEDS_GI_STRING 50 #define _LIGHT_MATRIX_SIZE 64 #define _MAX_LEDS_PER_LIGHT 3 +#define _MAX_CUSTOM_LEDS 12 #define _MAX_FLASHERS 12 class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, @@ -76,7 +85,8 @@ class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, ledGIPositions[number][i] = -1; } } - for (int number = 0; number < _LIGHT_MATRIX_SIZE + _MAX_FLASHERS; + for (int number = 0; + number < (_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + _MAX_FLASHERS); number++) { for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { ledLightMatrixPositions[number][i] = -1; @@ -109,6 +119,8 @@ class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, void assignLedToLightMatrixSYS11(uint8_t number, int16_t led); void assignLedToLightMatrixSYS11(uint8_t number, int16_t led, uint32_t color); + void assignCustomLed(uint8_t number, int16_t led, uint32_t color); + void assignLedToFlasher(uint8_t number, int16_t led, uint32_t color); void setDimmedPixelColor(int16_t led, uint32_t color, uint8_t brightness); @@ -133,10 +145,10 @@ class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, // Internally we store the positions in Data East numbering from 1 to 64. // The WPC-specific functions convert the WPC-specific numbering. - int16_t ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS] - [_MAX_LEDS_PER_LIGHT] = {{0}}; - uint32_t ledLightMatrixColors[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS] - [_MAX_LEDS_PER_LIGHT] = {{0}}; + int16_t ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + + _MAX_FLASHERS][_MAX_LEDS_PER_LIGHT] = {{0}}; + uint32_t ledLightMatrixColors[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + + _MAX_FLASHERS][_MAX_LEDS_PER_LIGHT] = {{0}}; uint8_t flasherNumber[_MAX_FLASHERS] = {0}; @@ -152,8 +164,9 @@ class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, int16_t msAfterGlow = 0; uint32_t heatUpGI[NUM_GI_STRINGS] = {0}; uint32_t afterGlowGI[NUM_GI_STRINGS] = {0}; - uint32_t heatUp[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS] = {0}; - uint32_t afterGlow[_LIGHT_MATRIX_SIZE + _MAX_FLASHERS] = {0}; + uint32_t heatUp[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + _MAX_FLASHERS] = {0}; + uint32_t afterGlow[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + _MAX_FLASHERS] = { + 0}; }; #endif diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 0760a02..0b416ad 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -43,9 +43,6 @@ EffectsController::createCombinedGiAndLightMatrixWs2812FXDevice(int port) { ws2812FXDevices[port][0] = giAndLightMatrix; delete ws2812FXDevice; - _eventDispatcher->addListener(giAndLightMatrix, EVENT_SOURCE_GI); - _eventDispatcher->addListener(giAndLightMatrix, EVENT_SOURCE_LIGHT); - return giAndLightMatrix; } @@ -232,7 +229,12 @@ void EffectsController::handleEvent(ConfigEvent *event) { config_color); break; case LED_TYPE_LAMP: - if (platform == PLATFORM_WPC) { + if (config_number >= 100) { + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignCustomLed(config_number, config_ledNumber, + config_color); + } else if (platform == PLATFORM_WPC) { ((CombinedGiAndLightMatrixWS2812FXDevice *) ws2812FXDevices[0][0]) ->assignLedToLightMatrixWPC( From 2ea85e657aec2a0a264ac5f7ac4445c08354184f Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Fri, 27 Sep 2024 17:23:43 +0200 Subject: [PATCH 046/102] avoid name collision "stateful" --- src/IOBoardController.cpp | 1 + src/IODevices/Switches.cpp | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index b29ba8b..c8a1ad0 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -92,6 +92,7 @@ void IOBoardController::handleEvent(ConfigEvent *event) { port = event->value; break; case CONFIG_TOPIC_NUMBER: + // Ports 15-18 (labeled as 13-16) of IO_16_8_1 are stateful. _switches->registerSwitch((byte)port, event->value, (controllerType == CONTROLLER_16_8_1 && port >= 15 && port <= 18)); diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index 8c78aa2..fec4171 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -1,8 +1,8 @@ #include "Switches.h" -void Switches::registerSwitch(byte p, byte n, bool stateful) { +void Switches::registerSwitch(byte p, byte n, bool s) { if (last < (MAX_SWITCHES - 1)) { - if (stateful) { + if (s) { resetStatefulPort(p); } @@ -11,6 +11,7 @@ void Switches::registerSwitch(byte p, byte n, bool stateful) { port[++last] = p; number[last] = n; toggled[last] = false; + stateful[last] = s; // Set the inverted value as initial state to let update() send the initial state on game start. // Note, we have active LOW! state[last] = digitalRead(p); From 70eb06e42c6ae4a4d113322e716e0c8068e9f492 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 28 Sep 2024 11:54:57 +0200 Subject: [PATCH 047/102] fixed stateful switches --- src/IODevices/Switches.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index fec4171..f7e15f2 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -22,19 +22,19 @@ void Switches::resetStatefulPort(byte p) { // Set mid power output as input. pinMode(p, OUTPUT); digitalWrite(p, HIGH); - delayMicroseconds(10); - digitalWrite(p, LOW); - delayMicroseconds(10); pinMode(p, INPUT); } void Switches::reset() { + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { + if (stateful[i]) resetStatefulPort(port[i]); + } + for (uint8_t i = 0; i < MAX_SWITCHES; i++) { port[i] = 0; number[i] = 0; state[i] = 0; toggled[i] = false; - if (stateful[i]) resetStatefulPort(i); stateful[i] = false; } @@ -59,7 +59,6 @@ void Switches::update() { // flippers, kick backs, jets and sling shots. _eventDispatcher->dispatch(new Event( EVENT_SOURCE_SWITCH, word(0, number[i]), state[i], true)); - if (stateful[i]) resetStatefulPort(i); } } } @@ -75,6 +74,7 @@ void Switches::handleEvent(Event *event) { _ms = millis(); for (int i = 0; i <= last; i++) { toggled[i] = false; + if (stateful[i]) resetStatefulPort(port[i]); } } break; @@ -89,6 +89,7 @@ void Switches::handleEvent(Event *event) { new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), state[i])); } else { toggled[i] = false; + if (stateful[i]) resetStatefulPort(port[i]); } } _ms = millis(); From ac2810dae15a280bf6d05583e0b7d1e308aea1cf Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 29 Sep 2024 18:00:42 +0200 Subject: [PATCH 048/102] fixed intial switch states --- src/IODevices/Switches.cpp | 8 ++++---- src/IODevices/Switches.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index f7e15f2..fc38531 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -7,14 +7,13 @@ void Switches::registerSwitch(byte p, byte n, bool s) { } pinMode(p, INPUT); - delayMicroseconds(10); port[++last] = p; number[last] = n; toggled[last] = false; stateful[last] = s; - // Set the inverted value as initial state to let update() send the initial state on game start. + delayMicroseconds(10); // Note, we have active LOW! - state[last] = digitalRead(p); + state[last] = !digitalRead(p); } } @@ -68,7 +67,7 @@ void Switches::update() { void Switches::handleEvent(Event *event) { switch (event->sourceId) { case EVENT_POLL_EVENTS: - if (boardId == (byte)event->value) { + if (running && boardId == (byte)event->value) { // This I/O board has been polled for events, so all current switch // states are transmitted. Reset switch debounce timer and toggles. _ms = millis(); @@ -93,6 +92,7 @@ void Switches::handleEvent(Event *event) { } } _ms = millis(); + running = true; break; } } diff --git a/src/IODevices/Switches.h b/src/IODevices/Switches.h index 6d4262b..8f895cb 100644 --- a/src/IODevices/Switches.h +++ b/src/IODevices/Switches.h @@ -45,6 +45,7 @@ class Switches : public EventListener { byte boardId; unsigned long _ms; + bool running = false; byte port[MAX_SWITCHES] = {0}; byte number[MAX_SWITCHES] = {0}; From 0edfe3d9f70270ea8fb15bb9e0bbf36a36a19a3b Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 7 Oct 2024 13:24:24 +0200 Subject: [PATCH 049/102] fixed PWM hold power, added watchdog to turn off coils --- src/IOBoardController.cpp | 8 +++++++ src/IODevices/PwmDevices.cpp | 40 ++++++++++++++++++++++++----------- src/IODevices/PwmDevices.h | 15 ++++++------- src/IODevices/Switches.h | 2 +- test/IO_16_8_1/platformio.ini | 1 + test/IO_16_8_1/src/main.cpp | 28 +++++++++++++++++++++++- 6 files changed, 72 insertions(+), 22 deletions(-) diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index c8a1ad0..e88d78c 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -25,6 +25,10 @@ IOBoardController::IOBoardController(int cT) { _pwmDevices = new PwmDevices(_eventDispatcher); _switches = new Switches(boardId, _eventDispatcher); _switchMatrix = new SwitchMatrix(boardId, _eventDispatcher); + + // Adjust PWM properties if needed. + analogWriteFreq(500); + analogWriteResolution(8); } } @@ -39,6 +43,10 @@ void IOBoardController::update() { if (activePwmDevices) { pwmDevices()->update(); } + } else { + if (activePwmDevices) { + pwmDevices()->off(); + } } if (resetTimer > 0 && resetTimer < millis()) { diff --git a/src/IODevices/PwmDevices.cpp b/src/IODevices/PwmDevices.cpp index fce5d6f..e126755 100644 --- a/src/IODevices/PwmDevices.cpp +++ b/src/IODevices/PwmDevices.cpp @@ -16,7 +16,7 @@ void PwmDevices::registerSolenoid(byte p, byte n, byte pow, uint16_t minPT, fastSwitch[last] = fS; pinMode(p, OUTPUT); - digitalWrite(p, 0); + analogWrite(p, 0); type[last++] = PWM_TYPE_SOLENOID; } } @@ -45,12 +45,20 @@ void PwmDevices::registerLamp(byte p, byte n, byte pow) { } } +void PwmDevices::off() { + for (uint8_t i = 0; i < last; i++) { + // Turn off PWM output. + analogWrite(port[i], 0); + activated[i] = 0; + currentPower[i] = 0; + scheduled[i] = 0; + } +} + void PwmDevices::reset() { + off(); + for (uint8_t i = 0; i < MAX_PWM_OUTPUTS; i++) { - if (i < last) { - // Turn off PWM output. - digitalWrite(port[i], 0); - } port[i] = 0; number[i] = 0; power[i] = 0; @@ -61,6 +69,7 @@ void PwmDevices::reset() { fastSwitch[i] = 0; type[i] = 0; activated[i] = 0; + currentPower[i] = 0; scheduled[i] = 0; } @@ -74,28 +83,31 @@ void PwmDevices::update() { for (byte i = 0; i < last; i++) { if (activated[i] > 0) { // The output is active. - uint16_t timePassed = _ms - activated[i]; + uint32_t timePassed = _ms - activated[i]; if ((scheduled[i] && (minPulseTime[i] > 0) && (timePassed > minPulseTime[i])) || ((maxPulseTime[i] > 0) && (timePassed > maxPulseTime[i]))) { // Deactivate the output if it is scheduled for delayed deactivation and // the minimum pulse time is reached. Deactivate the output if the // maximum pulse time is reached. - digitalWrite(port[i], 0); + analogWrite(port[i], 0); activated[i] = 0; + holdPower[i] = 0; scheduled[i] = false; CrossLinkDebugger::debug( "Performed scheduled deactivation of PWM device on port %d after " "%dms", port[i], timePassed); } else if ((holdPowerActivationTime[i] > 0) && + (currentPower[i] > holdPower[i]) && (timePassed > holdPowerActivationTime[i])) { // Reduce the power of the activated output if the hold power activation // time pased since the activation. analogWrite(port[i], holdPower[i]); + currentPower[i] = holdPower[i]; CrossLinkDebugger::debug( - "Reduced power of PWM device on port %d after %dms", port[i], - timePassed); + "Reduced power of PWM device on port %d to power %d after %dms", + port[i], holdPower[i], timePassed); } } } @@ -110,7 +122,9 @@ void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) { analogWrite(port[i], power[i]); // Rememebr when it got activated. activated[i] = _ms; - CrossLinkDebugger::debug("Activated PWM device on port %d", port[i]); + currentPower[i] = power[i]; + CrossLinkDebugger::debug("Activated PWM device on port %d with power %d", + port[i], power[i]); } else if (!targetState && activated[i] > 0) { // Event received to deactivate the output. // Check if a minimum pulse time is configured for this output. @@ -121,9 +135,10 @@ void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) { scheduled[i] = true; } else { // Deactivate the output. - digitalWrite(port[i], 0); + analogWrite(port[i], 0); // Mark the output as deactivated. activated[i] = 0; + currentPower[i] = 0; CrossLinkDebugger::debug("Deactivated PWM device on port %d", port[i]); } } @@ -171,9 +186,10 @@ void PwmDevices::handleEvent(Event *event) { } else if (powerToggled) { for (byte i = 0; i < last; i++) { // Deactivate the output. - digitalWrite(port[i], 0); + analogWrite(port[i], 0); // Mark the output as deactivated. activated[i] = 0; + currentPower[i] = 0; powerOn = false; CrossLinkDebugger::debug("Deactivated PWM device on port %d", port[i]); } diff --git a/src/IODevices/PwmDevices.h b/src/IODevices/PwmDevices.h index ddf4ea7..bf8c437 100644 --- a/src/IODevices/PwmDevices.h +++ b/src/IODevices/PwmDevices.h @@ -18,13 +18,10 @@ class PwmDevices : public HighPowerOffAware { public: // Constructor - PwmDevices(EventDispatcher *eventDispatcher): HighPowerOffAware(eventDispatcher) { + PwmDevices(EventDispatcher *eventDispatcher) + : HighPowerOffAware(eventDispatcher) { eventDispatcher->addListener(this, EVENT_SOURCE_LIGHT); - - // Adjust PWM properties if needed. - // analogWriteFreq(5000); - // analogWriteRange(65535); - // analogWriteResolution(16); + // Listening to solenoids and switches is added in HighPowerOffAware(). } void registerSolenoid(byte p, byte n, byte pow, uint16_t minPT, @@ -33,12 +30,13 @@ class PwmDevices : public HighPowerOffAware { void registerLamp(byte p, byte n, byte pow); void update(); + void off(); void reset(); void handleEvent(Event *event); private: - unsigned long _ms; + uint32_t _ms; byte port[MAX_PWM_OUTPUTS] = {0}; byte number[MAX_PWM_OUTPUTS] = {0}; @@ -49,7 +47,8 @@ class PwmDevices : public HighPowerOffAware { uint16_t holdPowerActivationTime[MAX_PWM_OUTPUTS] = {0}; byte fastSwitch[MAX_PWM_OUTPUTS] = {0}; byte type[MAX_PWM_OUTPUTS] = {0}; - unsigned long activated[MAX_PWM_OUTPUTS] = {0}; + uint32_t activated[MAX_PWM_OUTPUTS] = {0}; + byte currentPower[MAX_PWM_OUTPUTS] = {0}; bool scheduled[MAX_PWM_OUTPUTS] = {0}; byte last = 0; diff --git a/src/IODevices/Switches.h b/src/IODevices/Switches.h index 8f895cb..213ae2c 100644 --- a/src/IODevices/Switches.h +++ b/src/IODevices/Switches.h @@ -18,7 +18,7 @@ #endif #ifndef SWITCH_DEBOUNCE -#define SWITCH_DEBOUNCE 5 +#define SWITCH_DEBOUNCE 2 #endif class Switches : public EventListener { diff --git a/test/IO_16_8_1/platformio.ini b/test/IO_16_8_1/platformio.ini index 647bd04..39fc660 100644 --- a/test/IO_16_8_1/platformio.ini +++ b/test/IO_16_8_1/platformio.ini @@ -16,3 +16,4 @@ lib_deps = mkalkbrenner/WavePWM kitesurfer1404/WS2812FX Bounce2 + RPI_PICO_TimerInterrupt diff --git a/test/IO_16_8_1/src/main.cpp b/test/IO_16_8_1/src/main.cpp index adfcc1e..2488e7e 100644 --- a/test/IO_16_8_1/src/main.cpp +++ b/test/IO_16_8_1/src/main.cpp @@ -5,11 +5,27 @@ #include "EffectsController.h" #include "EventDispatcher/CrossLinkDebugger.h" #include "IOBoardController.h" +#include "RPi_Pico_TimerInterrupt.h" IOBoardController ioBoardController(CONTROLLER_16_8_1); + // Platform will be adjusted by ConfigEvent. EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_LIBPINMAME); +RPI_PICO_Timer ITimer(1); + +volatile uint32_t watchdog_ms = millis(); + +// Turn off all High Power Outputs in case the main loop has not finished in 1 +// second (or 2 seconds in edge cases). +bool watchdog(struct repeating_timer *t) { + if ((millis() - watchdog_ms) > 1000) { + for (int i = 19; i <= 26; i++) digitalWrite(i, LOW); + } + + return true; +} + bool usb_debugging = false; bool core_0_initilized = false; @@ -51,6 +67,13 @@ void setup() { // https://community.platformio.org/t/serial-monitor-not-working/1512/25 while (!Serial1) { } + + // The watchdog interferes with the USB debuging. + if (!usb_debugging) { + if (!ITimer.attachInterruptInterval(1000000, watchdog)) { + // @todo + } + } } void setup1() { @@ -68,6 +91,9 @@ void setup1() { effectsController.start(); } -void loop() { ioBoardController.update(); } +void loop() { + watchdog_ms = millis(); + ioBoardController.update(); +} void loop1() { effectsController.update(); } From 936e509befa85ee475fec48a283574a396028df0 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 9 Oct 2024 21:20:18 +0200 Subject: [PATCH 050/102] added watchdog to turn off coils if communication is lost --- src/EventDispatcher/Event.h | 3 +++ src/EventDispatcher/EventDispatcher.cpp | 15 +++++++++++++-- src/EventDispatcher/EventDispatcher.h | 4 ++++ test/IO_16_8_1/src/main.cpp | 5 ++++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 77cc52d..da206e5 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -8,6 +8,9 @@ #include +// microseconds +#define RS485_MODE_SWITCH_DELAY 50 + #define EVENT_SOURCE_ANY 42 // "*" #define EVENT_SOURCE_DEBUG 66 // "B" Debug #define EVENT_CONFIGURATION 67 // "C" Configure I/O diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index a8363a5..69fcd6f 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -230,7 +230,7 @@ void EventDispatcher::update() { if (rs485) { digitalWrite(rs485Pin, HIGH); // Write. // Wait until the RS485 converter switched to write mode. - delayMicroseconds(500); + delayMicroseconds(RS485_MODE_SWITCH_DELAY); } for (int k = 0; k <= stackCounter; k++) { @@ -248,15 +248,20 @@ void EventDispatcher::update() { callListeners(new Event(EVENT_NULL, 1, board), MAX_CROSS_LINKS, true); + lastPoll = millis(); + if (rs485) { // Flush the serial buffer and wait until done. hwSerial[i]->flush(); digitalWrite(rs485Pin, LOW); // Read. // Wait until the RS485 converter switched back to read // mode. - delayMicroseconds(200); + delayMicroseconds(RS485_MODE_SWITCH_DELAY); } + } else if (sourceId == EVENT_RUN) { + running = true; } + } else { #if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) if (Serial) { @@ -349,3 +354,9 @@ void EventDispatcher::update() { } #endif } + +uint32_t EventDispatcher::getLastPoll() { + if (running) return lastPoll; + + return millis(); +} diff --git a/src/EventDispatcher/EventDispatcher.h b/src/EventDispatcher/EventDispatcher.h index 2eff10b..9f58da5 100644 --- a/src/EventDispatcher/EventDispatcher.h +++ b/src/EventDispatcher/EventDispatcher.h @@ -50,6 +50,8 @@ class EventDispatcher { void update(); + uint32_t getLastPoll(); + private: void callListeners(Event* event, int sender, bool flush); @@ -68,6 +70,8 @@ class EventDispatcher { int rs485Pin = 0; byte board = 255; bool error = false; + uint32_t lastPoll; + bool running = false; bool multiCore = false; int crossLink = -1; diff --git a/test/IO_16_8_1/src/main.cpp b/test/IO_16_8_1/src/main.cpp index 2488e7e..433eca5 100644 --- a/test/IO_16_8_1/src/main.cpp +++ b/test/IO_16_8_1/src/main.cpp @@ -15,11 +15,13 @@ EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_LIBPINMAME); RPI_PICO_Timer ITimer(1); volatile uint32_t watchdog_ms = millis(); +volatile uint32_t lastPoll_ms = millis(); // Turn off all High Power Outputs in case the main loop has not finished in 1 // second (or 2 seconds in edge cases). bool watchdog(struct repeating_timer *t) { - if ((millis() - watchdog_ms) > 1000) { + uint32_t ms = millis(); + if ((ms - watchdog_ms) > 1000 || (ms - lastPoll_ms) > 3000) { for (int i = 19; i <= 26; i++) digitalWrite(i, LOW); } @@ -94,6 +96,7 @@ void setup1() { void loop() { watchdog_ms = millis(); ioBoardController.update(); + lastPoll_ms = ioBoardController.eventDispatcher()->getLastPoll(); } void loop1() { effectsController.update(); } From f1a06654721f62f080441732d4c82d0a0c821582 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 9 Oct 2024 22:26:21 +0200 Subject: [PATCH 051/102] support brightness --- src/EffectDevices/WS2812FXDevice.h | 2 +- src/EffectsController.cpp | 6 +++++- src/EffectsController.h | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/EffectDevices/WS2812FXDevice.h b/src/EffectDevices/WS2812FXDevice.h index caad481..ca4698d 100644 --- a/src/EffectDevices/WS2812FXDevice.h +++ b/src/EffectDevices/WS2812FXDevice.h @@ -72,7 +72,7 @@ class WS2812FXDevice : public EffectDevice { int firstSegment; int lastSegment; - byte brightness = 64; + byte brightness = 50; bool stopped = true; bool afterGlowSupport = false; diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 0b416ad..848c96e 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -158,10 +158,14 @@ void EffectsController::handleEvent(ConfigEvent *event) { config_neoPixelType = 0; config_amount = 0; config_afterGlow = 0; + config_brightness = 50; break; case CONFIG_TOPIC_TYPE: config_neoPixelType = (neoPixelType)event->value; break; + case CONFIG_TOPIC_BRIGHTNESS: + config_brightness = event->value; + break; case CONFIG_TOPIC_AMOUNT_LEDS: config_amount = event->value; break; @@ -180,7 +184,7 @@ void EffectsController::handleEvent(ConfigEvent *event) { ws2812FXDeviceCounters[0] = 1; // Brightness might be overwritten later. - // ws2812FXDevices[0][0]->setBrightness(WS2812FX_BRIGHTNESS); + ws2812FXDevices[0][0]->setBrightness(config_brightness); // "off" means no effects, standard operation mode. ws2812FXDevices[0][0]->off(); if (config_heatUp > 0) { diff --git a/src/EffectsController.h b/src/EffectsController.h index 392f694..e4e80a3 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -417,6 +417,7 @@ class EffectsController : public EventListener { byte boardId = 255; byte config_port = 0; byte config_type = 0; + byte config_brightness = 50; neoPixelType config_neoPixelType = 0; byte config_amount = 0; byte config_afterGlow = 0; From a8cf01b9d686392dc1b952d9359960f7c13d571d Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 15 Mar 2025 19:24:30 +0100 Subject: [PATCH 052/102] added PWM and LED effect support for IO Boards --- src/EffectDevices/WavePWMDevice.cpp | 2 +- src/EffectDevices/WavePWMDevice.h | 10 + src/Effects/WS2812FXEffect.cpp | 16 +- src/Effects/WS2812FXEffect.h | 23 ++ src/EffectsController.cpp | 333 +++++++++++++++++++++++----- src/EffectsController.h | 12 +- src/EventDispatcher/Event.h | 48 ++-- src/IOBoardController.cpp | 6 + 8 files changed, 364 insertions(+), 86 deletions(-) diff --git a/src/EffectDevices/WavePWMDevice.cpp b/src/EffectDevices/WavePWMDevice.cpp index eee23df..baead2d 100644 --- a/src/EffectDevices/WavePWMDevice.cpp +++ b/src/EffectDevices/WavePWMDevice.cpp @@ -8,7 +8,7 @@ void WavePWMDevice::reset() { setPWM(0); } void WavePWMDevice::setPWM(uint8_t pwm) { if (powerOn && coinDoorClosed) { - analogWrite(pin, pwm); + analogWrite(pin, (int)(pwm * pwmLimitFactor)); } currentPWM = pwm; } diff --git a/src/EffectDevices/WavePWMDevice.h b/src/EffectDevices/WavePWMDevice.h index 44133a1..dcf6a35 100644 --- a/src/EffectDevices/WavePWMDevice.h +++ b/src/EffectDevices/WavePWMDevice.h @@ -29,6 +29,15 @@ class WavePWMDevice : public EffectDevice, public HighPowerOffAware { pinMode(pin, OUTPUT); } + WavePWMDevice(int pin, uint8_t maxPWM, EventDispatcher* eventDispatcher) + : HighPowerOffAware(eventDispatcher) { + this->wavePWM = new WavePWM(); + this->pin = pin; + // A hard limit, for example to run a 12V motor at 48V, maxPWM has to be 63. + this->pwmLimitFactor = maxPWM / 255; + pinMode(pin, OUTPUT); + } + void on(); void reset(); @@ -46,6 +55,7 @@ class WavePWMDevice : public EffectDevice, public HighPowerOffAware { int pin; uint8_t currentPWM = 0; + float pwmLimitFactor = 1.0; }; #endif diff --git a/src/Effects/WS2812FXEffect.cpp b/src/Effects/WS2812FXEffect.cpp index 895c909..4b49096 100644 --- a/src/Effects/WS2812FXEffect.cpp +++ b/src/Effects/WS2812FXEffect.cpp @@ -8,9 +8,19 @@ void WS2812FXEffect::setDevice(EffectDevice *effectDevice) { void WS2812FXEffect::start(int r) { Effect::start(); device->on(); - ws2812FX->setSegment(getFirstSegment(), getFirstLED(), getlastLED(), mode, - colors, speed, options); - ws2812FX->resetSegmentRuntime(getFirstSegment()); + if (segment == 255) { + ws2812FX->setSegment(getFirstSegment(), getFirstLED(), getlastLED(), mode, + colors, speed, options); + ws2812FX->resetSegmentRuntime(getFirstSegment()); + } else { + ws2812FX->getSegment(segment)->mode = mode; + ws2812FX->getSegment(segment)->colors[0] = colors[0]; + ws2812FX->getSegment(segment)->colors[1] = colors[1]; + ws2812FX->getSegment(segment)->colors[2] = colors[2]; + ws2812FX->getSegment(segment)->speed = speed; + ws2812FX->getSegment(segment)->options = options; + ws2812FX->resetSegmentRuntime(segment); + } } void WS2812FXEffect::stop() { diff --git a/src/Effects/WS2812FXEffect.h b/src/Effects/WS2812FXEffect.h index 04f9a0d..4cd7f18 100644 --- a/src/Effects/WS2812FXEffect.h +++ b/src/Effects/WS2812FXEffect.h @@ -37,6 +37,28 @@ class WS2812FXEffect : public Effect { this->duration = duration; } + WS2812FXEffect(uint8_t segment, uint8_t mode, uint32_t color, uint16_t speed, + uint8_t options, int duration = 0) { + this->segment = segment; + this->mode = mode; + this->colors[0] = color; + this->speed = speed; + this->options = options; + this->duration = duration; + } + + WS2812FXEffect(uint8_t segment, uint8_t mode, const uint32_t colors[], + uint16_t speed, uint8_t options, int duration = 0) { + this->segment = segment; + this->mode = mode; + this->colors[0] = colors[0]; + this->colors[1] = colors[1]; + this->colors[2] = colors[2]; + this->speed = speed; + this->options = options; + this->duration = duration; + } + virtual void setDevice(EffectDevice* effectDevice); virtual void start(int repeat = 0); @@ -55,6 +77,7 @@ class WS2812FXEffect : public Effect { protected: WS2812FX* ws2812FX; + uint8_t segment = 255; uint8_t mode; uint32_t colors[3] = {0, 0, 0}; uint16_t speed; diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 848c96e..14c47e1 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -154,112 +154,323 @@ void EffectsController::handleEvent(ConfigEvent *event) { case CONFIG_TOPIC_LED_STRING: switch (event->key) { case CONFIG_TOPIC_PORT: - config_port = event->value; + config_values[0] = event->value; // port config_neoPixelType = 0; - config_amount = 0; - config_afterGlow = 0; - config_brightness = 50; + config_values[1] = 0; // amount of leds + config_values[2] = 0; // after glow + config_values[3] = 50; // brightness + config_values[4] = 0; // heat up break; case CONFIG_TOPIC_TYPE: config_neoPixelType = (neoPixelType)event->value; break; case CONFIG_TOPIC_BRIGHTNESS: - config_brightness = event->value; + config_values[3] = event->value; break; case CONFIG_TOPIC_AMOUNT_LEDS: - config_amount = event->value; + config_values[1] = event->value; break; case CONFIG_TOPIC_AFTER_GLOW: - config_afterGlow = event->value; + config_values[2] = event->value; break; case CONFIG_TOPIC_LIGHT_UP: - config_heatUp = event->value; + config_values[4] = event->value; if (!ws2812FXDevices[0][0]) { ws2812FXDevices[0][0] = new CombinedGiAndLightMatrixWS2812FXDevice( - new WS2812FX(config_amount, config_port, + new WS2812FX(config_values[1], config_values[0], config_neoPixelType), - 0, config_amount - 1, 0, 0, _eventDispatcher); + 0, config_values[1] - 1, 0, 0, _eventDispatcher); ws2812FXDevices[0][0]->getWS2812FX()->init(); ws2812FXDeviceCounters[0] = 1; // Brightness might be overwritten later. - ws2812FXDevices[0][0]->setBrightness(config_brightness); + ws2812FXDevices[0][0]->setBrightness(config_values[3]); // "off" means no effects, standard operation mode. ws2812FXDevices[0][0]->off(); - if (config_heatUp > 0) { + if (config_values[4] > 0) { ((CombinedGiAndLightMatrixWS2812FXDevice *) ws2812FXDevices[0][0]) - ->setHeatUp(config_heatUp); + ->setHeatUp(config_values[4]); } - if (config_afterGlow > 0) { + if (config_values[2] > 0) { ((CombinedGiAndLightMatrixWS2812FXDevice *) ws2812FXDevices[0][0]) - ->setAfterGlow(config_afterGlow); + ->setAfterGlow(config_values[2]); } ws2812FXstates[0] = true; } - break; } break; - case CONFIG_TOPIC_LAMPS: + case CONFIG_TOPIC_LED_SEGMENT: if (ws2812FXDevices[0][0]) { switch (event->key) { case CONFIG_TOPIC_PORT: - config_port = event->value; - config_type = 0; - config_number = 0; - config_ledNumber = 0; - config_color = 0; - break; - case CONFIG_TOPIC_TYPE: - config_type = event->value; + config_values[0] = event->value; // port + config_values[1] = 0; // number + config_values[2] = 0; // from + config_values[3] = 0; // to break; case CONFIG_TOPIC_NUMBER: - config_number = event->value; + config_values[1] = event->value; break; - case CONFIG_TOPIC_LED_NUMBER: - config_ledNumber = event->value; + case CONFIG_TOPIC_FROM: + config_values[2] = event->value; + break; + case CONFIG_TOPIC_TO: + config_values[3] = event->value; + + ws2812FXDevices[0][0]->getWS2812FX()->setSegment( + config_values[1], config_values[2], config_values[3]); + break; + } + } + break; + + case CONFIG_TOPIC_LED_EFFECT: + if (ws2812FXDevices[0][0]) { + switch (event->key) { + case CONFIG_TOPIC_PORT: + config_values[0] = event->value; // port + config_values[1] = 0; // segment + config_values[2] = 0; // duration + config_values[3] = 0; // effect + config_values[4] = 0; // reverse + config_values[5] = 0; // speed + config_values[6] = 0; // mode + config_values[7] = 0; // priority + config_values[8] = 0; // repeat + config_payload = 0; // color + ws1812Effect = nullptr; + break; + case CONFIG_TOPIC_LED_SEGMENT: + config_values[1] = event->value; break; case CONFIG_TOPIC_COLOR: - config_color = event->value; - switch (config_type) { - case LED_TYPE_GI: - ((CombinedGiAndLightMatrixWS2812FXDevice *) - ws2812FXDevices[0][0]) - ->assignLedToGiString(config_number, config_ledNumber, - config_color); + config_payload = event->value; + break; + case CONFIG_TOPIC_DURATION: + config_values[2] = event->value; + break; + case CONFIG_TOPIC_EFFECT: + config_values[3] = event->value; + break; + case CONFIG_TOPIC_REVERSE: + config_values[4] = event->value; + break; + case CONFIG_TOPIC_SPEED: + config_values[5] = event->value; + break; + case CONFIG_TOPIC_MODE: + config_values[6] = event->value; + break; + case CONFIG_TOPIC_PRIORITY: + config_values[7] = event->value; + break; + case CONFIG_TOPIC_REPEAT: + config_values[8] = event->value; + ws1812Effect = new WS2812FXEffect( + config_values[1], config_values[3], config_payload, + config_values[5], + config_values[4] == 1 ? REVERSE : NO_OPTIONS, + config_values[2]); + break; + } + } + break; + + case CONFIG_TOPIC_TRIGGER: + switch (event->key) { + case CONFIG_TOPIC_PORT: + config_values[0] = event->value; // port + config_values[1] = 0; // type + config_values[2] = 0; // source + config_values[3] = 0; // number + config_values[4] = 0; // value + break; + case CONFIG_TOPIC_TYPE: + config_values[1] = event->value; + break; + case CONFIG_TOPIC_SOURCE: + config_values[2] = event->value; // source + break; + case CONFIG_TOPIC_NUMBER: + config_values[3] = event->value; + break; + case CONFIG_TOPIC_VALUE: + config_values[4] = event->value; + switch (config_values[1]) { + case CONFIG_TOPIC_LED_EFFECT: + if (ws1812Effect) { + addEffect( + ws1812Effect, ws2812FXDevices[0][0], + new Event(config_values[0], config_values[1], + config_values[2]), + config_values[7], // priority + config_values[8] == 255 ? -1 + : config_values[8], // repeat + config_values[6] // mode + ); + } + break; + + case CONFIG_TOPIC_PWM_EFFECT: + if (pwmEffect) { + addEffect( + pwmEffect, _shakerPWMDevice, + new Event(config_values[0], config_values[1], + config_values[2]), + config_values[7], // priority + config_values[8] == 255 ? -1 + : config_values[8], // repeat + config_values[6] // mode + ); + } + break; + } + break; + + case CONFIG_TOPIC_LAMPS: + if (ws2812FXDevices[0][0]) { + switch (event->key) { + case CONFIG_TOPIC_PORT: + config_values[0] = event->value; // port + config_values[1] = 0; // type + config_values[2] = 0; // number + config_values[3] = 0; // led number + config_payload = 0; + break; + case CONFIG_TOPIC_TYPE: + config_values[1] = event->value; + break; + case CONFIG_TOPIC_NUMBER: + config_values[2] = event->value; + break; + case CONFIG_TOPIC_LED_NUMBER: + config_values[3] = event->value; break; - case LED_TYPE_LAMP: - if (config_number >= 100) { - ((CombinedGiAndLightMatrixWS2812FXDevice *) - ws2812FXDevices[0][0]) - ->assignCustomLed(config_number, config_ledNumber, - config_color); - } else if (platform == PLATFORM_WPC) { - ((CombinedGiAndLightMatrixWS2812FXDevice *) - ws2812FXDevices[0][0]) - ->assignLedToLightMatrixWPC( - config_number, config_ledNumber, config_color); - } else { - ((CombinedGiAndLightMatrixWS2812FXDevice *) - ws2812FXDevices[0][0]) - ->assignLedToLightMatrixDE( - config_number, config_ledNumber, config_color); + case CONFIG_TOPIC_COLOR: + config_payload = event->value; + switch (config_values[1]) { + case LED_TYPE_GI: + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignLedToGiString(config_values[2], + config_values[3], + config_payload); + break; + case LED_TYPE_LAMP: + if (config_values[2] >= 100) { + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignCustomLed(config_values[2], + config_values[3], config_payload); + } else if (platform == PLATFORM_WPC) { + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignLedToLightMatrixWPC(config_values[2], + config_values[3], + config_payload); + } else { + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignLedToLightMatrixDE(config_values[2], + config_values[3], + config_payload); + } + break; + case LED_TYPE_FLASHER: + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignLedToFlasher(config_values[2], + config_values[3], + config_payload); + break; } break; - case LED_TYPE_FLASHER: - ((CombinedGiAndLightMatrixWS2812FXDevice *) - ws2812FXDevices[0][0]) - ->assignLedToFlasher(config_number, config_ledNumber, - config_color); + } + } + break; + + case CONFIG_TOPIC_PWM: + switch (event->key) { + case CONFIG_TOPIC_PORT: + config_values[0] = event->value; // port + config_values[1] = 0; // power + case CONFIG_TOPIC_POWER: + config_values[1] = event->value; + break; + case CONFIG_TOPIC_TYPE: + switch (event->value) { + case PWM_TYPE_SHAKER: // Shaker + _shakerPWMDevice = new WavePWMDevice( + config_values[0], config_values[1], _eventDispatcher); + _shakerPWMDevice->off(); + break; + } + break; + } + break; + + case CONFIG_TOPIC_PWM_EFFECT: + if (_shakerPWMDevice) { + switch (event->key) { + case CONFIG_TOPIC_PORT: + config_values[0] = event->value; // port + config_values[1] = 0; // duration + config_values[2] = 0; // effect + config_values[3] = 0; // frequency + config_values[4] = 0; // max intensity + config_values[5] = 0; // min intensity + config_values[6] = 0; // mode + config_values[7] = 0; // priority + config_values[8] = 0; // repeat + config_payload = 0; // color + pwmEffect = nullptr; + break; + case CONFIG_TOPIC_DURATION: + config_values[1] = event->value; + break; + case CONFIG_TOPIC_EFFECT: + config_values[2] = event->value; + break; + case CONFIG_TOPIC_FREQUENCY: + config_values[3] = event->value; + break; + case CONFIG_TOPIC_MAX_INTENSITY: + config_values[4] = event->value; + break; + case CONFIG_TOPIC_MIN_INTENSITY: + config_values[5] = event->value; + break; + case CONFIG_TOPIC_MODE: + config_values[6] = event->value; + break; + case CONFIG_TOPIC_PRIORITY: + config_values[7] = event->value; + break; + case CONFIG_TOPIC_REPEAT: + config_values[8] = event->value; + switch (config_values[2]) { + case PWM_EFFECT_SINE: + pwmEffect = + new SinePWMEffect(config_values[3], config_values[1], + config_values[4], config_values[5]); + break; + case PWM_EFFECT_IMPULSE: + pwmEffect = new ImpulsePWMEffect(config_values[3], + config_values[4]); + break; + case PWM_EFFECT_RAMP_DOWN_STOP: + pwmEffect = new RampDownStopPWMEffect(config_values[3]); + break; + } break; } - break; - } - break; + } + break; } } } @@ -320,8 +531,8 @@ void EffectsController::update() { if (millis() - ws2812AfterGlowUpdateInterval > UPDATE_INTERVAL_WS2812FX_AFTERGLOW) { - // Updating the LEDs too fast leads to undefined behavior. Just update every - // 3ms. + // Updating the LEDs too fast leads to undefined behavior. Just update + // every 3ms. ws2812AfterGlowUpdateInterval = millis(); for (int i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) { if (ws2812FXstates[i] && ws2812FXDevices[i][0]->hasAfterGlowSupport() && diff --git a/src/EffectsController.h b/src/EffectsController.h index e4e80a3..b31320c 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -416,15 +416,11 @@ class EffectsController : public EventListener { byte controllerType; byte boardId = 255; byte config_port = 0; - byte config_type = 0; - byte config_brightness = 50; + byte config_values[9] = {0}; neoPixelType config_neoPixelType = 0; - byte config_amount = 0; - byte config_afterGlow = 0; - byte config_heatUp = 0; - byte config_number = 0; - byte config_ledNumber = 0; - uint32_t config_color = 0; + uint32_t config_payload = 0; + WS2812FXEffect* ws1812Effect; + WavePWMEffect* pwmEffect; unsigned long ws2812UpdateInterval = 0; unsigned long ws2812AfterGlowUpdateInterval = 0; diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index da206e5..56381b6 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -35,39 +35,57 @@ #define EVENT_NO_ERROR 98 // NO ERROR #define EVENT_ERROR 99 // ERROR -#define CONFIG_TOPIC_PLATFORM 102 // "f" -#define CONFIG_TOPIC_LED_STRING 103 // "g" -#define CONFIG_TOPIC_LAMPS 108 // "l" -#define CONFIG_TOPIC_MECHS 109 // "m" -#define CONFIG_TOPIC_PWM 112 // "p" -#define CONFIG_TOPIC_COIN_DOOR_CLOSED_SWITCH 113 // "q" -#define CONFIG_TOPIC_GAME_ON_SOLENOID 114 // "r" -#define CONFIG_TOPIC_SWITCHES 115 // "s" -#define CONFIG_TOPIC_SWITCH_MATRIX 120 // "x" +#define CONFIG_TOPIC_PLATFORM 102 // "f" +#define CONFIG_TOPIC_LED_STRING 103 // "g" +#define CONFIG_TOPIC_LED_SEGMENT 104 // "h" +#define CONFIG_TOPIC_LED_EFFECT 105 // "i" +#define CONFIG_TOPIC_PWM_EFFECT 106 // "j" +#define CONFIG_TOPIC_LAMPS 108 // "l" +#define CONFIG_TOPIC_MECHS 109 // "m" +#define CONFIG_TOPIC_PWM 112 // "p" +#define CONFIG_TOPIC_COIN_DOOR_CLOSED_SWITCH 113 // "q" +#define CONFIG_TOPIC_GAME_ON_SOLENOID 114 // "r" +#define CONFIG_TOPIC_SWITCHES 115 // "s" +#define CONFIG_TOPIC_TRIGGER 116 // "t" +#define CONFIG_TOPIC_SWITCH_MATRIX 120 // "x" #define CONFIG_TOPIC_HOLD_POWER_ACTIVATION_TIME 65 // "A" +#define CONFIG_TOPIC_DURATION 65 // "A" +#define CONFIG_TOPIC_VALUE 65 // "A" #define CONFIG_TOPIC_BRIGHTNESS 66 // "B" +#define CONFIG_TOPIC_REVERSE 66 // "B" #define CONFIG_TOPIC_COLOR 67 // "C" #define CONFIG_TOPIC_FAST_SWITCH 70 // "F" +#define CONFIG_TOPIC_FREQUENCY 70 // "F" #define CONFIG_TOPIC_AFTER_GLOW 71 // "G" #define CONFIG_TOPIC_HOLD_POWER 72 // "H" #define CONFIG_TOPIC_LED_NUMBER 76 // "L" -#define CONFIG_TOPIC_MAX_PULSE_TIME 77 // "M" +#define CONFIG_TOPIC_MIN_PULSE_TIME 77 // "M" +#define CONFIG_TOPIC_FROM 77 // "M" +#define CONFIG_TOPIC_MIN_INTENSITY 77 // "M" #define CONFIG_TOPIC_NUMBER 78 // "N" #define CONFIG_TOPIC_AMOUNT_LEDS 79 // "O" #define CONFIG_TOPIC_PORT 80 // "P" -#define CONFIG_TOPIC_MAX_PULSE_TIME 77 // "M" -#define CONFIG_TOPIC_MIN_PULSE_TIME 84 // "T" +#define CONFIG_TOPIC_SPEED 83 // "S" +#define CONFIG_TOPIC_SOURCE 83 // "S" +#define CONFIG_TOPIC_MAX_PULSE_TIME 84 // "T" +#define CONFIG_TOPIC_TO 84 // "T" +#define CONFIG_TOPIC_MAX_INTENSITY 84 // "T" #define CONFIG_TOPIC_LIGHT_UP 85 // "U" #define CONFIG_TOPIC_ACTIVE_LOW 86 // "V" #define CONFIG_TOPIC_POWER 87 // "W" #define CONFIG_TOPIC_TYPE 89 // "Y" +#define CONFIG_TOPIC_EFFECT 89 // "Y" +#define CONFIG_TOPIC_MODE 90 // "Z" +#define CONFIG_TOPIC_PRIORITY 91 // +#define CONFIG_TOPIC_REPEAT 92 // #define CONFIG_TOPIC_NULL 99 // NULL #define PWM_TYPE_SOLENOID 1 // Coil #define PWM_TYPE_FLASHER 2 // Flasher #define PWM_TYPE_LAMP 3 // Lamp -#define PWM_TYPE_SHAKER 4 // Shaker +#define PWM_TYPE_MOTOR 4 // Motor +#define PWM_TYPE_SHAKER 5 // Shaker #define LED_TYPE_GI 1 // GI #define LED_TYPE_FLASHER 2 // Flasher @@ -76,6 +94,10 @@ #define MATRIX_TYPE_COLUMN 1 // Column #define MATRIX_TYPE_ROW 2 // Row +#define PWM_EFFECT_SINE 1 +#define PWM_EFFECT_RAMP_DOWN_STOP 2 +#define PWM_EFFECT_IMPULSE 3 + struct Event { uint8_t sourceId; uint16_t eventId; diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index e88d78c..2a09def 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -189,6 +189,12 @@ void IOBoardController::handleEvent(ConfigEvent *event) { _pwmDevices->registerLamp((byte)port, number, power); activePwmDevices = true; break; + case PWM_TYPE_MOTOR: // Motor + // @todo + break; + case PWM_TYPE_SHAKER: // Shaker + // Shaker is handled by the EffectController. + break; } break; } From f78c125b245e439bbf50e0f6573965c890fbd7cb Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 28 Apr 2025 18:09:49 +0200 Subject: [PATCH 053/102] create uf2 files --- .github/workflows/ci.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7dc656..1eac73a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,7 @@ name: PPUC CI on: push: - pull_request: - schedule: - cron: '0 8 * * *' # run at 08:00 UTC @@ -47,3 +45,21 @@ jobs: run: | cd test/${{ matrix.controller }} pio run + + # New Step: Convert ELF/BIN to UF2 + - name: Create UF2 file + run: | + cd test/${{ matrix.controller }} + # Find the ELF file + ELF_FILE=$(find .pio/build/ -name "*.elf" | head -n 1) + echo "Found ELF file: $ELF_FILE" + # Use PlatformIO's elf2uf2 tool (should be available) + elf2uf2 "$ELF_FILE" "${ELF_FILE%.elf}.uf2" + + # New Step: Upload the UF2 as Artifact + - name: Upload UF2 artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.controller }}-firmware + path: | + test/${{ matrix.controller }}/.pio/build/**/*.uf2 From 598171a382d767515421db9b5efd4b9dec67635a Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 28 Apr 2025 18:17:29 +0200 Subject: [PATCH 054/102] use latest actions --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1eac73a..f65cfed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,10 +17,10 @@ jobs: name: PPUC ${{ matrix.controller }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Cache pip - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} @@ -28,13 +28,13 @@ jobs: ${{ runner.os }}-pip- - name: Cache PlatformIO - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.platformio key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 - name: Install PlatformIO run: | @@ -58,7 +58,7 @@ jobs: # New Step: Upload the UF2 as Artifact - name: Upload UF2 artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ matrix.controller }}-firmware path: | From 0f9ccef14ff7c74ad91f7e4411ebf46927af9453 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 28 Apr 2025 18:21:46 +0200 Subject: [PATCH 055/102] do not fail fast --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f65cfed..6402512 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: controller: ['EffectController', 'EffectControllerPico', 'InputController', 'IO_16_8_1', 'NanoController'] From 437bd6a5a17beb8fdca368ba269443c38d7a54a9 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 28 Apr 2025 18:35:52 +0200 Subject: [PATCH 056/102] earch elf2uf2 --- .github/workflows/ci.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6402512..a9a8c31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,17 +47,16 @@ jobs: cd test/${{ matrix.controller }} pio run - # New Step: Convert ELF/BIN to UF2 - name: Create UF2 file run: | cd test/${{ matrix.controller }} - # Find the ELF file ELF_FILE=$(find .pio/build/ -name "*.elf" | head -n 1) echo "Found ELF file: $ELF_FILE" - # Use PlatformIO's elf2uf2 tool (should be available) - elf2uf2 "$ELF_FILE" "${ELF_FILE%.elf}.uf2" + ELF2UF2=$(find ~/.platformio/packages/ -name "elf2uf2" | head -n 1) + echo "Found elf2uf2 tool: $ELF2UF2" + chmod +x "$ELF2UF2" + "$ELF2UF2" "$ELF_FILE" "${ELF_FILE%.elf}.uf2" - # New Step: Upload the UF2 as Artifact - name: Upload UF2 artifact uses: actions/upload-artifact@v4 with: From 470338f602e02b820571a898c45fa3213e5dd715 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 28 Apr 2025 21:29:49 +0200 Subject: [PATCH 057/102] install elf2uf2 --- .github/workflows/ci.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9a8c31..4ce4350 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,15 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 + - name: Install elf2uf2 + run: | + sudo apt-get update + sudo apt-get install -y cmake build-essential git + git clone https://github.com/raspberrypi/uf2.git + cd uf2/utils + make + sudo cp elf2uf2 /usr/local/bin/ + - name: Install PlatformIO run: | python -m pip install --upgrade pip @@ -52,10 +61,7 @@ jobs: cd test/${{ matrix.controller }} ELF_FILE=$(find .pio/build/ -name "*.elf" | head -n 1) echo "Found ELF file: $ELF_FILE" - ELF2UF2=$(find ~/.platformio/packages/ -name "elf2uf2" | head -n 1) - echo "Found elf2uf2 tool: $ELF2UF2" - chmod +x "$ELF2UF2" - "$ELF2UF2" "$ELF_FILE" "${ELF_FILE%.elf}.uf2" + elf2uf2 "$ELF_FILE" "${ELF_FILE%.elf}.uf2" - name: Upload UF2 artifact uses: actions/upload-artifact@v4 From 9e3860122782c7df36ff7a061b721aca928e806e Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 28 Apr 2025 21:55:50 +0200 Subject: [PATCH 058/102] use picotool --- .github/workflows/ci.yml | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ce4350..c183ec9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,6 +20,23 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Checkout picotool + uses: actions/checkout@v4 + with: + repository: raspberrypi/picotool + path: picotool + + - name: Build and install picotool + run: | + sudo apt-get update + sudo apt-get install -y cmake build-essential libusb-1.0-0-dev + cd picotool + mkdir build + cd build + cmake .. + make + sudo cp picotool /usr/local/bin/ + - name: Cache pip uses: actions/cache@v4 with: @@ -37,15 +54,6 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 - - name: Install elf2uf2 - run: | - sudo apt-get update - sudo apt-get install -y cmake build-essential git - git clone https://github.com/raspberrypi/uf2.git - cd uf2/utils - make - sudo cp elf2uf2 /usr/local/bin/ - - name: Install PlatformIO run: | python -m pip install --upgrade pip @@ -61,7 +69,7 @@ jobs: cd test/${{ matrix.controller }} ELF_FILE=$(find .pio/build/ -name "*.elf" | head -n 1) echo "Found ELF file: $ELF_FILE" - elf2uf2 "$ELF_FILE" "${ELF_FILE%.elf}.uf2" + picotool save "${ELF_FILE}" --format uf2 --output "${ELF_FILE%.elf}.uf2" - name: Upload UF2 artifact uses: actions/upload-artifact@v4 From 5ababec5bd2639709e9b6ec132f498c4e112fc3c Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 28 Apr 2025 22:09:27 +0200 Subject: [PATCH 059/102] install pico-sdk --- .github/workflows/ci.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c183ec9..a18a2a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,11 +20,19 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Checkout pico-sdk + uses: actions/checkout@v4 + with: + repository: raspberrypi/pico-sdk + path: pico-sdk + fetch-depth: 1 + - name: Checkout picotool uses: actions/checkout@v4 with: repository: raspberrypi/picotool path: picotool + fetch-depth: 1 - name: Build and install picotool run: | @@ -33,7 +41,7 @@ jobs: cd picotool mkdir build cd build - cmake .. + cmake .. -DPICO_SDK_PATH=../../pico-sdk make sudo cp picotool /usr/local/bin/ From 46d96b75a04cff54e7e5ab7687ec3c5cb3f3e8fb Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 28 Apr 2025 22:16:37 +0200 Subject: [PATCH 060/102] use tool-picotool-rp2040-earlephilhower --- .github/workflows/ci.yml | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a18a2a9..8ac552c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,31 +20,6 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Checkout pico-sdk - uses: actions/checkout@v4 - with: - repository: raspberrypi/pico-sdk - path: pico-sdk - fetch-depth: 1 - - - name: Checkout picotool - uses: actions/checkout@v4 - with: - repository: raspberrypi/picotool - path: picotool - fetch-depth: 1 - - - name: Build and install picotool - run: | - sudo apt-get update - sudo apt-get install -y cmake build-essential libusb-1.0-0-dev - cd picotool - mkdir build - cd build - cmake .. -DPICO_SDK_PATH=../../pico-sdk - make - sudo cp picotool /usr/local/bin/ - - name: Cache pip uses: actions/cache@v4 with: @@ -77,7 +52,7 @@ jobs: cd test/${{ matrix.controller }} ELF_FILE=$(find .pio/build/ -name "*.elf" | head -n 1) echo "Found ELF file: $ELF_FILE" - picotool save "${ELF_FILE}" --format uf2 --output "${ELF_FILE%.elf}.uf2" + ${HOME}/.platformio/packages/tool-picotool-rp2040-earlephilhower/picotool save "${ELF_FILE}" --format uf2 --output "${ELF_FILE%.elf}.uf2" - name: Upload UF2 artifact uses: actions/upload-artifact@v4 From a2aa0da54185b673aea0f3692f1f5ce7ddcb1d02 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 28 Apr 2025 23:17:54 +0200 Subject: [PATCH 061/102] fixed picotool paramters --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ac552c..2bbb736 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,7 @@ jobs: cd test/${{ matrix.controller }} ELF_FILE=$(find .pio/build/ -name "*.elf" | head -n 1) echo "Found ELF file: $ELF_FILE" - ${HOME}/.platformio/packages/tool-picotool-rp2040-earlephilhower/picotool save "${ELF_FILE}" --format uf2 --output "${ELF_FILE%.elf}.uf2" + ${HOME}/.platformio/packages/tool-picotool-rp2040-earlephilhower/picotool save -f uf2 "${ELF_FILE}" "${ELF_FILE%.elf}.uf2" - name: Upload UF2 artifact uses: actions/upload-artifact@v4 From 20a96893705a1870b5426b80e64d02f3c0b05fd7 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 28 Apr 2025 23:29:35 +0200 Subject: [PATCH 062/102] pico-sdk --- .github/workflows/ci.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bbb736..a939762 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,17 +42,28 @@ jobs: python -m pip install --upgrade pip pip install --upgrade platformio + - name: Install elf2uf2 (Pico SDK tool) + run: | + sudo apt update && sudo apt install -y cmake gcc-arm-none-eabi + git clone https://github.com/raspberrypi/pico-sdk.git + cd pico-sdk + git submodule update --init + cd tools/elf2uf2 + mkdir build && cd build + cmake .. && make + sudo cp elf2uf2 /usr/local/bin/ + - name: Run PlatformIO run: | cd test/${{ matrix.controller }} pio run - - name: Create UF2 file + - name: Create UF2 file (using elf2uf2) run: | cd test/${{ matrix.controller }} ELF_FILE=$(find .pio/build/ -name "*.elf" | head -n 1) echo "Found ELF file: $ELF_FILE" - ${HOME}/.platformio/packages/tool-picotool-rp2040-earlephilhower/picotool save -f uf2 "${ELF_FILE}" "${ELF_FILE%.elf}.uf2" + elf2uf2 "$ELF_FILE" "${ELF_FILE%.elf}.uf2" - name: Upload UF2 artifact uses: actions/upload-artifact@v4 From 26d3a293cf95100f95a4c5964f96a95e403f2c33 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 28 Apr 2025 23:36:34 +0200 Subject: [PATCH 063/102] use pico-tools --- .github/workflows/ci.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a939762..18fd8df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,16 +42,10 @@ jobs: python -m pip install --upgrade pip pip install --upgrade platformio - - name: Install elf2uf2 (Pico SDK tool) + - name: Install elf2uf2 (from pico-tools) run: | - sudo apt update && sudo apt install -y cmake gcc-arm-none-eabi - git clone https://github.com/raspberrypi/pico-sdk.git - cd pico-sdk - git submodule update --init - cd tools/elf2uf2 - mkdir build && cd build - cmake .. && make - sudo cp elf2uf2 /usr/local/bin/ + sudo apt update + sudo apt install -y pico-sdk-tools # Installs elf2uf2 - name: Run PlatformIO run: | From 66d387b5f7fc6786622e58d209add853d9701f92 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 28 Apr 2025 23:45:36 +0200 Subject: [PATCH 064/102] build --- .github/workflows/ci.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 18fd8df..7c5379f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,10 +42,15 @@ jobs: python -m pip install --upgrade pip pip install --upgrade platformio - - name: Install elf2uf2 (from pico-tools) + - name: Build elf2uf2 from source run: | - sudo apt update - sudo apt install -y pico-sdk-tools # Installs elf2uf2 + sudo apt update && sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi + git clone --depth=1 https://github.com/raspberrypi/pico-sdk.git + cd pico-sdk/tools/elf2uf2 + mkdir build && cd build + cmake .. + make + sudo cp elf2uf2 /usr/local/bin/ - name: Run PlatformIO run: | From cb7dfe5ad10a90fb0cfac37abb189a4901400f99 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 28 Apr 2025 23:50:21 +0200 Subject: [PATCH 065/102] elf2uf2 --- .github/workflows/ci.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c5379f..513d4be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,12 +46,14 @@ jobs: run: | sudo apt update && sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi git clone --depth=1 https://github.com/raspberrypi/pico-sdk.git - cd pico-sdk/tools/elf2uf2 - mkdir build && cd build + cd pico-sdk + git submodule update --init + mkdir -p build + cd build cmake .. - make - sudo cp elf2uf2 /usr/local/bin/ - + make elf2uf2 + sudo cp tools/elf2uf2/elf2uf2 /usr/local/bin/ + which elf2uf2 - name: Run PlatformIO run: | cd test/${{ matrix.controller }} From 91dfe97a34370c66230bf7c71869129abd8ec6e1 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Tue, 29 Apr 2025 00:10:15 +0200 Subject: [PATCH 066/102] different elf2uf2 --- .github/workflows/ci.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 513d4be..3085940 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,15 +45,12 @@ jobs: - name: Build elf2uf2 from source run: | sudo apt update && sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi - git clone --depth=1 https://github.com/raspberrypi/pico-sdk.git - cd pico-sdk - git submodule update --init - mkdir -p build - cd build - cmake .. - make elf2uf2 - sudo cp tools/elf2uf2/elf2uf2 /usr/local/bin/ - which elf2uf2 + git clone https://github.com/ckormanyos/elf2uf2.git + cd elf2uf2 + make all + sudo cp bin/elf2uf2 /usr/local/bin/ + cd .. + - name: Run PlatformIO run: | cd test/${{ matrix.controller }} From b9c9be4ff738bb22d2976f10369ab190fd228e59 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 1 May 2025 18:23:26 +0200 Subject: [PATCH 067/102] prepared 0.1.0 --- .github/workflows/io-bords.yml | 112 +++++++++++++++++++++++++++++++++ src/PPUC.h | 4 ++ 2 files changed, 116 insertions(+) create mode 100644 .github/workflows/io-bords.yml diff --git a/.github/workflows/io-bords.yml b/.github/workflows/io-bords.yml new file mode 100644 index 0000000..8937312 --- /dev/null +++ b/.github/workflows/io-bords.yml @@ -0,0 +1,112 @@ +name: PPUC IO Boards + +on: + push: + pull_request: + schedule: + - cron: '0 9 * * *' # run at 08:00 UTC + +jobs: + version: + name: Detect version + runs-on: ubuntu-latest + outputs: + tag: ${{ steps.version.outputs.tag }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - id: version + run: | + VERSION_MAJOR=$(grep -Eo "FIRMWARE_VERSION_MAJOR\s+[0-9]+" src/PPUC.h | grep -Eo "[0-9]+") + VERSION_MINOR=$(grep -Eo "FIRMWARE_VERSION_MINOR\s+[0-9]+" src/PPUC.h | grep -Eo "[0-9]+") + VERSION_PATCH=$(grep -Eo "FIRMWARE_VERSION_PATCH\s+[0-9]+" src/PPUC.h | grep -Eo "[0-9]+") + TAG="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" + echo "${TAG}" + echo "tag=${TAG}" >> $GITHUB_OUTPUT + - name: Check git tag + if: startsWith(github.ref, 'refs/tags/v') + run: | + GIT_TAG="${GITHUB_REF#refs/tags/}" + EXPECTED_TAG="v${{ steps.version.outputs.tag }}" + if [[ "${GIT_TAG}" != "${EXPECTED_TAG}" ]]; then + echo "Error: Git tag (${GIT_TAG}) does not match version from PPUC.h (v${{ steps.version.outputs.tag }})" + exit 1 + fi + + pio-run: + name: Build and upload firmware + runs-on: ubuntu-latest + needs: [ version ] + + strategy: + fail-fast: false + matrix: + controller: ['IO_16_8_1'] + + steps: + - name: PPUC ${{ matrix.controller }} + uses: actions/checkout@v4 + + - name: Cache pip + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Cache PlatformIO + uses: actions/cache@v4 + with: + path: ~/.platformio + key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + + - name: Set up Python + uses: actions/setup-python@v5 + + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + + - name: Build elf2uf2 from source + run: | + sudo apt update && sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi + git clone https://github.com/ckormanyos/elf2uf2.git + cd elf2uf2 + make all + sudo cp bin/elf2uf2 /usr/local/bin/ + cd .. + + - name: Run PlatformIO + run: | + cd test/${{ matrix.controller }} + pio run + + - name: Create UF2 file (using elf2uf2) + run: | + cd test/${{ matrix.controller }} + ELF_FILE=$(find .pio/build/ -name "*.elf" | head -n 1) + echo "Found ELF file: $ELF_FILE" + elf2uf2 "$ELF_FILE" "${ELF_FILE%.elf}.uf2" + cp ${ELF_FILE%.elf}.uf2 ../../${{ matrix.controller }}-${{ needs.version.outputs.tag }}.uf2 + - name: Upload UF2 artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.controller }}-firmware + path: | + ${{ matrix.controller }}.uf2 + + post-build: + runs-on: ubuntu-latest + needs: [ version, pio-run ] + name: Release + steps: + - uses: actions/download-artifact@v4 + - name: Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/v') + with: + draft: true + files: *.uf2 diff --git a/src/PPUC.h b/src/PPUC.h index d26133a..97f27e3 100644 --- a/src/PPUC.h +++ b/src/PPUC.h @@ -6,6 +6,10 @@ #ifndef PPUC_h #define PPUC_h +#define FIRMWARE_VERSION_MAJOR 0 // X Digits +#define FIRMWARE_VERSION_MINOR 1 // Max 2 Digits +#define FIRMWARE_VERSION_PATCH 0 // Max 2 Digits + #include #include "PPUCPlatforms.h" From 93fb4ba5e4233cfd04c35574384bb7802431c476 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 1 May 2025 18:26:04 +0200 Subject: [PATCH 068/102] fixed yml --- .github/workflows/io-bords.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/io-bords.yml b/.github/workflows/io-bords.yml index 8937312..f19aaee 100644 --- a/.github/workflows/io-bords.yml +++ b/.github/workflows/io-bords.yml @@ -109,4 +109,5 @@ jobs: if: startsWith(github.ref, 'refs/tags/v') with: draft: true - files: *.uf2 + files: | + *.uf2 From 1f5ad45158221a6303aa9f7c0495eddb389aeba1 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 1 May 2025 18:30:14 +0200 Subject: [PATCH 069/102] fixed firmware file name --- .github/workflows/io-bords.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/io-bords.yml b/.github/workflows/io-bords.yml index f19aaee..cbec9a0 100644 --- a/.github/workflows/io-bords.yml +++ b/.github/workflows/io-bords.yml @@ -96,7 +96,7 @@ jobs: with: name: ${{ matrix.controller }}-firmware path: | - ${{ matrix.controller }}.uf2 + ${{ matrix.controller }}-${{ needs.version.outputs.tag }}.uf2 post-build: runs-on: ubuntu-latest From 7ed55b7dcf3db9c3c9458c4e26e7e6e58a4e54d9 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 1 May 2025 18:38:15 +0200 Subject: [PATCH 070/102] changed path to firmware files for release --- .github/workflows/io-bords.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/io-bords.yml b/.github/workflows/io-bords.yml index cbec9a0..8c2429c 100644 --- a/.github/workflows/io-bords.yml +++ b/.github/workflows/io-bords.yml @@ -110,4 +110,4 @@ jobs: with: draft: true files: | - *.uf2 + */*.uf2 From 6e9a10f27d7b8b86f18ec843b32257557a66a1dd Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 8 May 2025 10:32:03 +0200 Subject: [PATCH 071/102] added more platforms and extended light matrix to support up to 128 lamps --- ...CombinedGiAndLightMatrixWS2812FXDevice.cpp | 4 +- .../CombinedGiAndLightMatrixWS2812FXDevice.h | 126 +++++++++++------- src/EffectsController.cpp | 2 +- src/PPUC.h | 2 + src/PPUCPlatforms.h | 18 ++- 5 files changed, 100 insertions(+), 52 deletions(-) diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp index 11cbb22..2479c5a 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp @@ -84,9 +84,9 @@ void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE( void CombinedGiAndLightMatrixWS2812FXDevice::assignCustomLed(uint8_t number, int16_t led, uint32_t color) { - // Custom LEDs have numbers >= 100. + // Custom LEDs have numbers >= CUSTOM_LED_OFFSET. // Attch them right behind the original matrix. - assignLedToLightMatrixDE(number - 100 + _LIGHT_MATRIX_SIZE, led, color); + assignLedToLightMatrixDE(number - CUSTOM_LED_OFFSET + _LIGHT_MATRIX_SIZE, led, color); } void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToFlasher( diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h index 29b5ce6..4cf7d67 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h @@ -1,54 +1,85 @@ /* CombinedGiAndLightMatrixWS2812FXDevice.h - Created by Markus Kalkbrenner, 2021 - 2024. - - WPC matrix numbering: - - | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 - ---+----+----+----+----+----+----+----+---- - R1 | 11 | 21 | 31 | 41 | 51 | 61 | 71 | 81 - ---+----+----+----+----+----+----+----+---- - R2 | 12 | 22 | 32 | 42 | 52 | 62 | 72 | 82 - ---+----+----+----+----+----+----+----+---- - R3 | 13 | 23 | 33 | 43 | 53 | 63 | 73 | 83 - ---+----+----+----+----+----+----+----+---- - R4 | 14 | 24 | 34 | 44 | 54 | 64 | 74 | 84 - ---+----+----+----+----+----+----+----+---- - R5 | 15 | 25 | 35 | 45 | 55 | 65 | 75 | 85 - ---+----+----+----+----+----+----+----+---- - R6 | 16 | 26 | 36 | 46 | 56 | 66 | 76 | 86 - ---+----+----+----+----+----+----+----+---- - R7 | 17 | 27 | 37 | 47 | 57 | 67 | 77 | 87 - ---+----+----+----+----+----+----+----+---- - R8 | 18 | 28 | 38 | 48 | 58 | 68 | 78 | 88 - - DE and SYS4-SYS11 matrix numbering: - - | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 - ---+----+----+----+----+----+----+----+---- - R1 | 1 | 9 | 17 | 25 | 33 | 41 | 49 | 57 - ---+----+----+----+----+----+----+----+---- - R2 | 2 | 10 | 18 | 26 | 34 | 42 | 50 | 58 - ---+----+----+----+----+----+----+----+---- - R3 | 3 | 11 | 19 | 27 | 35 | 43 | 51 | 59 - ---+----+----+----+----+----+----+----+---- - R4 | 4 | 12 | 20 | 28 | 36 | 44 | 52 | 60 - ---+----+----+----+----+----+----+----+---- - R5 | 5 | 13 | 21 | 29 | 37 | 45 | 53 | 61 - ---+----+----+----+----+----+----+----+---- - R6 | 6 | 14 | 22 | 30 | 38 | 46 | 54 | 62 - ---+----+----+----+----+----+----+----+---- - R7 | 7 | 15 | 23 | 31 | 39 | 47 | 55 | 63 - ---+----+----+----+----+----+----+----+---- + Created by Markus Kalkbrenner, 2021 - 2025. + + WPC matrix numbering: + + | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 + ---+----+----+----+----+----+----+----+---- + R1 | 11 | 21 | 31 | 41 | 51 | 61 | 71 | 81 + ---+----+----+----+----+----+----+----+---- + R2 | 12 | 22 | 32 | 42 | 52 | 62 | 72 | 82 + ---+----+----+----+----+----+----+----+---- + R3 | 13 | 23 | 33 | 43 | 53 | 63 | 73 | 83 + ---+----+----+----+----+----+----+----+---- + R4 | 14 | 24 | 34 | 44 | 54 | 64 | 74 | 84 + ---+----+----+----+----+----+----+----+---- + R5 | 15 | 25 | 35 | 45 | 55 | 65 | 75 | 85 + ---+----+----+----+----+----+----+----+---- + R6 | 16 | 26 | 36 | 46 | 56 | 66 | 76 | 86 + ---+----+----+----+----+----+----+----+---- + R7 | 17 | 27 | 37 | 47 | 57 | 67 | 77 | 87 + ---+----+----+----+----+----+----+----+---- + R8 | 18 | 28 | 38 | 48 | 58 | 68 | 78 | 88 + + DE and SYS4-SYS11 matrix numbering: + + | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 + ---+----+----+----+----+----+----+----+---- + R1 | 1 | 9 | 17 | 25 | 33 | 41 | 49 | 57 + ---+----+----+----+----+----+----+----+---- + R2 | 2 | 10 | 18 | 26 | 34 | 42 | 50 | 58 + ---+----+----+----+----+----+----+----+---- + R3 | 3 | 11 | 19 | 27 | 35 | 43 | 51 | 59 + ---+----+----+----+----+----+----+----+---- + R4 | 4 | 12 | 20 | 28 | 36 | 44 | 52 | 60 + ---+----+----+----+----+----+----+----+---- + R5 | 5 | 13 | 21 | 29 | 37 | 45 | 53 | 61 + ---+----+----+----+----+----+----+----+---- + R6 | 6 | 14 | 22 | 30 | 38 | 46 | 54 | 62 + ---+----+----+----+----+----+----+----+---- + R7 | 7 | 15 | 23 | 31 | 39 | 47 | 55 | 63 + ---+----+----+----+----+----+----+----+---- R8 | 8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 + Whitestar and early SAM matrix numbering: + + | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 + ---+----+----+----+----+----+----+----+---- + R1 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 + ---+----+----+----+----+----+----+----+---- + R2 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 + ---+----+----+----+----+----+----+----+---- + R3 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 + ---+----+----+----+----+----+----+----+---- + R4 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 + ---+----+----+----+----+----+----+----+---- + R5 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 + ---+----+----+----+----+----+----+----+---- + R6 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 + ---+----+----+----+----+----+----+----+---- + R7 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 + ---+----+----+----+----+----+----+----+---- + R8 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 + ---+----+----+----+----+----+----+----+---- + R9 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 + ---+----+----+----+----+----+----+----+---- + R10| 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 + + Bally 35 is speecial. It can drive 60 lamps. But using some relays 60 differnt + lamps could be drived, for example used in Elektra to drive the lamps of two + different playfields. In libpiname that is handled by adding an offset of 60 + to the lamp number if the relays are switched. So we have 120 lamps. + + Capcom uses two 8x8 matrix and has no GI. So we have 128 CPU-controlled lamps. In order to ease the AfterGlow handling and to avoid long iterations across - arrays and to reduce the numer of addressable LED strings, we extend the + arrays and to reduce the number of addressable LED strings, we extend the original Lamp Matrix. - The internal numbering of any matrix is 0 to 63. Starting at position 64 we - add custom LEDs which are added to the playfield and which are not part of the - original matrix. The amount of custom LEDs is limited by _MAX_CUSTOM_LEDS. - Flashers are added to the matrix at position (63 + _MAX_CUSTOM_LEDS). + The internal numbering to cover any matrix is 0 to 127, normalized to start at 0. + Starting at position 128 we add custom LEDs which are added to the playfield and + which are not part of the original matrix. The amount of custom LEDs is limited + by _MAX_CUSTOM_LEDS. + Flashers are added to the matrix at position (127 + _MAX_CUSTOM_LEDS). */ #ifndef CombinedGiAndLightMatrixWS2812FXDevice_h @@ -64,9 +95,9 @@ #include "WS2812FXDevice.h" #define _MAX_LEDS_GI_STRING 50 -#define _LIGHT_MATRIX_SIZE 64 +#define _LIGHT_MATRIX_SIZE 128 #define _MAX_LEDS_PER_LIGHT 3 -#define _MAX_CUSTOM_LEDS 12 +#define _MAX_CUSTOM_LEDS 24 #define _MAX_FLASHERS 12 class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, @@ -145,6 +176,7 @@ class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, // Internally we store the positions in Data East numbering from 1 to 64. // The WPC-specific functions convert the WPC-specific numbering. + // For other systems, the numbering can go up to 128. int16_t ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + _MAX_FLASHERS][_MAX_LEDS_PER_LIGHT] = {{0}}; uint32_t ledLightMatrixColors[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 14c47e1..720b7d5 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -362,7 +362,7 @@ void EffectsController::handleEvent(ConfigEvent *event) { config_payload); break; case LED_TYPE_LAMP: - if (config_values[2] >= 100) { + if (config_values[2] >= CUSTOM_LED_OFFSET) { ((CombinedGiAndLightMatrixWS2812FXDevice *) ws2812FXDevices[0][0]) ->assignCustomLed(config_values[2], diff --git a/src/PPUC.h b/src/PPUC.h index 97f27e3..e46684e 100644 --- a/src/PPUC.h +++ b/src/PPUC.h @@ -23,4 +23,6 @@ #include +#define CUSTOM_LED_OFFSET 130 + #endif diff --git a/src/PPUCPlatforms.h b/src/PPUCPlatforms.h index 24dab31..4ef72c3 100644 --- a/src/PPUCPlatforms.h +++ b/src/PPUCPlatforms.h @@ -1,15 +1,29 @@ /** - PPUC.h + PPUCPlatforms.h Created by Markus Kalkbrenner. */ #ifndef PPUC_PLATFORMS_h #define PPUC_PLATFORMS_h -#define PLATFORM_WPC 1 #define PLATFORM_DATA_EAST 2 + +// Williams +#define PLATFORM_WPC 1 +#define PLATFORM_SYS3 3 #define PLATFORM_SYS4 4 +#define PLATFORM_SYS6 6 +#define PLATFORM_SYS7 7 #define PLATFORM_SYS11 11 + +#define PLATFORM_BALLY35 35 + +// Stern +#define PLATFORM_WHITESTAR 50 +#define PLATFORM_SAM 51 + +#define PLATFORM_CAPCOM 99 + #define PLATFORM_LIBPINMAME 100 #endif From c010ccc048c179d11065b4766e2fa42c158e28ae Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 8 May 2025 10:48:39 +0200 Subject: [PATCH 072/102] fixed include --- src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h index 4cf7d67..3a83a50 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h @@ -88,6 +88,7 @@ #include #include +#include "../PPUC.h" #include "../EventDispatcher/Event.h" #include "../EventDispatcher/EventDispatcher.h" #include "../EventDispatcher/EventListener.h" From 746046ec74fcfc6bd323426c6b5d28ebde049f4f Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 8 May 2025 11:12:28 +0200 Subject: [PATCH 073/102] fixed teensy and arduino builds --- src/IOBoardController.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 2a09def..895cd2d 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -25,10 +25,11 @@ IOBoardController::IOBoardController(int cT) { _pwmDevices = new PwmDevices(_eventDispatcher); _switches = new Switches(boardId, _eventDispatcher); _switchMatrix = new SwitchMatrix(boardId, _eventDispatcher); - +#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) // Adjust PWM properties if needed. analogWriteFreq(500); analogWriteResolution(8); +#endif } } From f4750a07d31176ff2a2d3e677541a06b5fc6f976 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 8 May 2025 18:21:51 +0200 Subject: [PATCH 074/102] fixed Bally 35 lamp explanation --- .../CombinedGiAndLightMatrixWS2812FXDevice.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h index 3a83a50..9230e5c 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h @@ -66,12 +66,17 @@ ---+----+----+----+----+----+----+----+---- R10| 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 - Bally 35 is speecial. It can drive 60 lamps. But using some relays 60 differnt - lamps could be drived, for example used in Elektra to drive the lamps of two - different playfields. In libpiname that is handled by adding an offset of 60 - to the lamp number if the relays are switched. So we have 120 lamps. + Bally 35 is speecial. It can drive 60 lamps. But using relays, 60 different + lamps could be driven, for example used in Elektra to drive the lamps of two + different playfields. In libpiname that is handled using a standard 8x8 matrix + and adding a second (virtual) 8x8 matrix. We don't see the state of the relay, + but get dedicated lamp numbers from 1-60 and 65-124. So lamps that get triggered + in combination with the relay get offset of 64 to their number. So we have 120 + lamps out of 128. + + Capcom uses two real 8x8 matrix and has no GI. So we have 128 CPU-controlled + lamps. - Capcom uses two 8x8 matrix and has no GI. So we have 128 CPU-controlled lamps. In order to ease the AfterGlow handling and to avoid long iterations across arrays and to reduce the number of addressable LED strings, we extend the original Lamp Matrix. From 0ca2246a34bf1516488228d2971ea20daf30e921 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 19 Oct 2025 12:28:20 +0200 Subject: [PATCH 075/102] added more debugging --- src/IODevices/PwmDevices.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/IODevices/PwmDevices.cpp b/src/IODevices/PwmDevices.cpp index e126755..f13f4b1 100644 --- a/src/IODevices/PwmDevices.cpp +++ b/src/IODevices/PwmDevices.cpp @@ -133,6 +133,8 @@ void PwmDevices::updateSolenoidOrFlasher(bool targetState, byte i) { // A minimum pulse time is configured for this output. // Don't deactivate it immediately but schedule its later deactivation. scheduled[i] = true; + CrossLinkDebugger::debug("Scheduled PWM device state change port %d", + port[i]); } else { // Deactivate the output. analogWrite(port[i], 0); From 33bdaf1a3eecb5eddced54b9128843a56eb769a6 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 19 Oct 2025 21:29:23 +0200 Subject: [PATCH 076/102] disabled brightness setting --- src/EffectsController.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 720b7d5..26b9dc0 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -185,7 +185,7 @@ void EffectsController::handleEvent(ConfigEvent *event) { ws2812FXDeviceCounters[0] = 1; // Brightness might be overwritten later. - ws2812FXDevices[0][0]->setBrightness(config_values[3]); + //ws2812FXDevices[0][0]->setBrightness(config_values[3]); // "off" means no effects, standard operation mode. ws2812FXDevices[0][0]->off(); if (config_values[4] > 0) { @@ -340,7 +340,7 @@ void EffectsController::handleEvent(ConfigEvent *event) { config_values[1] = 0; // type config_values[2] = 0; // number config_values[3] = 0; // led number - config_payload = 0; + config_payload = 0; // color break; case CONFIG_TOPIC_TYPE: config_values[1] = event->value; From 9d1fda9a8158b7c77d068188b9796ea1d29eeb88 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 19 Oct 2025 22:18:43 +0200 Subject: [PATCH 077/102] fixed LED config event --- src/EffectsController.cpp | 251 +++++++++++++++++++------------------- 1 file changed, 124 insertions(+), 127 deletions(-) diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 26b9dc0..9fdec78 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -185,7 +185,7 @@ void EffectsController::handleEvent(ConfigEvent *event) { ws2812FXDeviceCounters[0] = 1; // Brightness might be overwritten later. - //ws2812FXDevices[0][0]->setBrightness(config_values[3]); + ws2812FXDevices[0][0]->setBrightness(config_values[3]); // "off" means no effects, standard operation mode. ws2812FXDevices[0][0]->off(); if (config_values[4] > 0) { @@ -331,147 +331,144 @@ void EffectsController::handleEvent(ConfigEvent *event) { break; } break; + } + break; - case CONFIG_TOPIC_LAMPS: - if (ws2812FXDevices[0][0]) { - switch (event->key) { - case CONFIG_TOPIC_PORT: - config_values[0] = event->value; // port - config_values[1] = 0; // type - config_values[2] = 0; // number - config_values[3] = 0; // led number - config_payload = 0; // color - break; - case CONFIG_TOPIC_TYPE: - config_values[1] = event->value; - break; - case CONFIG_TOPIC_NUMBER: - config_values[2] = event->value; - break; - case CONFIG_TOPIC_LED_NUMBER: - config_values[3] = event->value; + case CONFIG_TOPIC_LAMPS: + if (ws2812FXDevices[0][0]) { + switch (event->key) { + case CONFIG_TOPIC_PORT: + config_values[0] = event->value; // port + config_values[1] = 0; // type + config_values[2] = 0; // number + config_values[3] = 0; // led number + config_payload = 0; // color + break; + case CONFIG_TOPIC_TYPE: + config_values[1] = event->value; + break; + case CONFIG_TOPIC_NUMBER: + config_values[2] = event->value; + break; + case CONFIG_TOPIC_LED_NUMBER: + config_values[3] = event->value; + break; + case CONFIG_TOPIC_COLOR: + config_payload = event->value; + switch (config_values[1]) { + case LED_TYPE_GI: + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignLedToGiString(config_values[2], config_values[3], + config_payload); break; - case CONFIG_TOPIC_COLOR: - config_payload = event->value; - switch (config_values[1]) { - case LED_TYPE_GI: - ((CombinedGiAndLightMatrixWS2812FXDevice *) - ws2812FXDevices[0][0]) - ->assignLedToGiString(config_values[2], - config_values[3], - config_payload); - break; - case LED_TYPE_LAMP: - if (config_values[2] >= CUSTOM_LED_OFFSET) { - ((CombinedGiAndLightMatrixWS2812FXDevice *) - ws2812FXDevices[0][0]) - ->assignCustomLed(config_values[2], - config_values[3], config_payload); - } else if (platform == PLATFORM_WPC) { - ((CombinedGiAndLightMatrixWS2812FXDevice *) - ws2812FXDevices[0][0]) - ->assignLedToLightMatrixWPC(config_values[2], - config_values[3], - config_payload); - } else { - ((CombinedGiAndLightMatrixWS2812FXDevice *) - ws2812FXDevices[0][0]) - ->assignLedToLightMatrixDE(config_values[2], - config_values[3], - config_payload); - } - break; - case LED_TYPE_FLASHER: - ((CombinedGiAndLightMatrixWS2812FXDevice *) - ws2812FXDevices[0][0]) - ->assignLedToFlasher(config_values[2], - config_values[3], - config_payload); - break; + case LED_TYPE_LAMP: + if (config_values[2] >= CUSTOM_LED_OFFSET) { + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignCustomLed(config_values[2], config_values[3], + config_payload); + } else if (platform == PLATFORM_WPC) { + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignLedToLightMatrixWPC( + config_values[2], config_values[3], config_payload); + } else { + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignLedToLightMatrixDE( + config_values[2], config_values[3], config_payload); } break; + case LED_TYPE_FLASHER: + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignLedToFlasher(config_values[2], config_values[3], + config_payload); + break; } - } - break; + break; + } + } + break; - case CONFIG_TOPIC_PWM: - switch (event->key) { - case CONFIG_TOPIC_PORT: - config_values[0] = event->value; // port - config_values[1] = 0; // power - case CONFIG_TOPIC_POWER: - config_values[1] = event->value; - break; - case CONFIG_TOPIC_TYPE: - switch (event->value) { - case PWM_TYPE_SHAKER: // Shaker - _shakerPWMDevice = new WavePWMDevice( - config_values[0], config_values[1], _eventDispatcher); - _shakerPWMDevice->off(); - break; - } + case CONFIG_TOPIC_PWM: + switch (event->key) { + case CONFIG_TOPIC_PORT: + config_values[0] = event->value; // port + config_values[1] = 0; // power + case CONFIG_TOPIC_POWER: + config_values[1] = event->value; + break; + case CONFIG_TOPIC_TYPE: + switch (event->value) { + case PWM_TYPE_SHAKER: // Shaker + _shakerPWMDevice = new WavePWMDevice( + config_values[0], config_values[1], _eventDispatcher); + _shakerPWMDevice->off(); break; } break; + } + break; - case CONFIG_TOPIC_PWM_EFFECT: - if (_shakerPWMDevice) { - switch (event->key) { - case CONFIG_TOPIC_PORT: - config_values[0] = event->value; // port - config_values[1] = 0; // duration - config_values[2] = 0; // effect - config_values[3] = 0; // frequency - config_values[4] = 0; // max intensity - config_values[5] = 0; // min intensity - config_values[6] = 0; // mode - config_values[7] = 0; // priority - config_values[8] = 0; // repeat - config_payload = 0; // color - pwmEffect = nullptr; - break; - case CONFIG_TOPIC_DURATION: - config_values[1] = event->value; - break; - case CONFIG_TOPIC_EFFECT: - config_values[2] = event->value; - break; - case CONFIG_TOPIC_FREQUENCY: - config_values[3] = event->value; - break; - case CONFIG_TOPIC_MAX_INTENSITY: - config_values[4] = event->value; - break; - case CONFIG_TOPIC_MIN_INTENSITY: - config_values[5] = event->value; - break; - case CONFIG_TOPIC_MODE: - config_values[6] = event->value; + case CONFIG_TOPIC_PWM_EFFECT: + if (_shakerPWMDevice) { + switch (event->key) { + case CONFIG_TOPIC_PORT: + config_values[0] = event->value; // port + config_values[1] = 0; // duration + config_values[2] = 0; // effect + config_values[3] = 0; // frequency + config_values[4] = 0; // max intensity + config_values[5] = 0; // min intensity + config_values[6] = 0; // mode + config_values[7] = 0; // priority + config_values[8] = 0; // repeat + config_payload = 0; // color + pwmEffect = nullptr; + break; + case CONFIG_TOPIC_DURATION: + config_values[1] = event->value; + break; + case CONFIG_TOPIC_EFFECT: + config_values[2] = event->value; + break; + case CONFIG_TOPIC_FREQUENCY: + config_values[3] = event->value; + break; + case CONFIG_TOPIC_MAX_INTENSITY: + config_values[4] = event->value; + break; + case CONFIG_TOPIC_MIN_INTENSITY: + config_values[5] = event->value; + break; + case CONFIG_TOPIC_MODE: + config_values[6] = event->value; + break; + case CONFIG_TOPIC_PRIORITY: + config_values[7] = event->value; + break; + case CONFIG_TOPIC_REPEAT: + config_values[8] = event->value; + switch (config_values[2]) { + case PWM_EFFECT_SINE: + pwmEffect = + new SinePWMEffect(config_values[3], config_values[1], + config_values[4], config_values[5]); break; - case CONFIG_TOPIC_PRIORITY: - config_values[7] = event->value; + case PWM_EFFECT_IMPULSE: + pwmEffect = + new ImpulsePWMEffect(config_values[3], config_values[4]); break; - case CONFIG_TOPIC_REPEAT: - config_values[8] = event->value; - switch (config_values[2]) { - case PWM_EFFECT_SINE: - pwmEffect = - new SinePWMEffect(config_values[3], config_values[1], - config_values[4], config_values[5]); - break; - case PWM_EFFECT_IMPULSE: - pwmEffect = new ImpulsePWMEffect(config_values[3], - config_values[4]); - break; - case PWM_EFFECT_RAMP_DOWN_STOP: - pwmEffect = new RampDownStopPWMEffect(config_values[3]); - break; - } + case PWM_EFFECT_RAMP_DOWN_STOP: + pwmEffect = new RampDownStopPWMEffect(config_values[3]); break; } - } - break; + break; + } } + break; } } } From aa1bcb19fa63b8da8e279d3645cc35fb62fb9db9 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Tue, 21 Oct 2025 15:06:01 +0200 Subject: [PATCH 078/102] changed link --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e7c1e7e..c8f70c7 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ The development happens as part of the [PinMAME project](https://github.com/vpin We want to enable people to be creative and to modernize old pinball machines using today's technology. Our goal is to establish an open and affordable platform for that. Ideally people will publish their game-specific PPUs so others could -leverage and potentially improve them. We want to see a growing library of PPUs and a vital homebrew pinball community. +leverage and potentially improve them. We want to see a growing library of PPUs and a vital homebrew pinball community. ## Concept @@ -48,7 +48,7 @@ WIP ### Replacing a CPU (and drivers) -WIP, see [PinMAME project](https://github.com/vpinball/pinmame/tree/master/src/ppuc). +WIP, see [PPUC.org](https://ppuc.org). ## Licence From 875a5762c07b937c8cb3a651239ca962bb454bad Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 22 Oct 2025 00:31:27 +0200 Subject: [PATCH 079/102] fiexed effect trigger configs --- src/EffectsController.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 9fdec78..822c52a 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -306,8 +306,8 @@ void EffectsController::handleEvent(ConfigEvent *event) { if (ws1812Effect) { addEffect( ws1812Effect, ws2812FXDevices[0][0], - new Event(config_values[0], config_values[1], - config_values[2]), + new Event(config_values[2], config_values[3], + config_values[4]), config_values[7], // priority config_values[8] == 255 ? -1 : config_values[8], // repeat @@ -320,8 +320,8 @@ void EffectsController::handleEvent(ConfigEvent *event) { if (pwmEffect) { addEffect( pwmEffect, _shakerPWMDevice, - new Event(config_values[0], config_values[1], - config_values[2]), + new Event(config_values[2], config_values[3], + config_values[4]), config_values[7], // priority config_values[8] == 255 ? -1 : config_values[8], // repeat From 4faec954136bb9f6ffb9e65dcab9600186892fb2 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 10 Nov 2025 15:12:02 +0100 Subject: [PATCH 080/102] updated raspi platform, overclocked RP2040 to 200Mhz --- test/IO_16_8_1/platformio.ini | 4 ++-- test/IO_16_8_1/src/main.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/test/IO_16_8_1/platformio.ini b/test/IO_16_8_1/platformio.ini index 39fc660..8b0bcd3 100644 --- a/test/IO_16_8_1/platformio.ini +++ b/test/IO_16_8_1/platformio.ini @@ -2,9 +2,9 @@ default_envs = pico [env:pico] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git -board = pico +platform = https://github.com/mkalkbrenner/platform-raspberrypi#issue-112 framework = arduino +board = pico board_build.core = earlephilhower board_build.filesystem_size = 0.5m monitor_speed = 115200 diff --git a/test/IO_16_8_1/src/main.cpp b/test/IO_16_8_1/src/main.cpp index 433eca5..5dbdec6 100644 --- a/test/IO_16_8_1/src/main.cpp +++ b/test/IO_16_8_1/src/main.cpp @@ -7,6 +7,10 @@ #include "IOBoardController.h" #include "RPi_Pico_TimerInterrupt.h" +// set to officially supported 200MHz clock +// @see SYS_CLK_MHZ https://github.com/raspberrypi/pico-sdk/releases/tag/2.1.1 +#define SYS_CLK_MHZ 200 + IOBoardController ioBoardController(CONTROLLER_16_8_1); // Platform will be adjusted by ConfigEvent. @@ -38,6 +42,9 @@ bool core_0_initilized = false; // both cores. void setup() { + // Overclock according to Raspberry Pi Pico SDK recommendations. + set_sys_clock_khz(SYS_CLK_MHZ * 1000, true); + uint32_t timeout = millis() + 2000; Serial.begin(115200); From cac6812a440604e7a934addb5ddf51cc53732776 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Fri, 14 Nov 2025 18:23:31 +0100 Subject: [PATCH 081/102] Removed support for old PPUC controllers. The code is still available in the legacy branch. --- .github/workflows/ci.yml | 71 ----- .../platformio.ini => platformio.ini | 6 +- .../CombinedGiAndLightMatrixWS2812FXDevice.h | 5 +- src/EffectsController.cpp | 12 - src/EffectsController.h | 280 +----------------- src/EventDispatcher/CrossLinkDebugger.cpp | 16 - src/EventDispatcher/EventDispatcher.cpp | 20 -- src/EventDispatcher/MultiCoreCrossLink.h | 4 - src/IOBoardController.cpp | 12 +- src/IOBoardController.h | 2 - src/InputController.cpp | 44 --- src/InputController.h | 52 ---- .../DistributionControllerTestButtons.cpp | 26 -- .../DistributionControllerTestButtons.h | 28 -- .../EffectControllerTestButtons.cpp | 22 -- .../EffectControllerTestButtons.h | 28 -- src/InputDevices/GeneralIlluminationWPC.cpp | 140 --------- src/InputDevices/GeneralIlluminationWPC.h | 113 ------- .../InputControllerTestButtons.cpp | 22 -- src/InputDevices/InputControllerTestButtons.h | 28 -- src/InputDevices/LightMatrix.cpp | 123 -------- src/InputDevices/LightMatrix.h | 63 ---- src/InputDevices/Matrix.cpp | 99 ------- src/InputDevices/Matrix.h | 125 -------- src/InputDevices/PIN2DMD.cpp | 61 ---- src/InputDevices/PIN2DMD.h | 34 --- src/InputDevices/Solenoids.cpp | 209 ------------- src/InputDevices/Solenoids.h | 53 ---- src/InputDevices/SwitchMatrix.cpp | 76 ----- src/InputDevices/SwitchMatrix.h | 73 ----- src/PPUC.h | 10 +- src/PPUCTimings.h | 17 ++ src/VisualPinball/PUPComLink.cpp | 61 ---- src/VisualPinball/PUPComLink.h | 60 ---- src/VisualPinball/VPXComLink.cpp | 52 ---- src/VisualPinball/VPXComLink.h | 36 --- {test/IO_16_8_1/src => src}/main.cpp | 18 +- test/EffectController/platformio.ini | 22 -- test/EffectController/src/main.cpp | 128 -------- test/EffectController/test/README | 11 - test/EffectControllerPico/platformio.ini | 24 -- test/EffectControllerPico/src/main.cpp | 123 -------- test/EffectControllerPico/test/README | 11 - test/IOBoardController/platformio.ini | 24 -- test/IOBoardController/src/main.cpp | 22 -- test/IOBoardController/test/README | 11 - test/IO_16_8_1/test/README | 11 - test/IO_16_8_1_ouput_test/platformio.ini | 18 -- test/IO_16_8_1_ouput_test/src/main.cpp | 31 -- test/InputController/platformio.ini | 21 -- test/InputController/src/main.cpp | 65 ---- test/InputController/test/README | 0 test/NanoController/platformio.ini | 21 -- test/NanoController/src/main.cpp | 55 ---- test/NanoController/test/README | 0 55 files changed, 41 insertions(+), 2658 deletions(-) delete mode 100644 .github/workflows/ci.yml rename test/IO_16_8_1/platformio.ini => platformio.ini (86%) delete mode 100644 src/InputController.cpp delete mode 100644 src/InputController.h delete mode 100644 src/InputDevices/DistributionControllerTestButtons.cpp delete mode 100644 src/InputDevices/DistributionControllerTestButtons.h delete mode 100644 src/InputDevices/EffectControllerTestButtons.cpp delete mode 100644 src/InputDevices/EffectControllerTestButtons.h delete mode 100644 src/InputDevices/GeneralIlluminationWPC.cpp delete mode 100644 src/InputDevices/GeneralIlluminationWPC.h delete mode 100644 src/InputDevices/InputControllerTestButtons.cpp delete mode 100644 src/InputDevices/InputControllerTestButtons.h delete mode 100644 src/InputDevices/LightMatrix.cpp delete mode 100644 src/InputDevices/LightMatrix.h delete mode 100644 src/InputDevices/Matrix.cpp delete mode 100644 src/InputDevices/Matrix.h delete mode 100644 src/InputDevices/PIN2DMD.cpp delete mode 100644 src/InputDevices/PIN2DMD.h delete mode 100644 src/InputDevices/Solenoids.cpp delete mode 100644 src/InputDevices/Solenoids.h delete mode 100644 src/InputDevices/SwitchMatrix.cpp delete mode 100644 src/InputDevices/SwitchMatrix.h create mode 100644 src/PPUCTimings.h delete mode 100644 src/VisualPinball/PUPComLink.cpp delete mode 100644 src/VisualPinball/PUPComLink.h delete mode 100644 src/VisualPinball/VPXComLink.cpp delete mode 100644 src/VisualPinball/VPXComLink.h rename {test/IO_16_8_1/src => src}/main.cpp (92%) delete mode 100644 test/EffectController/platformio.ini delete mode 100644 test/EffectController/src/main.cpp delete mode 100644 test/EffectController/test/README delete mode 100644 test/EffectControllerPico/platformio.ini delete mode 100644 test/EffectControllerPico/src/main.cpp delete mode 100644 test/EffectControllerPico/test/README delete mode 100644 test/IOBoardController/platformio.ini delete mode 100644 test/IOBoardController/src/main.cpp delete mode 100644 test/IOBoardController/test/README delete mode 100644 test/IO_16_8_1/test/README delete mode 100644 test/IO_16_8_1_ouput_test/platformio.ini delete mode 100644 test/IO_16_8_1_ouput_test/src/main.cpp delete mode 100644 test/InputController/platformio.ini delete mode 100644 test/InputController/src/main.cpp delete mode 100644 test/InputController/test/README delete mode 100644 test/NanoController/platformio.ini delete mode 100644 test/NanoController/src/main.cpp delete mode 100644 test/NanoController/test/README diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 3085940..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: PPUC CI - -on: - push: - pull_request: - schedule: - - cron: '0 8 * * *' # run at 08:00 UTC - -jobs: - pio-run: - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - controller: ['EffectController', 'EffectControllerPico', 'InputController', 'IO_16_8_1', 'NanoController'] - - name: PPUC ${{ matrix.controller }} - - steps: - - uses: actions/checkout@v4 - - - name: Cache pip - uses: actions/cache@v4 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - name: Cache PlatformIO - uses: actions/cache@v4 - with: - path: ~/.platformio - key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - - - name: Set up Python - uses: actions/setup-python@v5 - - - name: Install PlatformIO - run: | - python -m pip install --upgrade pip - pip install --upgrade platformio - - - name: Build elf2uf2 from source - run: | - sudo apt update && sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi - git clone https://github.com/ckormanyos/elf2uf2.git - cd elf2uf2 - make all - sudo cp bin/elf2uf2 /usr/local/bin/ - cd .. - - - name: Run PlatformIO - run: | - cd test/${{ matrix.controller }} - pio run - - - name: Create UF2 file (using elf2uf2) - run: | - cd test/${{ matrix.controller }} - ELF_FILE=$(find .pio/build/ -name "*.elf" | head -n 1) - echo "Found ELF file: $ELF_FILE" - elf2uf2 "$ELF_FILE" "${ELF_FILE%.elf}.uf2" - - - name: Upload UF2 artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.controller }}-firmware - path: | - test/${{ matrix.controller }}/.pio/build/**/*.uf2 diff --git a/test/IO_16_8_1/platformio.ini b/platformio.ini similarity index 86% rename from test/IO_16_8_1/platformio.ini rename to platformio.ini index 8b0bcd3..618d469 100644 --- a/test/IO_16_8_1/platformio.ini +++ b/platformio.ini @@ -1,7 +1,7 @@ [platformio] -default_envs = pico +default_envs = IO_16_8_1 -[env:pico] +[env:IO_16_8_1] platform = https://github.com/mkalkbrenner/platform-raspberrypi#issue-112 framework = arduino board = pico @@ -10,8 +10,6 @@ board_build.filesystem_size = 0.5m monitor_speed = 115200 build_flags = -D PICO_STDIO_USB ; enable stdio over USB -lib_extra_dirs = - ../.. lib_deps = mkalkbrenner/WavePWM kitesurfer1404/WS2812FX diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h index 9230e5c..59cea01 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h @@ -97,7 +97,6 @@ #include "../EventDispatcher/Event.h" #include "../EventDispatcher/EventDispatcher.h" #include "../EventDispatcher/EventListener.h" -#include "../InputDevices/GeneralIlluminationWPC.h" #include "WS2812FXDevice.h" #define _MAX_LEDS_GI_STRING 50 @@ -106,6 +105,10 @@ #define _MAX_CUSTOM_LEDS 24 #define _MAX_FLASHERS 12 +// Number of WPC GI strings +#define NUM_GI_STRINGS 5 +// Number of WPC GI brightness steps +#define NUM_BRIGHTNESS 8 class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, public EventListener { public: diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 822c52a..247646a 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -71,10 +71,6 @@ WS2812FXDevice *EffectsController::ws2812FXDevice(int port, int number) { return ws2812FXDevices[--port][number]; } -GeneralIlluminationWPC *EffectsController::generalIllumintationWPC() { - return _generalIllumintationWPC; -} - void EffectsController::addEffect(Effect *effect, EffectDevice *device, Event *event, int priority, int repeat, int mode) { @@ -474,14 +470,6 @@ void EffectsController::handleEvent(ConfigEvent *event) { } void EffectsController::update() { - if (controllerType == CONTROLLER_MEGA_ALL_INPUT) { - _testButtons->update(); - } - - if (platform == PLATFORM_WPC && controllerType != CONTROLLER_16_8_1) { - _generalIllumintationWPC->update(); - } - _eventDispatcher->update(); for (int i = 0; i <= stackCounter; i++) { diff --git a/src/EffectsController.h b/src/EffectsController.h index b31320c..280997b 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -8,12 +8,7 @@ #ifndef EFFECTSCONTROLLER_h #define EFFECTSCONTROLLER_h -#include "PPUC.h" -#if defined(__IMXRT1062__) // Teensy 4.1 -#include -#else #include -#endif #include #include "EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h" @@ -36,8 +31,7 @@ #include "EventDispatcher/Event.h" #include "EventDispatcher/EventDispatcher.h" #include "EventDispatcher/EventListener.h" -#include "InputDevices/EffectControllerTestButtons.h" -#include "InputDevices/GeneralIlluminationWPC.h" +#include "PPUC.h" #ifndef EFFECT_STACK_SIZE #define EFFECT_STACK_SIZE 128 @@ -49,57 +43,8 @@ #define UPDATE_INTERVAL_WS2812FX_AFTERGLOW 3 #define UPDATE_INTERVAL_WS2812FX_BRIGHTNESS 10 -#if PPUC_CONTROLLER == CONTROLLER_TEENSY_OUTPUT || \ - PPUC_CONTROLLER == CONTROLLER_TEENSY_OUTPUT_2 || \ - PPUC_CONTROLLER == CONTROLLER_PICO_OUTPUT -#define PPUC_MAX_WS2812FX_DEVICES 7 -#define PPUC_MAX_BRIGHTNESS_CONTROLS 4 -#else #define PPUC_MAX_WS2812FX_DEVICES 1 #define PPUC_MAX_BRIGHTNESS_CONTROLS 1 -#endif - -#if defined(PPUC_NUM_LEDS_1) && defined(PPUC_LED_TYPE_1) && \ - defined(__IMXRT1062__) -DMAMEM byte frameBuffer1[PPUC_NUM_LEDS_1 * ((PPUC_LED_TYPE_1 < 6) ? 3 : 4) * - 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW -#endif - -#if defined(PPUC_NUM_LEDS_2) && defined(PPUC_LED_TYPE_2) && \ - defined(__IMXRT1062__) -DMAMEM byte frameBuffer2[PPUC_NUM_LEDS_2 * ((PPUC_LED_TYPE_2 < 6) ? 3 : 4) * - 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW -#endif - -#if defined(PPUC_NUM_LEDS_3) && defined(PPUC_LED_TYPE_3) && \ - defined(__IMXRT1062__) -DMAMEM byte frameBuffer3[PPUC_NUM_LEDS_3 * ((PPUC_LED_TYPE_3 < 6) ? 3 : 4) * - 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW -#endif - -#if defined(PPUC_NUM_LEDS_4) && defined(PPUC_LED_TYPE_4) && \ - defined(__IMXRT1062__) -DMAMEM byte frameBuffer4[PPUC_NUM_LEDS_4 * ((PPUC_LED_TYPE_4 < 6) ? 3 : 4) * - 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW -#endif - -#if defined(PPUC_NUM_LEDS_5) && defined(PPUC_LED_TYPE_5) && \ - defined(__IMXRT1062__) -DMAMEM byte frameBuffer5[PPUC_NUM_LEDS_5 * ((PPUC_LED_TYPE_5 < 6) ? 3 : 4) * - 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW -#endif - -#if defined(PPUC_NUM_LEDS_6) && defined(PPUC_LED_TYPE_6) && \ - defined(__IMXRT1062__) -DMAMEM byte frameBuffer6[PPUC_NUM_LEDS_6 * ((PPUC_LED_TYPE_6 < 6) ? 3 : 4) * - 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW -#endif - -#if defined(PPUC_NUM_LEDS_7) && defined(PPUC_LED_TYPE_7) && \ - defined(__IMXRT1062__) -DMAMEM byte frameBuffer7[PPUC_NUM_LEDS_7 * ((PPUC_LED_TYPE_7 < 6) ? 3 : 4) * - 4]; // 12 bytes per LED for RGB, 16 bytes for RGBW -#endif class EffectsController : public EventListener { public: @@ -111,196 +56,7 @@ class EffectsController : public EventListener { _eventDispatcher = new EventDispatcher(); _eventDispatcher->addListener(this); - if (controllerType == CONTROLLER_TEENSY_OUTPUT || - controllerType == CONTROLLER_TEENSY_OUTPUT_2 || - controllerType == CONTROLLER_PICO_OUTPUT) { - _ledBuiltInDevice = new LedBuiltInDevice(); - _ledBuiltInDevice->on(); - _nullDevice = new NullDevice(); - _testButtons = new EffectControllerTestButtons(_eventDispatcher); - _shakerPWMDevice = new WavePWMDevice(36, _eventDispatcher); - _shakerPWMDevice->off(); - _ledPWMDevice = new WavePWMDevice(37); - _ledPWMDevice->off(); - if (controllerType != CONTROLLER_TEENSY_OUTPUT) { - _rgbStripeDevice = new RgbStripDevice(9, 10, 11); - _rgbStripeDevice->off(); - } else { - // In revision 0.1.0 these pins are D5-D7, but we don't need them for - // the WPC GI. - pinMode(9, INPUT); - pinMode(10, INPUT); - pinMode(11, INPUT); - } - - brightnessControlBasePin = 38; - -#if defined(PPUC_NUM_LEDS_1) && defined(PPUC_LED_TYPE_1) - ws2812FXDevices[0][0] = - new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_1, 1, PPUC_LED_TYPE_1), - 0, PPUC_NUM_LEDS_1 - 1, 0, 0); - ws2812FXDevices[0][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[0] = 1; - -#if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[0] = - new WS2812Serial(PPUC_NUM_LEDS_1, frameBuffer1, - ws2812FXDevices[0][0]->getWS2812FX()->getPixels(), 1, - PPUC_LED_TYPE_1); - ws2812Serial[0]->begin(); - ws2812FXDevices[0][0]->getWS2812FX()->setCustomShow( - EffectsController::ws2812SerialShow1); -#endif - - ws2812FXDevices[0][0]->off(); - ws2812FXstates[0] = true; -#endif -#if defined(PPUC_NUM_LEDS_2) && defined(PPUC_LED_TYPE_2) - ws2812FXDevices[1][0] = - new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_2, 8, PPUC_LED_TYPE_2), - 0, PPUC_NUM_LEDS_2 - 1, 0, 0); - ws2812FXDevices[1][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[1] = 1; - -#if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[1] = - new WS2812Serial(PPUC_NUM_LEDS_2, frameBuffer2, - ws2812FXDevices[1][0]->getWS2812FX()->getPixels(), 8, - PPUC_LED_TYPE_2); - ws2812Serial[1]->begin(); - ws2812FXDevices[1][0]->getWS2812FX()->setCustomShow( - EffectsController::ws2812SerialShow2); -#endif - - ws2812FXDevices[1][0]->off(); - ws2812FXstates[1] = true; -#endif -#if defined(PPUC_NUM_LEDS_3) && defined(PPUC_LED_TYPE_3) - ws2812FXDevices[2][0] = - new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_3, 14, PPUC_LED_TYPE_3), - 0, PPUC_NUM_LEDS_3 - 1, 0, 0); - ws2812FXDevices[2][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[2] = 1; - -#if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[2] = - new WS2812Serial(PPUC_NUM_LEDS_3, frameBuffer3, - ws2812FXDevices[2][0]->getWS2812FX()->getPixels(), - 14, PPUC_LED_TYPE_3); - ws2812Serial[2]->begin(); - ws2812FXDevices[2][0]->getWS2812FX()->setCustomShow( - EffectsController::ws2812SerialShow3); -#endif - - ws2812FXDevices[2][0]->off(); - ws2812FXstates[2] = true; -#endif -#if defined(PPUC_NUM_LEDS_4) && defined(PPUC_LED_TYPE_4) - ws2812FXDevices[3][0] = - new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_4, 17, PPUC_LED_TYPE_4), - 0, PPUC_NUM_LEDS_4 - 1, 0, 0); - ws2812FXDevices[3][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[3] = 1; - -#if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[3] = - new WS2812Serial(PPUC_NUM_LEDS_4, frameBuffer4, - ws2812FXDevices[3][0]->getWS2812FX()->getPixels(), - 17, PPUC_LED_TYPE_4); - ws2812Serial[3]->begin(); - ws2812FXDevices[3][0]->getWS2812FX()->setCustomShow( - EffectsController::ws2812SerialShow4); -#endif - - ws2812FXDevices[3][0]->off(); - ws2812FXstates[3] = true; -#endif -#if defined(PPUC_NUM_LEDS_5) && defined(PPUC_LED_TYPE_5) - ws2812FXDevices[4][0] = - new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_5, 20, PPUC_LED_TYPE_5), - 0, PPUC_NUM_LEDS_5 - 1, 0, 0); - ws2812FXDevices[4][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[4] = 1; - -#if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[4] = - new WS2812Serial(PPUC_NUM_LEDS_5, frameBuffer5, - ws2812FXDevices[4][0]->getWS2812FX()->getPixels(), - 20, PPUC_LED_TYPE_5); - ws2812Serial[4]->begin(); - ws2812FXDevices[4][0]->getWS2812FX()->setCustomShow( - EffectsController::ws2812SerialShow5); -#endif - - ws2812FXDevices[4][0]->off(); - ws2812FXstates[4] = true; -#endif -#if defined(PPUC_NUM_LEDS_6) && defined(PPUC_LED_TYPE_6) - ws2812FXDevices[5][0] = - new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_6, 24, PPUC_LED_TYPE_6), - 0, PPUC_NUM_LEDS_6 - 1, 0, 0); - ws2812FXDevices[5][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[5] = 1; - -#if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[5] = - new WS2812Serial(PPUC_NUM_LEDS_6, frameBuffer6, - ws2812FXDevices[5][0]->getWS2812FX()->getPixels(), - 24, PPUC_LED_TYPE_6); - ws2812Serial[5]->begin(); - ws2812FXDevices[5][0]->getWS2812FX()->setCustomShow( - EffectsController::ws2812SerialShow6); -#endif - - ws2812FXDevices[5][0]->off(); - ws2812FXstates[5] = true; -#endif -#if defined(PPUC_NUM_LEDS_7) && defined(PPUC_LED_TYPE_7) - ws2812FXDevices[6][0] = - new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_7, 29, PPUC_LED_TYPE_7), - 0, PPUC_NUM_LEDS_7 - 1, 0, 0); - ws2812FXDevices[6][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[6] = 1; - -#if defined(__IMXRT1062__) // Teensy 4.1 - ws2812Serial[6] = - new WS2812Serial(PPUC_NUM_LEDS_7, frameBuffer7, - ws2812FXDevices[6][0]->getWS2812FX()->getPixels(), - 29, PPUC_LED_TYPE_7); - ws2812Serial[6]->begin(); - ws2812FXDevices[6][0]->getWS2812FX()->setCustomShow( - EffectsController::ws2812SerialShow7); -#endif - - ws2812FXDevices[6][0]->off(); - ws2812FXstates[6] = true; -#endif - _testButtons = new EffectControllerTestButtons(_eventDispatcher); - - if (platform == PLATFORM_WPC) { - _generalIllumintationWPC = new GeneralIlluminationWPC(_eventDispatcher); - _generalIllumintationWPC->start(); - } - } else if (controllerType == CONTROLLER_NANO_PIN2DMD_OUTPUT) { - _ledBuiltInDevice = new LedBuiltInDevice(); - _ledBuiltInDevice->on(); - _nullDevice = new NullDevice(); - _shakerPWMDevice = new WavePWMDevice(9, _eventDispatcher); - _shakerPWMDevice->off(); -#if defined(PIN_A0) - brightnessControlBasePin = PIN_A0; -#endif -#if defined(PPUC_NUM_LEDS_1) && defined(PPUC_LED_TYPE_1) - ws2812FXDevices[0][0] = - new WS2812FXDevice(new WS2812FX(PPUC_NUM_LEDS_1, 6, PPUC_LED_TYPE_1), - 0, PPUC_NUM_LEDS_1 - 1, 0, 0); - ws2812FXDevices[0][0]->getWS2812FX()->init(); - ws2812FXDeviceCounters[0] = 1; - - ws2812FXDevices[0][0]->off(); - ws2812FXstates[0] = true; -#endif - } else if (controllerType == CONTROLLER_16_8_1) { + if (controllerType == CONTROLLER_16_8_1) { // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 // -> 58.46 to 935.3 boardId = 16 - ((int)((analogRead(28) + 29.23) / 58.46)); @@ -343,8 +99,6 @@ class EffectsController : public EventListener { WS2812FXDevice* ws2812FXDevice(int port, int number); - GeneralIlluminationWPC* generalIllumintationWPC(); - void addEffect(Effect* effect, EffectDevice* device, Event* event, int priority, int repeat, int mode); @@ -365,30 +119,6 @@ class EffectsController : public EventListener { void handleEvent(ConfigEvent* event); -#if defined(__IMXRT1062__) // Teensy 4.1 - static void ws2812SerialShow1() { - effectsControllerInstance->ws2812Serial[0]->show(); - } - static void ws2812SerialShow2() { - effectsControllerInstance->ws2812Serial[1]->show(); - } - static void ws2812SerialShow3() { - effectsControllerInstance->ws2812Serial[2]->show(); - } - static void ws2812SerialShow4() { - effectsControllerInstance->ws2812Serial[3]->show(); - } - static void ws2812SerialShow5() { - effectsControllerInstance->ws2812Serial[4]->show(); - } - static void ws2812SerialShow6() { - effectsControllerInstance->ws2812Serial[5]->show(); - } - static void ws2812SerialShow7() { - effectsControllerInstance->ws2812Serial[6]->show(); - } -#endif - private: EventDispatcher* _eventDispatcher; LedBuiltInDevice* _ledBuiltInDevice; @@ -401,9 +131,6 @@ class EffectsController : public EventListener { bool ws2812FXstates[PPUC_MAX_WS2812FX_DEVICES] = {0}; bool ws2812FXrunning[PPUC_MAX_WS2812FX_DEVICES] = {0}; byte ws2812FXbrightness[PPUC_MAX_WS2812FX_DEVICES] = {0}; -#if defined(__IMXRT1062__) // Teensy 4.1 - WS2812Serial* ws2812Serial[PPUC_MAX_WS2812FX_DEVICES]; -#endif EffectContainer* stackEffectContainers[EFFECT_STACK_SIZE]; int stackCounter = -1; byte brightnessControl[PPUC_MAX_WS2812FX_DEVICES] = {0}; @@ -426,9 +153,6 @@ class EffectsController : public EventListener { unsigned long ws2812AfterGlowUpdateInterval = 0; unsigned long brightnessUpdateInterval = 0; - EffectControllerTestButtons* _testButtons; - GeneralIlluminationWPC* _generalIllumintationWPC; - static EffectsController* effectsControllerInstance; }; diff --git a/src/EventDispatcher/CrossLinkDebugger.cpp b/src/EventDispatcher/CrossLinkDebugger.cpp index ae26d0c..b731403 100644 --- a/src/EventDispatcher/CrossLinkDebugger.cpp +++ b/src/EventDispatcher/CrossLinkDebugger.cpp @@ -3,7 +3,6 @@ bool CrossLinkDebugger::active = false; CrossLinkDebugger::CrossLinkDebugger() { -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) if (get_core_num() == 0) { rp2040.idleOtherCore(); Serial.println("PPUC IO_16_8_1"); @@ -12,46 +11,37 @@ CrossLinkDebugger::CrossLinkDebugger() { // to 935.3 Serial.println(16 - ((int)((analogRead(28) + 29.23) / 58.46))); Serial.println("PPUC core #0 started"); -#endif Serial.println("PPUC CrossLinkDebugger"); Serial.println("----------------------"); -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.resumeOtherCore(); } else { rp2040.idleOtherCore(); Serial.println("PPUC core #1 started"); rp2040.resumeOtherCore(); } -#endif CrossLinkDebugger::active = true; } void CrossLinkDebugger::handleEvent(Event *event) { -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.idleOtherCore(); Serial.print("Core "); Serial.print(get_core_num(), DEC); Serial.print(" "); -#endif Serial.print("handleEvent: sourceId "); Serial.print(event->sourceId); Serial.print(", eventId "); Serial.print(event->eventId, DEC); Serial.print(", value "); Serial.println(event->value, DEC); -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.resumeOtherCore(); -#endif } void CrossLinkDebugger::handleEvent(ConfigEvent *event) { -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.idleOtherCore(); Serial.print("Core "); Serial.print(get_core_num(), DEC); Serial.print(" "); -#endif Serial.print("handleConfigEvent: boardId "); Serial.print(event->boardId, DEC); Serial.print(", topic "); @@ -64,9 +54,7 @@ void CrossLinkDebugger::handleEvent(ConfigEvent *event) { Serial.print(event->value, DEC); Serial.print(", value(HEX) "); Serial.println(event->value, HEX); -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.resumeOtherCore(); -#endif } void CrossLinkDebugger::debug(const char *format, ...) { @@ -78,16 +66,12 @@ void CrossLinkDebugger::debug(const char *format, ...) { vsnprintf(buffer, sizeof(buffer), format, args); va_end(args); -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.idleOtherCore(); Serial.print("Core "); Serial.print(get_core_num(), DEC); Serial.print(" "); -#endif Serial.print("debug: "); Serial.println(buffer); -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.resumeOtherCore(); -#endif } } diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index 69fcd6f..334fab3 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -12,10 +12,8 @@ void EventDispatcher::setRS485ModePin(int pin) { void EventDispatcher::setBoard(byte b) { board = b; } void EventDispatcher::setMultiCoreCrossLink(MultiCoreCrossLink *mccl) { -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) multiCoreCrossLink = mccl; multiCore = true; -#endif } MultiCoreCrossLink *EventDispatcher::getMultiCoreCrossLink() { @@ -105,7 +103,6 @@ void EventDispatcher::callListeners(Event *event, int sender, bool flush) { } } -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) if (false && Serial) { rp2040.idleOtherCore(); Serial.print("Sent event: sourceId "); @@ -116,15 +113,12 @@ void EventDispatcher::callListeners(Event *event, int sender, bool flush) { Serial.println(event->value, DEC); rp2040.resumeOtherCore(); } -#endif } } -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) if (multiCore && sender != -1 && event->sourceId != EVENT_NULL) { multiCoreCrossLink->pushEvent(event); } -#endif // delete the event and free the memory delete event; @@ -160,11 +154,9 @@ void EventDispatcher::callListeners(ConfigEvent *event, int sender) { } } -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) if (multiCoreCrossLink && event->boardId == board) { multiCoreCrossLink->pushConfigEvent(event); } -#endif } // delete the event and free the memory @@ -263,55 +255,45 @@ void EventDispatcher::update() { } } else { -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) if (Serial) { rp2040.idleOtherCore(); Serial.print("Received wrong second stop byte "); Serial.println(stopByte, DEC); rp2040.resumeOtherCore(); } -#endif } } else { -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) if (Serial) { rp2040.idleOtherCore(); Serial.print("Received wrong first stop byte "); Serial.println(stopByte, DEC); rp2040.resumeOtherCore(); } -#endif } } else { -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) if (Serial) { rp2040.idleOtherCore(); Serial.print("Received invalid event id "); Serial.println(eventId, DEC); rp2040.resumeOtherCore(); } -#endif } } } else { -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) if (Serial) { rp2040.idleOtherCore(); Serial.print("Received invalid source id "); Serial.println(sourceId, DEC); rp2040.resumeOtherCore(); } -#endif } } else { -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) if (Serial) { rp2040.idleOtherCore(); Serial.print("Received wrong start byte "); Serial.println(startByte, DEC); rp2040.resumeOtherCore(); } -#endif // We didn't receive a start byte. Fake "success" to start over with the // next byte. success = true; @@ -340,7 +322,6 @@ void EventDispatcher::update() { } } -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) if (multiCoreCrossLink) { if (multiCoreCrossLink->eventAvailable()) { Event *event = multiCoreCrossLink->popEvent(); @@ -352,7 +333,6 @@ void EventDispatcher::update() { callListeners(configEvent, -1); } } -#endif } uint32_t EventDispatcher::getLastPoll() { diff --git a/src/EventDispatcher/MultiCoreCrossLink.h b/src/EventDispatcher/MultiCoreCrossLink.h index 16851de..259874b 100644 --- a/src/EventDispatcher/MultiCoreCrossLink.h +++ b/src/EventDispatcher/MultiCoreCrossLink.h @@ -1,9 +1,7 @@ #ifndef MULTI_CORE_CROSS_LINK_h #define MULTI_CORE_CROSS_LINK_h -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) #include -#endif #include @@ -29,7 +27,6 @@ typedef struct QueuedConfigEvent { } ConfigEventItem; class MultiCoreCrossLink { -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) public: MultiCoreCrossLink() { if (get_core_num() == 0) { @@ -90,7 +87,6 @@ class MultiCoreCrossLink { private: queue_t _eventQueue[2]; queue_t _configEventQueue; -#endif }; #endif \ No newline at end of file diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 895cd2d..858bff1 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -18,18 +18,14 @@ IOBoardController::IOBoardController(int cT) { _eventDispatcher->setRS485ModePin(2); _eventDispatcher->setBoard(boardId); _eventDispatcher->setCrossLinkSerial(Serial1); -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) _multiCoreCrossLink = new MultiCoreCrossLink(); _eventDispatcher->setMultiCoreCrossLink(_multiCoreCrossLink); -#endif _pwmDevices = new PwmDevices(_eventDispatcher); _switches = new Switches(boardId, _eventDispatcher); _switchMatrix = new SwitchMatrix(boardId, _eventDispatcher); -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) // Adjust PWM properties if needed. analogWriteFreq(500); analogWriteResolution(8); -#endif } } @@ -52,9 +48,7 @@ void IOBoardController::update() { if (resetTimer > 0 && resetTimer < millis()) { if (!m_debug) { -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) rp2040.reboot(); -#endif } else { resetTimer = 0; CrossLinkDebugger::debug( @@ -84,9 +78,9 @@ void IOBoardController::handleEvent(Event *event) { _switches->reset(); _switchMatrix->reset(); - // Issue a reset of the board in 3 seconds. - // Core 1 should have enough time to rest it's devices. - resetTimer = millis() + 3000; + // Issue a delayed reset of the board. + // Core 1 should have enough time to turn off it's devices. + resetTimer = millis() + WAIT_FOR_EFFECT_CONTROLLER_RESET; break; } diff --git a/src/IOBoardController.h b/src/IOBoardController.h index 421f852..b07f627 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -67,9 +67,7 @@ class IOBoardController : public EventListener { uint32_t resetTimer = 0; EventDispatcher *_eventDispatcher; -#if defined(ARDUINO_ARCH_MBED_RP2040) || defined(ARDUINO_ARCH_RP2040) MultiCoreCrossLink *_multiCoreCrossLink; -#endif }; #endif diff --git a/src/InputController.cpp b/src/InputController.cpp deleted file mode 100644 index 781b7a7..0000000 --- a/src/InputController.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "InputController.h" - -InputController::InputController(int controllerType, byte pf) { - _eventDispatcher = new EventDispatcher(); - InputController(controllerType, pf, _eventDispatcher); -} - -InputController::InputController(int controllerType, byte pf, - EventDispatcher* eventDispatcher) { - pinMode(LED_BUILTIN, OUTPUT); - - platform = pf; - _eventDispatcher = eventDispatcher; - - if (controllerType == CONTROLLER_MEGA_ALL_INPUT) { - _solenoids = new Solenoids(controllerType, _eventDispatcher); - _switchMatrix = new SwitchMatrix(_eventDispatcher, platform); - _lightMatrix = new LightMatrix(_eventDispatcher, platform); - _pin2Dmd = new PIN2DMD(_eventDispatcher); - _pupComLink = new PUPComLink(); - _testButtons = new InputControllerTestButtons(_eventDispatcher); - } else if (controllerType == CONTROLLER_NANO_PIN2DMD_OUTPUT) { - _pin2Dmd = new PIN2DMD(_eventDispatcher); - } else { - Serial.print("Unsupported Input Controller: "); - Serial.println(controllerType); - } -} - -Solenoids* InputController::solenoids() { return _solenoids; } - -SwitchMatrix* InputController::switchMatrix() { return _switchMatrix; } - -LightMatrix* InputController::lightMatrix() { return _lightMatrix; } - -PIN2DMD* InputController::pin2Dmd() { return _pin2Dmd; } - -PUPComLink* InputController::pupComLink() { return _pupComLink; } - -InputControllerTestButtons* InputController::testButtons() { - return _testButtons; -} - -EventDispatcher* InputController::eventDispatcher() { return _eventDispatcher; } diff --git a/src/InputController.h b/src/InputController.h deleted file mode 100644 index 2de9612..0000000 --- a/src/InputController.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - InputController.h - Created by Markus Kalkbrenner. -*/ - -#ifndef INPUTCONTROLLER_h -#define INPUTCONTROLLER_h - -#include "EventDispatcher/Event.h" -#include "EventDispatcher/EventDispatcher.h" -#include "InputDevices/InputControllerTestButtons.h" -#include "InputDevices/LightMatrix.h" -#include "InputDevices/PIN2DMD.h" -#include "InputDevices/Solenoids.h" -#include "InputDevices/SwitchMatrix.h" -#include "PPUC.h" -#include "VisualPinball/PUPComLink.h" - -class InputController { - public: - InputController(int controllerType, byte platform); - - InputController(int controllerType, byte platform, - EventDispatcher* eventDispatcher); - - Solenoids* solenoids(); - - SwitchMatrix* switchMatrix(); - - LightMatrix* lightMatrix(); - - PIN2DMD* pin2Dmd(); - - PUPComLink* pupComLink(); - - InputControllerTestButtons* testButtons(); - - EventDispatcher* eventDispatcher(); - - byte platform; - - private: - Solenoids* _solenoids; - SwitchMatrix* _switchMatrix; - LightMatrix* _lightMatrix; - PIN2DMD* _pin2Dmd; - PUPComLink* _pupComLink; - InputControllerTestButtons* _testButtons; - EventDispatcher* _eventDispatcher; -}; - -#endif diff --git a/src/InputDevices/DistributionControllerTestButtons.cpp b/src/InputDevices/DistributionControllerTestButtons.cpp deleted file mode 100644 index 2ed44f5..0000000 --- a/src/InputDevices/DistributionControllerTestButtons.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "DistributionControllerTestButtons.h" - -DistributionControllerTestButtons::DistributionControllerTestButtons( - EventDispatcher* eD) { - eventDispatcher = eD; - - for (int i = 0; i <= 1; i++) { - button[i] = new Bounce2::Button(); - button[i]->attach(22 + i, INPUT_PULLUP); - button[i]->interval(10); - button[i]->setPressedState(LOW); - } -} - -void DistributionControllerTestButtons::update() { - for (int i = 0; i <= 1; i++) { - button[i]->update(); - if (button[i]->pressed()) { - eventDispatcher->dispatch( - new Event(EVENT_SOURCE_SWITCH, word(0, 63 + i), 1)); - } else if (button[i]->released()) { - eventDispatcher->dispatch( - new Event(EVENT_SOURCE_SWITCH, word(0, 63 + i), 0)); - } - } -} diff --git a/src/InputDevices/DistributionControllerTestButtons.h b/src/InputDevices/DistributionControllerTestButtons.h deleted file mode 100644 index 243e8b7..0000000 --- a/src/InputDevices/DistributionControllerTestButtons.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - DistributionControllerTestButtons.h - Created by Markus Kalkbrenner, 2022. - - Play more pinball! -*/ - -#ifndef EffectControllerTestButtons_h -#define EffectControllerTestButtons_h - -#include -#include - -#include "../EventDispatcher/Event.h" -#include "../EventDispatcher/EventDispatcher.h" - -class DistributionControllerTestButtons { - public: - DistributionControllerTestButtons(EventDispatcher* eD); - - void update(); - - protected: - EventDispatcher* eventDispatcher; - Bounce2::Button* button[2]; -}; - -#endif diff --git a/src/InputDevices/EffectControllerTestButtons.cpp b/src/InputDevices/EffectControllerTestButtons.cpp deleted file mode 100644 index 752a2d2..0000000 --- a/src/InputDevices/EffectControllerTestButtons.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "EffectControllerTestButtons.h" - -EffectControllerTestButtons::EffectControllerTestButtons(EventDispatcher* eD) { - eventDispatcher = eD; - - for (int i = 0; i <= 1; i++) { - button[i] = new Bounce2::Button(); - button[i]->attach(22 + i, INPUT_PULLUP); - button[i]->interval(10); - button[i]->setPressedState(LOW); - } -} - -void EffectControllerTestButtons::update() { - for (int i = 0; i <= 1; i++) { - button[i]->update(); - if (button[i]->pressed()) { - eventDispatcher->dispatch( - new Event(EVENT_SOURCE_SWITCH, word(0, 201 + i))); - } - } -} diff --git a/src/InputDevices/EffectControllerTestButtons.h b/src/InputDevices/EffectControllerTestButtons.h deleted file mode 100644 index 17cf52f..0000000 --- a/src/InputDevices/EffectControllerTestButtons.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - EffectControllerTestButtons.h - Created by Markus Kalkbrenner, 2021. - - Play more pinball! -*/ - -#ifndef EffectControllerTestButtons_h -#define EffectControllerTestButtons_h - -#include -#include - -#include "../EventDispatcher/Event.h" -#include "../EventDispatcher/EventDispatcher.h" - -class EffectControllerTestButtons { - public: - EffectControllerTestButtons(EventDispatcher* eD); - - void update(); - - protected: - EventDispatcher* eventDispatcher; - Bounce2::Button* button[2]; -}; - -#endif diff --git a/src/InputDevices/GeneralIlluminationWPC.cpp b/src/InputDevices/GeneralIlluminationWPC.cpp deleted file mode 100644 index 7d324cb..0000000 --- a/src/InputDevices/GeneralIlluminationWPC.cpp +++ /dev/null @@ -1,140 +0,0 @@ -// -// Created by Markus Kalkbrenner on 14.03.21. -// - -#include "GeneralIlluminationWPC.h" - -// see https://forum.arduino.cc/index.php?topic=398610.0 -GeneralIlluminationWPC* GeneralIlluminationWPC::giInstance = NULL; - -void GeneralIlluminationWPC::start() { - // initialize data - for (int i = 0; i < NUM_GI_STRINGS; i++) { - for (int k = 0; k <= NUM_BRIGHTNESS; k++) { - sBrightnessHist[i][k] = 0; - } - } - - attachInterrupt(digitalPinToInterrupt(2), GeneralIlluminationWPC::_changeD0, - RISING); - attachInterrupt(digitalPinToInterrupt(3), GeneralIlluminationWPC::_changeD1, - RISING); - attachInterrupt(digitalPinToInterrupt(4), GeneralIlluminationWPC::_changeD2, - RISING); - attachInterrupt(digitalPinToInterrupt(5), GeneralIlluminationWPC::_changeD3, - RISING); - attachInterrupt(digitalPinToInterrupt(6), GeneralIlluminationWPC::_changeD4, - RISING); - attachInterrupt(digitalPinToInterrupt(12), GeneralIlluminationWPC::_changeZC, - FALLING); -} - -void GeneralIlluminationWPC::stop() { - detachInterrupt(digitalPinToInterrupt(2)); - detachInterrupt(digitalPinToInterrupt(3)); - detachInterrupt(digitalPinToInterrupt(4)); - detachInterrupt(digitalPinToInterrupt(5)); - detachInterrupt(digitalPinToInterrupt(6)); - detachInterrupt(digitalPinToInterrupt(12)); -} - -void GeneralIlluminationWPC::update() { - for (int string = 0; string < NUM_GI_STRINGS; string++) { - if (sBrightness[string] != sBrightnessTarget[string]) { - sBrightness[string] = sBrightnessTarget[string]; - eventDispatcher->dispatch( - new Event(EVENT_SOURCE_GI, word(0, string + 1), sBrightness[string])); - } - } -} - -void GeneralIlluminationWPC::newBrightness(uint8_t string, uint8_t b) { - // Check whether the brightness has changed - if (b <= NUM_BRIGHTNESS && b != sBrightnessTarget[string]) { - // Add the current brightness value to the histogram - if (sBrightnessHist[string][b] < 255) { - sBrightnessHist[string][b]++; - } - - // Only switch when some measurements in the center of the - // brightness interval have been seen - if (sBrightnessHist[string][b] > BRIGHTNESS_SWITCH_THRESH) { - // switch to the new brightness target value - sBrightnessTarget[string] = b; - - // clear the histogram - memset((void*)&(sBrightnessHist[string][0]), 0, NUM_BRIGHTNESS + 1); - } - } -} - -void GeneralIlluminationWPC::_changeD0() { giInstance->handlePinChange(0); } - -void GeneralIlluminationWPC::_changeD1() { giInstance->handlePinChange(1); } - -void GeneralIlluminationWPC::_changeD2() { giInstance->handlePinChange(2); } - -void GeneralIlluminationWPC::_changeD3() { giInstance->handlePinChange(3); } - -void GeneralIlluminationWPC::_changeD4() { giInstance->handlePinChange(4); } - -void GeneralIlluminationWPC::handlePinChange(uint8_t giString) { - // Handle the new brightness value - newBrightness(giString, dtToBrightness(micros() - sZCIntTime)); - - sInterruptsSeen |= (1 << giString); -} - -void GeneralIlluminationWPC::_changeZC() { - // Serial.println("ZC"); - - // What time is it? - giInstance->sZCIntTime = micros(); - - // All strings without interrupt in the previous interval are either fully - // on or off. So their brightness is not set by handlePinChange(). Set - // 0 (off) or NUM_BRIGHTNESS (on) here. - for (int i = 0; i < NUM_GI_STRINGS; i++) { - if ((giInstance->sInterruptsSeen & (1 << i)) == 0) { - giInstance->newBrightness(i, digitalRead(2 + i) ? 0 : NUM_BRIGHTNESS); - } - } - // Clear the interrupts mask - giInstance->sInterruptsSeen = 0; -} - -uint8_t GeneralIlluminationWPC::dtToBrightness(uint32_t dt) { - // This function leaves some margin at the interval borders to account for - // the fact the intervals are slightly overlapping and therefore an - // unambiguous brightness determination is not always possible. In this case - // the function returns 255. - if (dt < (1200 - BRIGHTNESS_INTERVAL_MARGIN)) { - // It seems that brightness level 7 is never used in any WPC pinball - // machine. It us selectable in the GI test, but the time is not measurable. - // The signal remains HIGH and therefore a brightness level of 8 will be - // detected. So we return 8 here as well, even if this part of the code - // should never be reached. - return NUM_BRIGHTNESS; - } else if ((dt > (1200 + BRIGHTNESS_INTERVAL_MARGIN)) && - (dt < (2200 - BRIGHTNESS_INTERVAL_MARGIN))) { - return 6; - } else if ((dt > (2200 + BRIGHTNESS_INTERVAL_MARGIN)) && - (dt < (3200 - BRIGHTNESS_INTERVAL_MARGIN))) { - return 5; - } else if ((dt > (3200 + BRIGHTNESS_INTERVAL_MARGIN)) && - (dt < (4200 - BRIGHTNESS_INTERVAL_MARGIN))) { - return 4; - } else if ((dt > (4200 + BRIGHTNESS_INTERVAL_MARGIN)) && - (dt < (5200 - BRIGHTNESS_INTERVAL_MARGIN))) { - return 3; - } else if ((dt > (5200 + BRIGHTNESS_INTERVAL_MARGIN)) && - (dt < (6200 - BRIGHTNESS_INTERVAL_MARGIN))) { - return 2; - } else if ((dt > (6200 + BRIGHTNESS_INTERVAL_MARGIN)) && - (dt < (7200 - BRIGHTNESS_INTERVAL_MARGIN))) { - return 1; - } - - // invalid interval - return BRIGHTNESS_UNCERTAIN; -} diff --git a/src/InputDevices/GeneralIlluminationWPC.h b/src/InputDevices/GeneralIlluminationWPC.h deleted file mode 100644 index 293423e..0000000 --- a/src/InputDevices/GeneralIlluminationWPC.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - GeneralIlluminationWPC.h. - Created by Markus Kalkbrenner, 2021. - - Based on Afterglow GI by Christoph Schmid, 2019 - - Play more pinball! -*/ - -#ifndef _GENERALILLUMINATIONWPC_H -#define _GENERALILLUMINATIONWPC_H - -/* This code assumes following pin layout: - * - * +----------+---------------+------+ - * | Name | Function | Pin# | - * +----------+---------------+------+ - * | STR1_IN | D0 Data Bus | D2 | - * | STR2_IN | D1 Data Bus | D3 | - * | STR3_IN | D2 Data Bus | D4 | - * | STR4_IN | D3 Data Bus | D5 | - * | STR5_IN | D4 Data Bus | D6 | - * | ZC | Zero Crossing | D12 | - * +----------+---------------+------+ - */ - -// The WPC CPU issues a short signal to turn on the triac controlling the -// AC voltage. The Triac will stay on until the next zero crossing of the -// AC signal. -// The closer the next signal is to the zero crossing, the brighter the lamps -// will be. If no signal is issued at all (stays high), the lamps will light -// at full power (brightness level 8). If the signal remains low, the lamps -// are turned off. -// The zero crossing signal is issued with twice the AC frequency, i.e. with -// 100Hz or every 10ms in Europe. -// The scope says the ZC signal is 1ms long while the Triac signal is only -// ~8us long. - -// ZC Sig TR Sig ZC Sig ZC Zero Crossing Signal -// | | | TR Triac enable signal -// |--+ | | | | v| | | | |--+ B0-B6 Brightness 1-7 levels (WPC GI) -// |ZC| |ZC| -// | |B7 B6 B5 B4 B3 B2 B1 | | -// +-----------------------------+------ -// 0ms 10ms - -#include "../EventDispatcher/EventDispatcher.h" - -//------------------------------------------------------------------------------ -// Setup - -// Number of GI strings -#define NUM_GI_STRINGS 5 - -// Number of brightness steps -#define NUM_BRIGHTNESS 8 - -// Number of center brightness values required to switch value -#define BRIGHTNESS_SWITCH_THRESH 5 - -// Brightness interval margin to account for overlapping intervals [us] -#define BRIGHTNESS_INTERVAL_MARGIN 150 - -// Uncertain brightness value -#define BRIGHTNESS_UNCERTAIN 255 - -class GeneralIlluminationWPC { - public: - GeneralIlluminationWPC(EventDispatcher *eD) { - giInstance = this; - eventDispatcher = eD; - - pinMode(2, INPUT); - pinMode(3, INPUT); - pinMode(4, INPUT); - pinMode(5, INPUT); - pinMode(6, INPUT); - pinMode(12, INPUT_PULLUP); // Inverted on Adapter. - } - - void start(); - void stop(); - void update(); - - void handlePinChange(uint8_t giString); - void newBrightness(uint8_t string, uint8_t b); - - static void _changeD0(); - static void _changeD1(); - static void _changeD2(); - static void _changeD3(); - static void _changeD4(); - static void _changeZC(); - - volatile uint32_t sZCIntTime = 0; - volatile uint8_t sInterruptsSeen = 0; - volatile uint32_t sDataIntLast[NUM_GI_STRINGS] = {0}; - - protected: - uint8_t dtToBrightness(uint32_t dt); - - EventDispatcher *eventDispatcher; - - uint8_t sBrightness[NUM_GI_STRINGS] = {0}; - uint8_t sBrightnessTarget[NUM_GI_STRINGS] = {0}; - uint8_t sBrightnessHist[NUM_GI_STRINGS] - [NUM_BRIGHTNESS + 1]; // including 0 for 'off' - - private: - static GeneralIlluminationWPC *giInstance; -}; - -#endif //_GENERALILLUMINATIONWPC_H diff --git a/src/InputDevices/InputControllerTestButtons.cpp b/src/InputDevices/InputControllerTestButtons.cpp deleted file mode 100644 index c6e980d..0000000 --- a/src/InputDevices/InputControllerTestButtons.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "InputControllerTestButtons.h" - -InputControllerTestButtons::InputControllerTestButtons(EventDispatcher* eD) { - eventDispatcher = eD; - - for (int i = 0; i <= 1; i++) { - button[i] = new Bounce2::Button(); - button[i]->attach(52 + i, INPUT_PULLUP); - button[i]->interval(10); - button[i]->setPressedState(LOW); - } -} - -void InputControllerTestButtons::update() { - for (int i = 0; i <= 1; i++) { - button[i]->update(); - if (button[i]->pressed()) { - eventDispatcher->dispatch( - new Event(EVENT_SOURCE_SWITCH, word(0, 203 + i))); - } - } -} diff --git a/src/InputDevices/InputControllerTestButtons.h b/src/InputDevices/InputControllerTestButtons.h deleted file mode 100644 index d00cd37..0000000 --- a/src/InputDevices/InputControllerTestButtons.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - InputControllerTestButtons.h - Created by Markus Kalkbrenner, 2021. - - Play more pinball! -*/ - -#ifndef InputControllerTestButtons_h -#define InputControllerTestButtons_h - -#include -#include - -#include "../EventDispatcher/Event.h" -#include "../EventDispatcher/EventDispatcher.h" - -class InputControllerTestButtons { - public: - InputControllerTestButtons(EventDispatcher* eD); - - void update(); - - protected: - EventDispatcher* eventDispatcher; - Bounce2::Button* button[2]; -}; - -#endif diff --git a/src/InputDevices/LightMatrix.cpp b/src/InputDevices/LightMatrix.cpp deleted file mode 100644 index 4be6a9a..0000000 --- a/src/InputDevices/LightMatrix.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#if defined(__AVR__) || (__avr__) || (__IMXRT1062__) -#include -#endif - -#include "LightMatrix.h" - -// see https://forum.arduino.cc/index.php?topic=398610.0 -LightMatrix* LightMatrix::lightMatrixInstance = NULL; - -void LightMatrix::start() { -#if defined(__AVR__) || (__avr__) || (__IMXRT1062__) - Timer1.attachInterrupt(LightMatrix::_readRow); -#endif -} - -void LightMatrix::stop() { -#if defined(__AVR__) || (__avr__) || (__IMXRT1062__) - Timer1.detachInterrupt(); -#endif -} - -void LightMatrix::_readRow() { - // 74HC165 16bit sampling - uint16_t inData = lightMatrixInstance->sampleInput(); - byte inColMask = (inData >> 8); // LSB is col 0, MSB is col 7 - byte inRowMask = ~(byte)inData; // high means OFF, LSB is row 0, MSB is row 7 - - // evaluate the column reading - // only one bit should be set as only one column can be active at a time - uint32_t inCol = NUM_COLS; - switch (inColMask) { - case 0x01: - inCol = 0; - break; - case 0x02: - inCol = 1; - break; - case 0x04: - inCol = 2; - break; - case 0x08: - inCol = 3; - break; - case 0x10: - inCol = 4; - break; - case 0x20: - inCol = 5; - break; - case 0x40: - inCol = 6; - break; - case 0x80: - inCol = 7; - break; - default: - // This may happen if the sample is taken in between column transition. - // Depending on the pinball ROM version the duration of this transition - // varies. On a Whitewater with Home ROM LH6 (contains anti ghosting - // updates) this gap was measured to be around 30us long. Machines with - // anti-ghosting firmware will show a gap with no column enabled for a - // while during the transition while older firmwares might have two - // columns enabled at the same time due to slow transistor deactivation. - // Both cases are caught here. See also - // https://emmytech.com/arcade/led_ghost_busting/index.html for details. - return; - } - - // Update only with a valid input. If the input is invalid the current - // matrix state is left unchanged. - // The matrix is updated only once per original column cycle. The code - // waits for a number of consecutive consistent information before updating - // the matrix. - if (lightMatrixInstance->updateValid(inCol, inRowMask)) { - // Serial.print(inCol + 1); Serial.print(": "); Serial.println(inRowMask, - // BIN); - // update the current column - lightMatrixInstance->rows[inCol] = inRowMask; - } -} - -uint16_t LightMatrix::sampleInput() { - // drive CLK and LOAD low - digitalWrite(6, LOW); - digitalWrite(7, LOW); - - // wait some time - uint16_t data = 0; - data += 17; - data -= 3; - - // drive LOAD high to save pin states - digitalWrite(7, HIGH); - - // clock in all data - for (byte i = 0; i < 16; i++) { - data <<= 1; // make way for the new bit - digitalWrite(6, LOW); // CLK low - data |= digitalRead(5); // read data bit - digitalWrite(6, HIGH); // CLK high - } - - return data; -} - -bool LightMatrix::updateValid(byte inCol, byte inRowMask) { - // check if the current column has not been handled already - if (inRowMask != lastRowMask[inCol]) { - // reset the counter when the data changes - consistentSamples[inCol] = 1; - lastRowMask[inCol] = inRowMask; - } - // count number of consecutive samples with consistent data - else if (consistentSamples[inCol] < 255) { - consistentSamples[inCol]++; - } - - if (consistentSamples[inCol] >= SINGLE_UPDATE_CONS) { - return true; - } - - return false; -} diff --git a/src/InputDevices/LightMatrix.h b/src/InputDevices/LightMatrix.h deleted file mode 100644 index f9d841b..0000000 --- a/src/InputDevices/LightMatrix.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - LightMatrix.h - Created by Markus Kalkbrenner, 2020. - Derived from afterglow: 2018-2019 Christoph Schmid - - Play more pinball! -*/ - -#ifndef LightMatrix_h -#define LightMatrix_h - -#include -#if defined(__AVR__) || (__avr__) || (__IMXRT1062__) -#include -#endif - -#include "../EventDispatcher/Event.h" -#include "Matrix.h" - -// Number of consistent data samples required for matrix update -#define SINGLE_UPDATE_CONS 2 - -// local time interval, config A [us] -#define TTAG_INT_A (250) - -class LightMatrix : public Matrix { - public: - LightMatrix(EventDispatcher* eD, byte pf) : Matrix(eD, pf) { - lightMatrixInstance = this; - - eventSource = EVENT_SOURCE_LIGHT; - maxChangesPerRead = MAX_FIELDS_REGISTERED; - - pinMode(5, INPUT); - pinMode(6, OUTPUT); - pinMode(7, OUTPUT); - -#if defined(__AVR__) || (__avr__) || (__IMXRT1062__) - Timer1.initialize(TTAG_INT_A); -#endif - } - - void start(); - - void stop(); - - static void _readRow(); - - uint16_t sampleInput(); - - bool updateValid(byte inCol, byte inRowMask); - - void updateCol(uint32_t col, byte rowMask); - - // remember the last row samples - volatile byte lastRowMask[8] = {0}; - volatile byte consistentSamples[8] = {0}; - - private: - static LightMatrix* lightMatrixInstance; -}; - -#endif diff --git a/src/InputDevices/Matrix.cpp b/src/InputDevices/Matrix.cpp deleted file mode 100644 index 6f7486b..0000000 --- a/src/InputDevices/Matrix.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "Matrix.h" - -Matrix::Matrix(EventDispatcher* eD, byte pf) { - eventDispatcher = eD; - platform = pf; - - setLastColToRead(8); - - for (int i = 0; i < lastColToRead; i++) { - rows[i] = 0b00000000; - previousRows[i] = 0b00000000; - } -} - -void Matrix::setLastColToRead(byte last) { lastColToRead = last; } - -void Matrix::registerFieldAsEvent(byte row, byte column, byte number) { - if (registeredFieldsCounter < (MAX_FIELDS_REGISTERED - 1)) { - registeredFieldRowCol[++registeredFieldsCounter] = - word(row - 1, column - 1); - registeredFieldNum[registeredFieldsCounter] = number; - } -} - -void Matrix::registerAllFieldsAsEvent() { - registeredFieldsCounter = -1; - - if (platform == PLATFORM_WPC) { - for (byte col = 1; col <= lastColToRead; col++) { - for (byte row = 1; row <= 8; row++) { - registerFieldAsEvent(row, col, col * 10 + row); - } - } - } else if (platform == PLATFORM_DATA_EAST || platform == PLATFORM_SYS11) { - byte number = 0; - for (byte col = 1; col <= lastColToRead; col++) { - for (byte row = 1; row <= 8; row++) { - registerFieldAsEvent(row, col, ++number); - } - } - } -} - -void Matrix::update() { - if (updateDelay > 0) { - uint32_t ms = millis(); - - if (nextUpdate > ms) { - return; - } - - nextUpdate = ms + updateDelay; - } - - byte fieldNum[maxChangesPerRead] = {0}; - byte value[maxChangesPerRead] = {0}; - byte counter = 0; - - for (int col = 0; col < lastColToRead; col++) { - for (int row = 0; row < 8; row++) { - word row_col = word(row, col); - for (byte i = 0; i <= registeredFieldsCounter; i++) { - if (row_col == registeredFieldRowCol[i]) { - byte bit = 1 << row; - if ((rows[col] & bit) != (previousRows[col] & bit)) { - if (counter < maxChangesPerRead) { - fieldNum[counter] = registeredFieldNum[i]; - value[counter++] = (rows[col] & bit) ? 1 : 0; - } else { - // Too many changes, assume erroneous read. - return; - } - } - } - } - } - previousRows[col] = rows[col]; - } - - if (counter <= maxChangesPerRead) { - for (int i = 0; i < counter; i++) { - eventDispatcher->dispatch( - new Event(eventSource, word(0, fieldNum[i]), value[i])); - } - } -} - -void Matrix::print() { - Serial.print("Matrix "); - Serial.println(eventSource); - Serial.println(" 8 7 6 5 4 3 2 1"); - for (int i = 0; i < lastColToRead; i++) { - Serial.print(i + 1); - for (byte mask = 0x80; mask; mask >>= 1) { - Serial.print(mask & rows[i] ? " *" : " -"); - } - Serial.println(); - } -} diff --git a/src/InputDevices/Matrix.h b/src/InputDevices/Matrix.h deleted file mode 100644 index 9e10ee3..0000000 --- a/src/InputDevices/Matrix.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - Matrix.h - Created by Markus Kalkbrenner, 2020-2021. - - Play more pinball! -*/ - -// WPC matrix numbering: -// -// | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 -// ---+----+----+----+----+----+----+----+---- -// R1 | 11 | 21 | 31 | 41 | 51 | 61 | 71 | 81 -// ---+----+----+----+----+----+----+----+---- -// R2 | 12 | 22 | 32 | 42 | 52 | 62 | 72 | 82 -// ---+----+----+----+----+----+----+----+---- -// R3 | 13 | 23 | 33 | 43 | 53 | 63 | 73 | 83 -// ---+----+----+----+----+----+----+----+---- -// R4 | 14 | 24 | 34 | 44 | 54 | 64 | 74 | 84 -// ---+----+----+----+----+----+----+----+---- -// R5 | 15 | 25 | 35 | 45 | 55 | 65 | 75 | 85 -// ---+----+----+----+----+----+----+----+---- -// R6 | 16 | 26 | 36 | 46 | 56 | 66 | 76 | 86 -// ---+----+----+----+----+----+----+----+---- -// R7 | 17 | 27 | 37 | 47 | 57 | 67 | 77 | 87 -// ---+----+----+----+----+----+----+----+---- -// R8 | 18 | 28 | 38 | 48 | 58 | 68 | 78 | 88 - -// WPC matrix numbering (IJ, STTNG, TZ): -// -// | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 | C9 -// ---+----+----+----+----+----+----+----+----+---- -// R1 | 11 | 21 | 31 | 41 | 51 | 61 | 71 | 81 | 91 -// ---+----+----+----+----+----+----+----+----+---- -// R2 | 12 | 22 | 32 | 42 | 52 | 62 | 72 | 82 | 92 -// ---+----+----+----+----+----+----+----+----+---- -// R3 | 13 | 23 | 33 | 43 | 53 | 63 | 73 | 83 | 93 -// ---+----+----+----+----+----+----+----+----+---- -// R4 | 14 | 24 | 34 | 44 | 54 | 64 | 74 | 84 | 94 -// ---+----+----+----+----+----+----+----+----+---- -// R5 | 15 | 25 | 35 | 45 | 55 | 65 | 75 | 85 | 95 -// ---+----+----+----+----+----+----+----+----+---- -// R6 | 16 | 26 | 36 | 46 | 56 | 66 | 76 | 86 | 96 -// ---+----+----+----+----+----+----+----+----+---- -// R7 | 17 | 27 | 37 | 47 | 57 | 67 | 77 | 87 | 97 -// ---+----+----+----+----+----+----+----+----+---- -// R8 | 18 | 28 | 38 | 48 | 58 | 68 | 78 | 88 | 98 - -// DE matrix numbering: -// -// | C1 | C2 | C3 | C4 | C5 | C6 | C7 | C8 -// ---+----+----+----+----+----+----+----+---- -// R1 | 1 | 9 | 17 | 25 | 33 | 41 | 49 | 57 -// ---+----+----+----+----+----+----+----+---- -// R2 | 2 | 10 | 18 | 26 | 34 | 42 | 50 | 58 -// ---+----+----+----+----+----+----+----+---- -// R3 | 3 | 11 | 19 | 27 | 35 | 43 | 51 | 59 -// ---+----+----+----+----+----+----+----+---- -// R4 | 4 | 12 | 20 | 28 | 36 | 44 | 52 | 60 -// ---+----+----+----+----+----+----+----+---- -// R5 | 5 | 13 | 21 | 29 | 37 | 45 | 53 | 61 -// ---+----+----+----+----+----+----+----+---- -// R6 | 6 | 14 | 22 | 30 | 38 | 46 | 54 | 62 -// ---+----+----+----+----+----+----+----+---- -// R7 | 7 | 15 | 23 | 31 | 39 | 47 | 55 | 63 -// ---+----+----+----+----+----+----+----+---- -// R8 | 8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 - -// In case of 9 Columns on WPC the 9th column is only read every second run. - -#ifndef Matrix_h -#define Matrix_h - -#include "../EventDispatcher/Event.h" -#include "../EventDispatcher/EventDispatcher.h" -#include "../PPUC.h" - -#ifndef NUM_COLS -#define NUM_COLS 9 -#endif - -#ifndef MAX_FIELDS_REGISTERED -#define MAX_FIELDS_REGISTERED (NUM_COLS * 8) -#endif - -class Matrix { - public: - Matrix(EventDispatcher* eD, byte pf); - - virtual void start() = 0; - - virtual void stop() = 0; - - void update(); - - void print(); - - void setLastColToRead(byte lastColToRead); - - void registerFieldAsEvent(byte row, byte column, byte number); - - void registerAllFieldsAsEvent(); - - static void _readRow() {} - - volatile byte lastColToRead; - volatile byte rows[NUM_COLS]; - - protected: - EventDispatcher* eventDispatcher; - - char eventSource; - byte maxChangesPerRead = 6; - byte previousRows[NUM_COLS]; - - int registeredFieldsCounter = -1; - word registeredFieldRowCol[MAX_FIELDS_REGISTERED]; - byte registeredFieldNum[MAX_FIELDS_REGISTERED]; - - byte platform; - - byte updateDelay = 0; - uint32_t nextUpdate = 0; -}; - -#endif diff --git a/src/InputDevices/PIN2DMD.cpp b/src/InputDevices/PIN2DMD.cpp deleted file mode 100644 index 7b665e8..0000000 --- a/src/InputDevices/PIN2DMD.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "PIN2DMD.h" - -void PIN2DMD::setSerial(HardwareSerial &reference) { - hwSerial = (HardwareSerial *)&reference; - hwSerial->begin(57600); -} - -void PIN2DMD::update() { - if (hwSerial->available() > 2) { - byte deviceByte = hwSerial->read(); - if (debug) { - Serial.println(deviceByte, DEC); - } - if (deviceByte != 0) { - byte eventByte = hwSerial->read(); - if (debug) { - Serial.println(eventByte, DEC); - } - if (eventByte != 0) { - byte nullByte = hwSerial->read(); - if (debug) { - Serial.println(nullByte, DEC); - } - if (nullByte == 0) { - // Quick explanation: - // The PUP Player understands event IDs that are 8 bits long. But we - // assume that nobody needs that much events. But more than 255, which - // is the maximum value of 4 bits, are exceeded. The pack for STTNG is - // already very close to this limit. On the other hand we don’t really - // need a device ID as the will be the only Device attached to - // PIN2DMD. But as the device must must not be "0", we agreed on this - // pattern: The „hundreds“ of the decimal Device ID in PIN2DMD are the - // actual ID. So "100" means Device 1. - // ("200" aka Device 2 is not used at the moment and therefore - // ignored.) The other two digits are added as high byte to the event - // ID which itself is treated as low byte. - // - // Examples of decimal values to be entered in the PIN2DMD Editor: - // 100 187 => Device 1, Event 187 - // 143 187 => Device 1, Event 11195 (43 decimal is 101011 binary, 187 - // is 10111011, binary 101011 10111011 is 11195 decimal) 200 123 => - // Device 2, Event 123 (Device2 is currently not used) 243 187 => - // Device 2, Event 11195 (Device2 is currently not used) - // - // 100 255 => Device 1, Event 255 - // 101 001 => Device 1, Event 257 - // - // This looks complicated, but I consider this to be the smartest - // solution to close the gap between PIN2DMD 4bit event IDs and - // PUPPack 8bit event IDs that remains somehow „readable“ in the - // PIN2DMD Editor. - eventDispatcher->dispatch( - new Event(EVENT_SOURCE_DMD, - word((deviceByte & 0b1111111) - 100, eventByte))); - } - } - } - } -} - -void PIN2DMD::setDebug(bool value) { debug = value; } diff --git a/src/InputDevices/PIN2DMD.h b/src/InputDevices/PIN2DMD.h deleted file mode 100644 index 21ac6b6..0000000 --- a/src/InputDevices/PIN2DMD.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - PIN2DMD.h - Created by Markus Kalkbrenner, 2020-2021. - - Play more pinball! -*/ - -#ifndef PIN2DMD_h -#define PIN2DMD_h - -#include - -#include "../EventDispatcher/Event.h" -#include "../EventDispatcher/EventDispatcher.h" - -class PIN2DMD { - public: - PIN2DMD(EventDispatcher* eD) { eventDispatcher = eD; } - - void setSerial(HardwareSerial& reference); - - void update(); - - void setDebug(bool value); - - private: - EventDispatcher* eventDispatcher; - - HardwareSerial* hwSerial; - - bool debug = false; -}; - -#endif diff --git a/src/InputDevices/Solenoids.cpp b/src/InputDevices/Solenoids.cpp deleted file mode 100644 index 100479b..0000000 --- a/src/InputDevices/Solenoids.cpp +++ /dev/null @@ -1,209 +0,0 @@ -#include "Solenoids.h" - -Solenoids::Solenoids(int controllerType, EventDispatcher* ed) { - eventDispatcher = ed; - - if (controllerType == CONTROLLER_MEGA_ALL_INPUT) { - pins[0] = 8; - pins[1] = 9; - pins[2] = 10; - pins[3] = 11; - pins[4] = 12; - pins[5] = 13; - pins[6] = 30; - pins[7] = 31; - pins[8] = 32; - pins[9] = 33; - pins[10] = 34; - pins[11] = 35; - pins[12] = 36; - pins[13] = 37; - pins[14] = 38; - pins[15] = 39; - pins[16] = 40; - pins[17] = 41; - pins[18] = 42; - pins[19] = 43; - pins[20] = 44; - pins[21] = 45; - pins[22] = 46; - pins[23] = 47; - pins[24] = 48; - pins[25] = 49; - } - - for (int i = 0; i < NUM_PINS; i++) { - pinMode(pins[i], INPUT); - pinStates[i] = false; - previousPinStates[i] = false; - registeredNum[i] = 0; - } -} - -void Solenoids::update() { - for (int i = 0; i < NUM_PINS; i++) { - previousPinStates[i] = pinStates[i]; - pinStates[i] = digitalRead(pins[i]) == HIGH; - if ((registeredNum[i] != 0) && (previousPinStates[i] != pinStates[i])) { - eventDispatcher->dispatch(new Event( - EVENT_SOURCE_SOLENOID, word(0, registeredNum[i]), pinStates[i])); - } - } -} - -void Solenoids::registerJ3(byte pin, byte number) { - if (pin == 1) { - registeredNum[0] = number; - } else if (pin == 2) { - registeredNum[1] = number; - } else if (pin == 3) { - registeredNum[2] = number; - } else if (pin == 4) { - registeredNum[3] = number; - } else if (pin == 5) { - registeredNum[4] = number; - } - // 6 is key - else if (pin == 7) { - registeredNum[5] = number; - } -} - -void Solenoids::registerJ4(byte pin, byte number) { - if (pin == 1) { - registeredNum[0] = number; - } else if (pin == 2) { - registeredNum[1] = number; - } - // 3 is key - else if (pin == 4) { - registeredNum[3] = number; - } else if (pin == 5) { - registeredNum[4] = number; - } else if (pin == 6) { - registeredNum[2] = number; - } else if (pin == 7) { - registeredNum[5] = number; - } -} - -void Solenoids::registerJ122(byte pin, byte number) { - if (pin == 1) { - registeredNum[6] = number; - } else if (pin == 2) { - registeredNum[7] = number; - } else if (pin == 3) { - registeredNum[8] = number; - } else if (pin == 4) { - registeredNum[9] = number; - } else if (pin == 5) { - registeredNum[10] = number; - } else if (pin == 6) { - registeredNum[11] = number; - } - // 7 is key - else if (pin == 8) { - registeredNum[12] = number; - } else if (pin == 9) { - registeredNum[13] = number; - } -} - -void Solenoids::registerJ123(byte pin, byte number) { - if (pin == 1) { - registeredNum[6] = number; - } - // 2 is key - else if (pin == 3) { - registeredNum[7] = number; - } else if (pin == 4) { - registeredNum[8] = number; - } else if (pin == 5) { - registeredNum[9] = number; - } -} - -void Solenoids::registerJ124(byte pin, byte number) { - if (pin == 1) { - registeredNum[6] = number; - } else if (pin == 2) { - registeredNum[7] = number; - } else if (pin == 3) { - registeredNum[8] = number; - } - // 4 is key - else if (pin == 5) { - registeredNum[9] = number; - } -} - -void Solenoids::registerJ125(byte pin, byte number) { - if (pin == 1) { - registeredNum[14] = number; - } else if (pin == 2) { - registeredNum[15] = number; - } else if (pin == 3) { - registeredNum[16] = number; - } - // 4 is key - else if (pin == 5) { - registeredNum[17] = number; - } else if (pin == 6) { - registeredNum[18] = number; - } else if (pin == 7) { - registeredNum[19] = number; - } else if (pin == 8) { - registeredNum[20] = number; - } else if (pin == 9) { - registeredNum[21] = number; - } -} - -void Solenoids::registerJ126(byte pin, byte number) { - if (pin == 1) { - registeredNum[14] = number; - } else if (pin == 2) { - registeredNum[15] = number; - } else if (pin == 3) { - registeredNum[16] = number; - } else if (pin == 4) { - registeredNum[17] = number; - } else if (pin == 5) { - registeredNum[18] = number; - } else if (pin == 6) { - registeredNum[19] = number; - } else if (pin == 7) { - registeredNum[20] = number; - } else if (pin == 8) { - registeredNum[21] = number; - } - // 9 is key - else if (pin == 10) { - registeredNum[22] = number; - } else if (pin == 11) { - registeredNum[23] = number; - } else if (pin == 12) { - registeredNum[24] = number; - } else if (pin == 13) { - registeredNum[25] = number; - } -} - -void Solenoids::registerJ110(byte pin, byte number) {} - -void Solenoids::registerJ111(byte pin, byte number) {} - -void Solenoids::registerJ9(byte pin, byte number) {} - -void Solenoids::registerP11(byte pin, byte number) {} - -void Solenoids::registerP12(byte pin, byte number) {} - -// helps with debugging -void Solenoids::print() { - for (int i = 0; i < NUM_PINS; i++) { - Serial.print(pinStates[i]); - Serial.print(" "); - } - Serial.println(); -} diff --git a/src/InputDevices/Solenoids.h b/src/InputDevices/Solenoids.h deleted file mode 100644 index ed29d50..0000000 --- a/src/InputDevices/Solenoids.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Solenoids.h - Created by Markus Kalkbrenner, 2020-2021. - - Play more pinball! -*/ -#ifndef SOLENOIDS_h -#define SOLENOIDS_h - -#define NUM_PINS 26 - -#include "../EventDispatcher/Event.h" -#include "../EventDispatcher/EventDispatcher.h" -#include "../PPUC.h" - -class Solenoids { - public: - // Constructor - Solenoids(int controllerType, EventDispatcher* eD); - - // WPC - void registerJ3(byte pin, byte number); // A16100 8-Driver PCB Assembly - void registerJ4(byte pin, byte number); // A16100 8-Driver PCB Assembly - void registerJ122(byte pin, byte number); - void registerJ123(byte pin, byte number); - void registerJ124(byte pin, byte number); - void registerJ125(byte pin, byte number); - void registerJ126(byte pin, byte number); - - // WPC95 - void registerJ110(byte pin, byte number); - void registerJ111(byte pin, byte number); - - // Sega - void registerJ9(byte pin, byte number); - void registerP11(byte pin, byte number); - void registerP12(byte pin, byte number); - - void update(); - - void print(); - - private: - EventDispatcher* eventDispatcher; - - int pins[NUM_PINS]; - bool pinStates[NUM_PINS]; - byte previousPinStates[NUM_PINS]; - - byte registeredNum[NUM_PINS]; -}; - -#endif diff --git a/src/InputDevices/SwitchMatrix.cpp b/src/InputDevices/SwitchMatrix.cpp deleted file mode 100644 index 404c5dc..0000000 --- a/src/InputDevices/SwitchMatrix.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "SwitchMatrix.h" - -// see https://forum.arduino.cc/index.php?topic=398610.0 -SwitchMatrix* SwitchMatrix::switchMatrixInstance = NULL; - -void SwitchMatrix::start() { - attachInterrupt(digitalPinToInterrupt(CS_ODD), - SwitchMatrix::_readRowForOddColumn, RISING); -} - -void SwitchMatrix::stop() { - detachInterrupt(digitalPinToInterrupt(CS_ODD)); - detachInterrupt(digitalPinToInterrupt(CS_EVEN)); -} - -void SwitchMatrix::_readRowForOddColumn() { - // Serial.println("CS_ODD"); - switchMatrixInstance->readRow(CS_ODD); -} - -void SwitchMatrix::_readRowForEvenColumn() { - // Serial.println("CS_EVEN"); - switchMatrixInstance->readRow(CS_EVEN); -} - -void SwitchMatrix::readRow(int pin) { - // Immediately turn off further interrupts. - detachInterrupt(digitalPinToInterrupt(pin)); - - delayMicroseconds(rowReadDelay); - - if (pin == CS_ODD && digitalRead(CS_X) == LOW) { - // Serial.println("CS_X"); - columnCounter = 0; - } - - if (columnCounter >= 0 && columnCounter < lastColToRead) { - // Serial.println(switchMatrixInstance->columnCounter, DEC); - -#if defined(__AVR_ATmega2560__) - // Read row return at PIN 22 - 29 three times and use the majority of bits. - byte a = PINA; - delayMicroseconds(4); - byte b = PINA; - delayMicroseconds(4); - byte c = PINA; -#else - // The Switch Matrix adapter currently requires an Arduino. - byte a = 0; - byte b = 0; - byte c = 0; -#endif - - if (columnCounter > 0 || - // The first column is only valid, if CS_X is still LOW. Otherwise it's - // noise. - (columnCounter == 0 && digitalRead(CS_X) == LOW)) { - // Serial.println("READ"); - rows[columnCounter++] |= ((a & b) | (b & c) | (c & a)) ^ 0b11111111; - } else { - columnCounter = 255; - } - } - - if (columnCounter >= lastColToRead) { - columnCounter = 255; - } - - if (pin == CS_ODD && columnCounter >= 0 && columnCounter < lastColToRead) { - attachInterrupt(digitalPinToInterrupt(CS_EVEN), - SwitchMatrix::_readRowForEvenColumn, RISING); - } else { - attachInterrupt(digitalPinToInterrupt(CS_ODD), - SwitchMatrix::_readRowForOddColumn, RISING); - } -} diff --git a/src/InputDevices/SwitchMatrix.h b/src/InputDevices/SwitchMatrix.h deleted file mode 100644 index 497c3af..0000000 --- a/src/InputDevices/SwitchMatrix.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - SwitchMatrix.h. - Created by Markus Kalkbrenner, 2020-2021. - - Play more pinball! -*/ - -#ifndef SwitchMatrix_h -#define SwitchMatrix_h - -#include - -#include "../EventDispatcher/Event.h" -#include "../EventDispatcher/EventDispatcher.h" -#include "Matrix.h" - -#define CS_ODD 3 -#define CS_EVEN 2 -#define CS_X 4 - -class SwitchMatrix : public Matrix { - public: - SwitchMatrix(EventDispatcher* eD, byte pf) : Matrix(eD, pf) { - switchMatrixInstance = this; - - eventSource = EVENT_SOURCE_SWITCH; - - if (platform == PLATFORM_WPC) { - // Read rows some micro seconds after column strobe signal. - rowReadDelay = 4; - - // On WPC the switches are read every 2ms. Ensure that we have a complete - // read before sending next events. - updateDelay = 3; - } else if (platform == PLATFORM_DATA_EAST) { - // @todo - } else if (platform == PLATFORM_SYS11) { - // @todo - } - - maxChangesPerRead = 3; - - pinMode(CS_ODD, INPUT); - pinMode(CS_EVEN, INPUT); - pinMode(CS_X, INPUT); - - pinMode(22, INPUT); - pinMode(23, INPUT); - pinMode(24, INPUT); - pinMode(25, INPUT); - pinMode(26, INPUT); - pinMode(27, INPUT); - pinMode(28, INPUT); - pinMode(29, INPUT); - } - - void start(); - - void stop(); - - void readRow(int pin); - static void _readRowForOddColumn(); - static void _readRowForEvenColumn(); - - protected: - byte columnCounter = 255; - int rowReadDelay = 0; - - private: - static SwitchMatrix* switchMatrixInstance; -}; - -#endif diff --git a/src/PPUC.h b/src/PPUC.h index e46684e..1b0c5a3 100644 --- a/src/PPUC.h +++ b/src/PPUC.h @@ -7,19 +7,15 @@ #define PPUC_h #define FIRMWARE_VERSION_MAJOR 0 // X Digits -#define FIRMWARE_VERSION_MINOR 1 // Max 2 Digits +#define FIRMWARE_VERSION_MINOR 2 // Max 2 Digits #define FIRMWARE_VERSION_PATCH 0 // Max 2 Digits #include +#include "PPUCTimings.h" #include "PPUCPlatforms.h" -#define CONTROLLER_MEGA_ALL_INPUT 1 -#define CONTROLLER_TEENSY_OUTPUT 10 -#define CONTROLLER_TEENSY_OUTPUT_2 11 -#define CONTROLLER_PICO_OUTPUT 20 -#define CONTROLLER_NANO_PIN2DMD_OUTPUT 30 -#define CONTROLLER_16_8_1 40 +#define CONTROLLER_16_8_1 1 #include diff --git a/src/PPUCTimings.h b/src/PPUCTimings.h new file mode 100644 index 0000000..91b5929 --- /dev/null +++ b/src/PPUCTimings.h @@ -0,0 +1,17 @@ +/** + PPUCTimings.h + Created by Markus Kalkbrenner. +*/ + +#ifndef PPUC_TIMINGS_h +#define PPUC_TIMINGS_h + +#define WAIT_FOR_EFFECT_CONTROLLER_RESET 3000 // 3 seconds +#define WAIT_FOR_SERIAL_DEBUGGER_TIMEOUT 1000 // 1 second +#define WAIT_FOR_IO_BOARD_BOOT 1000 // 1 second + +#define WAIT_FOR_IO_BOARD_RESET \ + (WAIT_FOR_SERIAL_DEBUGGER_TIMEOUT + WAIT_FOR_EFFECT_CONTROLLER_RESET + \ + WAIT_FOR_IO_BOARD_BOOT) // 5 seconds + +#endif diff --git a/src/VisualPinball/PUPComLink.cpp b/src/VisualPinball/PUPComLink.cpp deleted file mode 100644 index 42ae5cd..0000000 --- a/src/VisualPinball/PUPComLink.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "PUPComLink.h" - -void PUPComLink::setSerial(HardwareSerial& reference) { - hwSerial = (HardwareSerial*)&reference; - hwSerial->begin(115200, SERIAL_8N1); -} - -void PUPComLink::handleEvent(Event* event) { - write(PUP_POST_EVENT_COMMAND, event->sourceId, event->eventId, event->value); -} - -void PUPComLink::postEvent(char msgtype, int msgindex, int msgvalue) { - write(PUP_POST_EVENT_COMMAND, msgtype, word(msgindex), word(msgvalue)); -} - -void PUPComLink::customCommand(char msgtype, int msgindex, int msgvalue) { - write(PUP_CUSTOM_COMMAND, msgtype, word(msgindex), word(msgvalue)); -} - -void PUPComLink::setVolume(int volume) { - write(PUP_CUSTOM_COMMAND, PUP_CUSTOM_VOLUME, word(0), word(volume)); -} - -void PUPComLink::startBatch(int id) { - write(PUP_CUSTOM_COMMAND, PUP_CUSTOM_BATCH, word(0), word(id)); -} - -void PUPComLink::restart() { - write(PUP_CUSTOM_COMMAND, PUP_CUSTOM_RESTART, word(0), word(1)); -} - -void PUPComLink::shutdown() { - write(PUP_CUSTOM_COMMAND, PUP_CUSTOM_SHUTDOWN, word(0), word(1)); -} - -int PUPComLink::available() { return hwSerial->available(); } - -byte PUPComLink::read() { return hwSerial->read(); } - -void PUPComLink::write(byte command, char msgtype, word msgindex, - word msgvalue) { - // Send to PUP Com Link. But only if there's room left in write buffer. - // Otherwise the program will be blocked. The buffer gets full if the data is - // not fetched by PUP Com Link for any reason. - // @todo Possible optimization to check hwSerial->availableForWrite() >= 8 - // failed on Arduino for unknown reason. - // if (hwSerial->availableForWrite() >= 8) { - byte msg[8]; - - msg[0] = command; - msg[1] = msgtype; - msg[2] = highByte(msgindex); - msg[3] = lowByte(msgindex); - msg[4] = highByte(msgvalue); - msg[5] = lowByte(msgvalue); - msg[6] = msg[0] ^ msg[1] ^ msg[2] ^ msg[3] ^ msg[4] ^ msg[5]; - msg[7] = PUP_EOF; - - hwSerial->write(msg, 8); - //} -} diff --git a/src/VisualPinball/PUPComLink.h b/src/VisualPinball/PUPComLink.h deleted file mode 100644 index e894328..0000000 --- a/src/VisualPinball/PUPComLink.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - PUPComLink.h - Created by Markus Kalkbrenner, 2020-2021. - - Play more pinball! -*/ - -#ifndef PUPCOMLINK_h -#define PUPCOMLINK_h - -#include - -#include "../EventDispatcher/Event.h" -#include "../EventDispatcher/EventDispatcher.h" - -#define PUP_POST_EVENT_COMMAND 80 // "P" -#define PUP_CUSTOM_COMMAND 67 // "C" -#define PUP_EOF 13 -#define PUP_VALUE_ON 1 -#define PUP_CUSTOM_VOLUME 86 // "V" -#define PUP_CUSTOM_BATCH 66 // "B" -#define PUP_CUSTOM_RESTART 82 // "R" -#define PUP_CUSTOM_SHUTDOWN 83 // "S" - -class PUPComLink : public EventListener { - public: - PUPComLink() {} - - void setSerial(HardwareSerial& reference); - - void handleEvent(Event* event); - - void handleEvent(ConfigEvent* event) {} - - void postEvent(char msgtype, int msgindex, int msgvalue); - - void customCommand(char msgtype, int msgindex, int msgvalue); - - void setVolume(int volume); - - /** - * Starts "id".bat in the "pinupsystem\launch" folder - */ - void startBatch(int id); - - void restart(); - - void shutdown(); - - int available(); - - byte read(); - - protected: - void write(byte command, char msgtype, word msgindex, word msgvalue); - - HardwareSerial* hwSerial; -}; - -#endif diff --git a/src/VisualPinball/VPXComLink.cpp b/src/VisualPinball/VPXComLink.cpp deleted file mode 100644 index 19fbe2e..0000000 --- a/src/VisualPinball/VPXComLink.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#if defined(__IMXRT1062__) // Teensy 4.1 -#include -#endif - -#include "VPXComLink.h" - -void VPXComLink::update() { - if (Serial.available() >= 6) { - byte startByte = Serial.read(); - if (startByte == 255) { - byte sourceId = Serial.read(); - if (sourceId != 0) { - word eventId = word(Serial.read(), Serial.read()); - if (eventId != 0) { - byte value = Serial.read(); - byte stopByte = Serial.read(); - if (stopByte == 255) { - eventDispatcher->dispatch( - new Event((char)sourceId, eventId, value)); - } - } - } - } - } -} - -void VPXComLink::handleEvent(Event* event) { - // Add this to platformio.ini to get a Keyboard: - // build_flags = -D USB_SERIAL_HID -#ifdef Keyboard - if (event->sourceId == EVENT_SOURCE_SWITCH) { - if (platform == PLATFORM_SYS11) { - switch (event->eventId) { - case 63: - if (event->value) { - Keyboard.press(KEY_END); - } else { - Keyboard.release(KEY_END); - } - break; - case 64: - if (event->value) { - Keyboard.press(KEY_PAGE_UP); - } else { - Keyboard.release(KEY_PAGE_UP); - } - break; - } - } - } -#endif -} diff --git a/src/VisualPinball/VPXComLink.h b/src/VisualPinball/VPXComLink.h deleted file mode 100644 index c3a3b90..0000000 --- a/src/VisualPinball/VPXComLink.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - VPXComLink.h - Created by Markus Kalkbrenner, 2021. - - Play more pinball! -*/ - -#ifndef VPXCOMLINK_h -#define VPXCOMLINK_h - -#include - -#include "../EventDispatcher/Event.h" -#include "../EventDispatcher/EventDispatcher.h" -#include "../EventDispatcher/EventListener.h" - -class VPXComLink : public EventListener { - public: - VPXComLink(EventDispatcher* eD, byte pf) { - eventDispatcher = eD; - platform = pf; - } - - void update(); - - void handleEvent(Event* event); - - void handleEvent(ConfigEvent* event) {} - - private: - EventDispatcher* eventDispatcher; - - byte platform; -}; - -#endif diff --git a/test/IO_16_8_1/src/main.cpp b/src/main.cpp similarity index 92% rename from test/IO_16_8_1/src/main.cpp rename to src/main.cpp index 5dbdec6..df14b31 100644 --- a/test/IO_16_8_1/src/main.cpp +++ b/src/main.cpp @@ -1,16 +1,15 @@ -// Markus Kalkbrenner 2023 +// Markus Kalkbrenner 2023-2025 -#include +// set to officially supported 200MHz clock +// @see SYS_CLK_MHZ https://github.com/raspberrypi/pico-sdk/releases/tag/2.1.1 +#define SYS_CLK_MHZ 200 #include "EffectsController.h" #include "EventDispatcher/CrossLinkDebugger.h" #include "IOBoardController.h" +#include "PPUC.h" #include "RPi_Pico_TimerInterrupt.h" -// set to officially supported 200MHz clock -// @see SYS_CLK_MHZ https://github.com/raspberrypi/pico-sdk/releases/tag/2.1.1 -#define SYS_CLK_MHZ 200 - IOBoardController ioBoardController(CONTROLLER_16_8_1); // Platform will be adjusted by ConfigEvent. @@ -43,11 +42,12 @@ bool core_0_initilized = false; void setup() { // Overclock according to Raspberry Pi Pico SDK recommendations. - set_sys_clock_khz(SYS_CLK_MHZ * 1000, true); + set_sys_clock_khz(SYS_CLK_KHZ, true); - uint32_t timeout = millis() + 2000; + uint32_t timeout = millis() + WAIT_FOR_SERIAL_DEBUGGER_TIMEOUT; Serial.begin(115200); + // Wait for a serial connection of a debugger via USB. // The Pico implements USB itself so special care must be taken. Use // while(!Serial){} in the setup() code before printing anything so that it // waits for the USB connection to be established. @@ -60,6 +60,8 @@ void setup() { ioBoardController.debug(); delay(10); ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); + } else { + Serial.end(); } core_0_initilized = true; diff --git a/test/EffectController/platformio.ini b/test/EffectController/platformio.ini deleted file mode 100644 index 7019959..0000000 --- a/test/EffectController/platformio.ini +++ /dev/null @@ -1,22 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html - -[env:teensy41] -platform = teensy -board = teensy41 -framework = arduino -lib_extra_dirs = - ../.. -lib_deps = - mkalkbrenner/WavePWM - mkalkbrenner/WS2812Serial - kitesurfer1404/WS2812FX - thomasfredericks/Bounce2 - https://github.com/PaulStoffregen/TimerOne.git#master diff --git a/test/EffectController/src/main.cpp b/test/EffectController/src/main.cpp deleted file mode 100644 index f87a1f5..0000000 --- a/test/EffectController/src/main.cpp +++ /dev/null @@ -1,128 +0,0 @@ -// Markus Kalkbrenner 2022 - -#include -#include - -#define PPUC_NUM_LEDS_1 60 -#define PPUC_LED_TYPE_1 SK6812_GBRW -#define PPUC_NUM_LEDS_2 1 -#define PPUC_LED_TYPE_2 WS2812_GRB -#define PPUC_NUM_LEDS_3 1000 -#define PPUC_LED_TYPE_3 WS2812_GRB -#define PPUC_NUM_LEDS_4 23 -#define PPUC_LED_TYPE_4 WS2812_GRB -#define PPUC_NUM_LEDS_5 18 -#define PPUC_LED_TYPE_5 WS2812_GRB -#define PPUC_NUM_LEDS_6 60 -#define PPUC_LED_TYPE_6 WS2812_GRB -#define PPUC_NUM_LEDS_7 60 -#define PPUC_LED_TYPE_7 WS2812_GRB - -#include - -EffectsController effectsController(CONTROLLER_TEENSY_OUTPUT, PLATFORM_SYS11); - -void setup() { - // Debug - Serial.begin(9600); // USB is always 12 Mbit/sec - - effectsController.eventDispatcher()->addListener(new CrossLinkDebugger()); - - // Setup - effectsController.eventDispatcher()->setCrossLinkSerial(Serial8); - - effectsController.createCombinedGiAndLightMatrixWs2812FXDevice(7); - - effectsController.setBrightness(1, 64); - effectsController.setBrightness(7, 128); - //effectsController.attachBrightnessControl(7, 1); - - effectsController.giAndLightMatrix(7)->setHeatUp(40); - effectsController.giAndLightMatrix(7)->setAfterGlow(280); - - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(1, 1, ORANGE); // HOLD - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(2, 2, ORANGE); // BONUS - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(3, 3, ORANGE); // DOUBLE - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(4, 4, ORANGE); // SCORES - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(5, 5, ORANGE); // CYCLONE 50K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(6, 6, ORANGE); // CYCLONE 100K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(7, 7, ORANGE); // CYCLONE Gate Bonis - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(8, 8, ORANGE); // RIDE THE COMET (on ramp) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(9, 9, RED); // W/L SCORE FERRIS WHEEL BONUS - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(10, 10, ORANGE); // ADV. "X" - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(11, 11, ORANGE); // Balloon 25K (Ducks) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(12, 12, ORANGE); // Balloon 50K (Ducks) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(13, 13, ORANGE); // Balloon LITES EX. BALL (Ducks) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(14, 14, ORANGE); // 1 (Gate Lane) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(15, 15, ORANGE); // 2 (Gate Lane) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(16, 16, RED); // 3 (Gate Lane) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(17, 17, RED); // RIDE AGAIN - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(18, 18, RED); // SPINS MYSTERY WHEEL - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(19, 19, WHITE); // Ducks (top) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(20, 20, WHITE); // Ducks (mid) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(21, 21, WHITE); // Ducks (bottom) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(22, 22, RED); // Ball Toss (top) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(23, 23, YELLOW); // Ball Toss (mid) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(24, 24, WHITE); // Ball Toss (bottom) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(25, 25, YELLOW); // EXTRA BALL Left Outlane - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(26, 26, YELLOW); // EXTRA BALL Right Outlane - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(27, 27, YELLOW); // COMET 20K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(28, 28, YELLOW); // COMET 40K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(29, 29, YELLOW); // COMET 60K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(30, 30, RED); // COMET 80K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(31, 31, RED); // COMET 100K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(32, 32, WHITE); // COMET 1 Million - - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(49, 33, YELLOW); // 2X - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(50, 34, YELLOW); // 7X - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(51, 35, YELLOW); // 6X - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(52, 36, WHITE); // 5X - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(53, 37, YELLOW); // 4X - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(54, 38, YELLOW); // 3X - - // Test Buttons - effectsController.addEffect( - new LedBlinkEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_SWITCH, 201), - 1, // priority - 5, // repeat - 0 // mode - ); - - effectsController.addEffect( - new NullEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_SWITCH, 202), - 2, // priority - 0, // repeat - 0 // mode - ); - - effectsController.addEffect( - new LedBlinkEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_SWITCH, 203), - 1, // priority - 5, // repeat - 0 // mode - ); - - // Controller start - effectsController.addEffect( - new NullEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_SWITCH, 204), - 2, // priority - 0, // repeat - 0 // mode - ); - - // Start - effectsController.start(); - //effectsController.generalIllumintationWPC()->start(); -} - -void loop() { - effectsController.update(); -} diff --git a/test/EffectController/test/README b/test/EffectController/test/README deleted file mode 100644 index b94d089..0000000 --- a/test/EffectController/test/README +++ /dev/null @@ -1,11 +0,0 @@ - -This directory is intended for PlatformIO Unit Testing and project tests. - -Unit Testing is a software testing method by which individual units of -source code, sets of one or more MCU program modules together with associated -control data, usage procedures, and operating procedures, are tested to -determine whether they are fit for use. Unit testing finds problems early -in the development cycle. - -More information about PlatformIO Unit Testing: -- https://docs.platformio.org/page/plus/unit-testing.html diff --git a/test/EffectControllerPico/platformio.ini b/test/EffectControllerPico/platformio.ini deleted file mode 100644 index 0f288f4..0000000 --- a/test/EffectControllerPico/platformio.ini +++ /dev/null @@ -1,24 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html - -[env:pico] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git -board = pico -framework = arduino -board_build.core = earlephilhower -board_build.filesystem_size = 0.5m -lib_extra_dirs = - ../.. -lib_deps = - mkalkbrenner/WavePWM - kitesurfer1404/WS2812FX - Bounce2 - Adafruit_NeoPixel - diff --git a/test/EffectControllerPico/src/main.cpp b/test/EffectControllerPico/src/main.cpp deleted file mode 100644 index d8cec8a..0000000 --- a/test/EffectControllerPico/src/main.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// Markus Kalkbrenner 2022 - -#include -#include - -#define PPUC_NUM_LEDS_1 60 -#define PPUC_LED_TYPE_1 SK6812_GBRW -#define PPUC_NUM_LEDS_2 1 -#define PPUC_LED_TYPE_2 WS2812_GRB -#define PPUC_NUM_LEDS_3 1000 -#define PPUC_LED_TYPE_3 WS2812_GRB -#define PPUC_NUM_LEDS_4 23 -#define PPUC_LED_TYPE_4 WS2812_GRB -#define PPUC_NUM_LEDS_5 18 -#define PPUC_LED_TYPE_5 WS2812_GRB -#define PPUC_NUM_LEDS_6 60 -#define PPUC_LED_TYPE_6 WS2812_GRB -#define PPUC_NUM_LEDS_7 60 -#define PPUC_LED_TYPE_7 WS2812_GRB - -#include - -EffectsController effectsController(CONTROLLER_PICO_OUTPUT, PLATFORM_LIBPINMAME); - -void setup() { - // Setup - effectsController.eventDispatcher()->setCrossLinkSerial(Serial); - - effectsController.createCombinedGiAndLightMatrixWs2812FXDevice(7); - - effectsController.setBrightness(1, 64); - effectsController.setBrightness(7, 128); - //effectsController.attachBrightnessControl(7, 1); - - effectsController.giAndLightMatrix(7)->setHeatUp(40); - effectsController.giAndLightMatrix(7)->setAfterGlow(280); - - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(1, 1, ORANGE); // HOLD - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(2, 2, ORANGE); // BONUS - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(3, 3, ORANGE); // DOUBLE - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(4, 4, ORANGE); // SCORES - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(5, 5, ORANGE); // CYCLONE 50K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(6, 6, ORANGE); // CYCLONE 100K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(7, 7, ORANGE); // CYCLONE Gate Bonis - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(8, 8, ORANGE); // RIDE THE COMET (on ramp) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(9, 9, RED); // W/L SCORE FERRIS WHEEL BONUS - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(10, 10, ORANGE); // ADV. "X" - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(11, 11, ORANGE); // Balloon 25K (Ducks) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(12, 12, ORANGE); // Balloon 50K (Ducks) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(13, 13, ORANGE); // Balloon LITES EX. BALL (Ducks) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(14, 14, ORANGE); // 1 (Gate Lane) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(15, 15, ORANGE); // 2 (Gate Lane) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(16, 16, RED); // 3 (Gate Lane) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(17, 17, RED); // RIDE AGAIN - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(18, 18, RED); // SPINS MYSTERY WHEEL - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(19, 19, WHITE); // Ducks (top) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(20, 20, WHITE); // Ducks (mid) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(21, 21, WHITE); // Ducks (bottom) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(22, 22, RED); // Ball Toss (top) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(23, 23, YELLOW); // Ball Toss (mid) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(24, 24, WHITE); // Ball Toss (bottom) - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(25, 25, YELLOW); // EXTRA BALL Left Outlane - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(26, 26, YELLOW); // EXTRA BALL Right Outlane - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(27, 27, YELLOW); // COMET 20K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(28, 28, YELLOW); // COMET 40K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(29, 29, YELLOW); // COMET 60K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(30, 30, RED); // COMET 80K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(31, 31, RED); // COMET 100K - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(32, 32, WHITE); // COMET 1 Million - - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(49, 33, YELLOW); // 2X - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(50, 34, YELLOW); // 7X - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(51, 35, YELLOW); // 6X - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(52, 36, WHITE); // 5X - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(53, 37, YELLOW); // 4X - effectsController.giAndLightMatrix(7)->assignLedToLightMatrixSYS11(54, 38, YELLOW); // 3X - - // Test Buttons - effectsController.addEffect( - new LedBlinkEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_SWITCH, 201), - 1, // priority - 5, // repeat - 0 // mode - ); - - effectsController.addEffect( - new NullEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_SWITCH, 202), - 2, // priority - 0, // repeat - 0 // mode - ); - - effectsController.addEffect( - new LedBlinkEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_SWITCH, 203), - 1, // priority - 5, // repeat - 0 // mode - ); - - // Controller start - effectsController.addEffect( - new NullEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_SWITCH, 204), - 2, // priority - 0, // repeat - 0 // mode - ); - - // Start - effectsController.start(); - //effectsController.generalIllumintationWPC()->start(); -} - -void loop() { - effectsController.update(); -} diff --git a/test/EffectControllerPico/test/README b/test/EffectControllerPico/test/README deleted file mode 100644 index b94d089..0000000 --- a/test/EffectControllerPico/test/README +++ /dev/null @@ -1,11 +0,0 @@ - -This directory is intended for PlatformIO Unit Testing and project tests. - -Unit Testing is a software testing method by which individual units of -source code, sets of one or more MCU program modules together with associated -control data, usage procedures, and operating procedures, are tested to -determine whether they are fit for use. Unit testing finds problems early -in the development cycle. - -More information about PlatformIO Unit Testing: -- https://docs.platformio.org/page/plus/unit-testing.html diff --git a/test/IOBoardController/platformio.ini b/test/IOBoardController/platformio.ini deleted file mode 100644 index bb55bef..0000000 --- a/test/IOBoardController/platformio.ini +++ /dev/null @@ -1,24 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html - -[env:pico] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git -board = pico -framework = arduino -board_build.core = earlephilhower -board_build.filesystem_size = 0.5m -build_flags = - -D PICO_STDIO_USB ; enable stdio over USB -lib_extra_dirs = - ../.. -lib_deps = - mkalkbrenner/WavePWM - kitesurfer1404/WS2812FX - Bounce2 diff --git a/test/IOBoardController/src/main.cpp b/test/IOBoardController/src/main.cpp deleted file mode 100644 index 4ea1fb1..0000000 --- a/test/IOBoardController/src/main.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// Markus Kalkbrenner 2022 - -#include - -#include "EffectsController.h" -#include "IOBoardController.h" - -IOBoardController ioBoardController(CONTROLLER_16_8_1); -EffectsController effectsController(CONTROLLER_16_8_1, PLATFORM_LIBPINMAME); - -void setup() { - ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); -} - -void setup1() {} - -void loop() { - ioBoardController.update(); - // Serial.println(16 - ((int) (analogRead(28) + 30) / 60)); -} - -void loop1() { effectsController.update(); } diff --git a/test/IOBoardController/test/README b/test/IOBoardController/test/README deleted file mode 100644 index b94d089..0000000 --- a/test/IOBoardController/test/README +++ /dev/null @@ -1,11 +0,0 @@ - -This directory is intended for PlatformIO Unit Testing and project tests. - -Unit Testing is a software testing method by which individual units of -source code, sets of one or more MCU program modules together with associated -control data, usage procedures, and operating procedures, are tested to -determine whether they are fit for use. Unit testing finds problems early -in the development cycle. - -More information about PlatformIO Unit Testing: -- https://docs.platformio.org/page/plus/unit-testing.html diff --git a/test/IO_16_8_1/test/README b/test/IO_16_8_1/test/README deleted file mode 100644 index b94d089..0000000 --- a/test/IO_16_8_1/test/README +++ /dev/null @@ -1,11 +0,0 @@ - -This directory is intended for PlatformIO Unit Testing and project tests. - -Unit Testing is a software testing method by which individual units of -source code, sets of one or more MCU program modules together with associated -control data, usage procedures, and operating procedures, are tested to -determine whether they are fit for use. Unit testing finds problems early -in the development cycle. - -More information about PlatformIO Unit Testing: -- https://docs.platformio.org/page/plus/unit-testing.html diff --git a/test/IO_16_8_1_ouput_test/platformio.ini b/test/IO_16_8_1_ouput_test/platformio.ini deleted file mode 100644 index 647bd04..0000000 --- a/test/IO_16_8_1_ouput_test/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -default_envs = pico - -[env:pico] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git -board = pico -framework = arduino -board_build.core = earlephilhower -board_build.filesystem_size = 0.5m -monitor_speed = 115200 -build_flags = - -D PICO_STDIO_USB ; enable stdio over USB -lib_extra_dirs = - ../.. -lib_deps = - mkalkbrenner/WavePWM - kitesurfer1404/WS2812FX - Bounce2 diff --git a/test/IO_16_8_1_ouput_test/src/main.cpp b/test/IO_16_8_1_ouput_test/src/main.cpp deleted file mode 100644 index 67eb0e4..0000000 --- a/test/IO_16_8_1_ouput_test/src/main.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Markus Kalkbrenner 2023 - -#include - -bool state = 0; - -void setup() { - pinMode(19, OUTPUT); - pinMode(20, OUTPUT); - pinMode(21, OUTPUT); - pinMode(22, OUTPUT); - pinMode(23, OUTPUT); - pinMode(24, OUTPUT); - pinMode(26, OUTPUT); - pinMode(27, OUTPUT); -} - -void loop() { - digitalWrite(19, state); - digitalWrite(20, state); - digitalWrite(21, state); - digitalWrite(22, state); - digitalWrite(23, state); - digitalWrite(24, state); - digitalWrite(26, state); - digitalWrite(27, state); - - state = !state; - - delay(1000); -} diff --git a/test/InputController/platformio.ini b/test/InputController/platformio.ini deleted file mode 100644 index 30888cd..0000000 --- a/test/InputController/platformio.ini +++ /dev/null @@ -1,21 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html - -[env:megaatmega2560] -platform = atmelavr -framework = arduino -board = megaatmega2560 -lib_extra_dirs = - ../.. -lib_deps = - mkalkbrenner/WavePWM - kitesurfer1404/WS2812FX - thomasfredericks/Bounce2 - https://github.com/PaulStoffregen/TimerOne.git#master diff --git a/test/InputController/src/main.cpp b/test/InputController/src/main.cpp deleted file mode 100644 index b2c9739..0000000 --- a/test/InputController/src/main.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Markus Kalkbrenner 2022 - -#include -#include -#include - -InputController inputController(CONTROLLER_MEGA_ALL_INPUT, PLATFORM_WPC); - -void setup() { - inputController.pupComLink()->setSerial(Serial); - inputController.pin2Dmd()->setSerial(Serial1); - inputController.eventDispatcher()->setCrossLinkSerial(Serial3); - - // inputController.switchMatrix()->setLastColToRead(9); - inputController.switchMatrix()->registerFieldAsEvent(3, 1, - 13); // Start Button - inputController.switchMatrix()->registerFieldAsEvent(7, 2, - 27); // Ball Shooter - inputController.switchMatrix()->registerFieldAsEvent(8, 2, - 28); // Rocket Kicker - inputController.switchMatrix()->registerFieldAsEvent(1, 3, 31); // Bumper - inputController.switchMatrix()->registerFieldAsEvent(2, 3, 32); // Bumper - inputController.switchMatrix()->registerFieldAsEvent(3, 3, 33); // Bumper - inputController.switchMatrix()->registerFieldAsEvent(1, 6, - 61); // Lower Skill - inputController.switchMatrix()->registerFieldAsEvent(2, 6, - 62); // Center Skill - inputController.switchMatrix()->registerFieldAsEvent(3, 6, - 63); // Upper Skill - - inputController.lightMatrix()->registerAllFieldsAsEvent(); - - inputController.solenoids()->registerJ125(1, 17); // Flasher Bumpers - inputController.solenoids()->registerJ125(2, 18); // Flasher Power Payoff - inputController.solenoids()->registerJ125(3, 19); // Flasher Mini-Playfield - inputController.solenoids()->registerJ125(5, 20); // Flasher Upper Left Ramp - inputController.solenoids()->registerJ125(6, 21); // Flasher Left Magnet - inputController.solenoids()->registerJ125(8, - 23); // Flasher Lower Right Magnet - inputController.solenoids()->registerJ125(9, 24); // Flasher Gumball Motor - - inputController.solenoids()->registerJ124(1, 25); // Left Mini Magnet - inputController.solenoids()->registerJ124(2, 26); // Right Mini Magnet - inputController.solenoids()->registerJ124(3, 27); // Left Ramp Diverter - inputController.solenoids()->registerJ124(5, 28); // Inside Ramp - - inputController.eventDispatcher()->addListener(new CrossLinkDebugger()); - inputController.eventDispatcher()->addListener(inputController.pupComLink(), - EVENT_SOURCE_ANY); - - inputController.switchMatrix()->start(); - inputController.lightMatrix()->start(); -} - -void loop() { - // read data - inputController.pin2Dmd()->update(); - inputController.switchMatrix()->update(); - inputController.lightMatrix()->update(); - inputController.solenoids()->update(); - inputController.testButtons()->update(); - - // handle data - inputController.eventDispatcher()->update(); -} diff --git a/test/InputController/test/README b/test/InputController/test/README deleted file mode 100644 index e69de29..0000000 diff --git a/test/NanoController/platformio.ini b/test/NanoController/platformio.ini deleted file mode 100644 index 30888cd..0000000 --- a/test/NanoController/platformio.ini +++ /dev/null @@ -1,21 +0,0 @@ -; PlatformIO Project Configuration File -; -; Build options: build flags, source filter -; Upload options: custom upload port, speed and extra flags -; Library options: dependencies, extra library storages -; Advanced options: extra scripting -; -; Please visit documentation for the other options and examples -; https://docs.platformio.org/page/projectconf.html - -[env:megaatmega2560] -platform = atmelavr -framework = arduino -board = megaatmega2560 -lib_extra_dirs = - ../.. -lib_deps = - mkalkbrenner/WavePWM - kitesurfer1404/WS2812FX - thomasfredericks/Bounce2 - https://github.com/PaulStoffregen/TimerOne.git#master diff --git a/test/NanoController/src/main.cpp b/test/NanoController/src/main.cpp deleted file mode 100644 index 0eee5e2..0000000 --- a/test/NanoController/src/main.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - Created by Markus Kalkbrenner. -*/ - -#include - -#define PPUC_CONTROLLER CONTROLLER_NANO_PIN2DMD_OUTPUT -#define PPUC_NUM_LEDS_1 40 -#define PPUC_LED_TYPE_1 WS2812_GRB - -#include -#include - -EffectsController effectsController(PPUC_CONTROLLER, PLATFORM_DATA_EAST); -InputController inputController(PPUC_CONTROLLER, PLATFORM_DATA_EAST, - effectsController.eventDispatcher()); - -void setup() { - inputController.pin2Dmd()->setSerial(Serial); - - effectsController.createCombinedGiAndLightMatrixWs2812FXDevice(1); - // effectsController.setBrightness(1, 128); - - effectsController.attachBrightnessControl(1, 1); - - effectsController.giAndLightMatrix(1)->setHeatUp(40); - effectsController.giAndLightMatrix(1)->setAfterGlow(280); - - effectsController.giAndLightMatrix(1)->assignLedRangeToGiString(1, 0, 39); - - effectsController.addEffect(new WS2812FXEffect(FX_MODE_STATIC, WHITE, 0, 0), - effectsController.giAndLightMatrix(1), - new Event(EVENT_SOURCE_EFFECT, 1, 255), - 1, // priority - 0, // repeat - -1 // mode - ); - - effectsController.addEffect(new LedBlinkEffect(), - effectsController.ledBuiltInDevice(), - new Event(EVENT_SOURCE_EFFECT, 1, 255), - 1, // priority - 50, // repeat - -1 // mode - ); - - effectsController.start(); -} - -void loop() { - inputController.pin2Dmd()->update(); - - // The effectController also calls update() on the eventDispatcher. - effectsController.update(); -} diff --git a/test/NanoController/test/README b/test/NanoController/test/README deleted file mode 100644 index e69de29..0000000 From a355e98c01728a804ff7d725c0076e96c7195eab Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 15 Nov 2025 21:20:57 +0100 Subject: [PATCH 082/102] removed legacy stuff from GI and Light Matrix. Removed 3 LEDs per number limit. --- .github/workflows/io-bords.yml | 2 - ...CombinedGiAndLightMatrixWS2812FXDevice.cpp | 408 +++++------------- .../CombinedGiAndLightMatrixWS2812FXDevice.h | 191 +++++--- src/EffectsController.cpp | 20 +- src/PPUC.h | 2 - 5 files changed, 234 insertions(+), 389 deletions(-) diff --git a/.github/workflows/io-bords.yml b/.github/workflows/io-bords.yml index 8c2429c..bb7f4e2 100644 --- a/.github/workflows/io-bords.yml +++ b/.github/workflows/io-bords.yml @@ -81,12 +81,10 @@ jobs: - name: Run PlatformIO run: | - cd test/${{ matrix.controller }} pio run - name: Create UF2 file (using elf2uf2) run: | - cd test/${{ matrix.controller }} ELF_FILE=$(find .pio/build/ -name "*.elf" | head -n 1) echo "Found ELF file: $ELF_FILE" elf2uf2 "$ELF_FILE" "${ELF_FILE%.elf}.uf2" diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp index 2479c5a..45a9375 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.cpp @@ -12,118 +12,13 @@ void CombinedGiAndLightMatrixWS2812FXDevice::off() { reset(); } -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToGiString( - uint8_t giString, int16_t led) { - assignLedToGiString(giString, led, ULTRAWHITE); -} - -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToGiString( - uint8_t giString, int16_t led, uint32_t color) { - if (numLEDsGI[--giString] < _MAX_LEDS_GI_STRING) { - ledGIPositions[giString][numLEDsGI[giString]] = led; - ledGIColors[giString][numLEDsGI[giString]++] = color; - } -} - -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedRangeToGiString( - uint8_t giString, int16_t first, int16_t last) { - for (int16_t i = first; i <= last; i++) { - assignLedToGiString(giString, i); - } -} - -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrix( - uint8_t column, uint8_t row, int16_t led) { - assignLedToLightMatrix(column, row, led, ULTRAWHITE); -} - -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrix( - uint8_t column, uint8_t row, int16_t led, uint32_t color) { - assignLedToLightMatrixDE(((column - 1) * 8) + row, led, color); -} - -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixWPC( - uint8_t number, int16_t led) { - assignLedToLightMatrixWPC(number, led, ULTRAWHITE); - wpc = true; -} - -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixWPC( - uint8_t number, int16_t led, uint32_t color) { - assignLedToLightMatrix(number / 10 % 10, number % 10, led, color); - wpc = true; -} - -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixSYS11( - uint8_t number, int16_t led) { - assignLedToLightMatrixDE(number, led, ULTRAWHITE); -} - -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixSYS11( - uint8_t number, int16_t led, uint32_t color) { - assignLedToLightMatrixDE(number, led, color); -} - -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE( - uint8_t number, int16_t led) { - assignLedToLightMatrixDE(number, led, ULTRAWHITE); -} - -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToLightMatrixDE( - uint8_t number, int16_t led, uint32_t color) { - --number; - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { - if (ledLightMatrixPositions[number][i] == -1) { - ledLightMatrixPositions[number][i] = led; - ledLightMatrixColors[number][i] = color; - return; - } - } -} - -void CombinedGiAndLightMatrixWS2812FXDevice::assignCustomLed(uint8_t number, - int16_t led, - uint32_t color) { - // Custom LEDs have numbers >= CUSTOM_LED_OFFSET. - // Attch them right behind the original matrix. - assignLedToLightMatrixDE(number - CUSTOM_LED_OFFSET + _LIGHT_MATRIX_SIZE, led, color); -} - -void CombinedGiAndLightMatrixWS2812FXDevice::assignLedToFlasher( - uint8_t number, int16_t led, uint32_t color) { - for (int offset = 0; offset < _MAX_FLASHERS; offset++) { - if (flasherNumber[offset] == number) { - // Flasher already registered, add another LED to it. - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { - if (ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + - offset][i] == -1) { - ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + - offset][i] = led; - ledLightMatrixColors[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + offset] - [i] = color; - return; - } - } - return; - } - } - - // Flasher not yet registered, find a free slot. - for (int f = _LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS; - f < (_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + _MAX_FLASHERS); f++) { - if (ledLightMatrixPositions[f][0] == -1) { - ledLightMatrixPositions[f][0] = led; - ledLightMatrixColors[f][0] = color; - flasherNumber[f - (_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS)] = number; - return; - } - } -} - -void CombinedGiAndLightMatrixWS2812FXDevice::handleEvent(Event *event) { +void CombinedGiAndLightMatrixWS2812FXDevice::handleEvent(Event* event) { if (!effectRunning) { if (event->sourceId == EVENT_SOURCE_GI) { uint8_t giString = event->eventId - 1; + if (giString >= NUM_GI_STRINGS) { + return; + } // Brightness is a value between 0 and 8. Convert it into a value from 0 // to 255. uint8_t giBrightness = 0; @@ -155,143 +50,80 @@ void CombinedGiAndLightMatrixWS2812FXDevice::handleEvent(Event *event) { if (targetGIBrightness[giString] != giBrightness) { if ((targetGIBrightness[giString] < giBrightness && msHeatUp == 0) || (targetGIBrightness[giString] > giBrightness && msAfterGlow == 0)) { - for (int i = 0; i <= numLEDsGI[giString]; i++) { - setDimmedPixelColor(ledGIPositions[giString][i], - ledGIColors[giString][i], giBrightness); + for (auto& led : getGILEDsByNumber(giString)) { + ws2812FX->setPixelColor( + led->position, + getDimmedPixelColor(led->color, giBrightness)); } } else { - if (targetGIBrightness[giString] < giBrightness) { - if (heatUpGI[giString] == 0 && afterGlowGI[giString] == 0) { - heatUpGI[giString] = millis(); - } else if (afterGlowGI[giString] > 0) { - // There's still an after glow effect running. Start heat up from - // current value. - byte value = wavePWMAfterGlow->getExponentialValue( - millis() - afterGlowGI[giString] + msAfterGlow); - afterGlowGI[giString] = 0; - for (int ms = 1; ms <= msHeatUp; ms++) { - if (wavePWMHeatUp->getExponentialValue(ms) >= value) { - heatUpGI[giString] = millis() - ms; - break; - } - } - // safety net - if (heatUpGI[giString] == 0) { - heatUpGI[giString] = millis() - msHeatUp + 1; - } - } - } else { - if (afterGlowGI[giString] == 0 && heatUpGI[giString] == 0) { - afterGlowGI[giString] = millis(); - } else if (heatUpGI[giString] > 0) { - // There's still a heat up effect running. Start after glow from - // current value. - byte value = wavePWMHeatUp->getExponentialValue(millis() - - heatUp[giString]); - heatUpGI[giString] = 0; - for (int ms = msAfterGlow; ms <= (msAfterGlow * 2); ms++) { - if (wavePWMAfterGlow->getExponentialValue(ms) <= value) { - afterGlowGI[giString] = millis() - ms; - break; - } - } - // safety net - if (afterGlowGI[giString] == 0) { - afterGlowGI[giString] = millis() - (2 * msAfterGlow) + 1; - } - } + for (auto& led : getGILEDsByNumber(giString)) { + intializeNewLEDState(led, targetGIBrightness[giString] > giBrightness); } } sourceGIBrightness[giString] = targetGIBrightness[giString]; targetGIBrightness[giString] = giBrightness; } - } else if (event->sourceId == EVENT_SOURCE_LIGHT || - event->sourceId == EVENT_SOURCE_SOLENOID) { + } else if (event->sourceId == EVENT_SOURCE_LIGHT) { uint8_t number = event->eventId; - - if (event->sourceId == EVENT_SOURCE_LIGHT) { - if (wpc) { - // WPC - uint8_t column = number / 10 % 10; - uint8_t row = number % 10; - number = ((column - 1) * 8) + row; - } - - // We start at "0", not "1". - --number; - } else { - for (int offset = 0; offset < _MAX_FLASHERS; offset++) { - if (flasherNumber[offset] == number) { - number = _LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + offset; - break; - } - } - - if (number < (_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS)) { - // The solenoid isn't a registered flasher. - return; - } + bool on = (bool)event->value; + for (auto& led : getLightMatrixLEDsByNumber(number)) { + intializeNewLEDState(led, on); } - + } else if (event->sourceId == EVENT_SOURCE_SOLENOID) { + uint8_t number = event->eventId; bool on = (bool)event->value; + for (auto& led : getFlasherLEDsByNumber(number)) { + intializeNewLEDState(led, on); + } + } + } +} - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { - if (ledLightMatrixPositions[number][i] >= 0) { - if (on && msHeatUp == 0) { - ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], - ledLightMatrixColors[number][i]); - } else if (!on && msAfterGlow == 0) { - ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], - RGBW_BLACK); - } else if (i == 0) { - if (on) { - if (heatUp[number] == 0 && afterGlow[number] == 0) { - heatUp[number] = millis(); - } else if (afterGlow[number] > 0) { - // There's still an after glow effect running. Start heat up - // from current value. - byte value = wavePWMAfterGlow->getExponentialValue( - millis() - afterGlow[number] + msAfterGlow); - afterGlow[number] = 0; - for (int ms = 1; ms <= msHeatUp; ms++) { - if (wavePWMHeatUp->getExponentialValue(ms) >= value) { - heatUp[number] = millis() - ms; - break; - } - } - // safety net - if (heatUp[number] == 0) { - heatUp[number] = millis() - msHeatUp + 1; - } - } - } else { - if (afterGlow[number] == 0 && heatUp[number] == 0) { - afterGlow[number] = millis(); - } else if (heatUp[number] > 0) { - // There's still a heat up effect running. Start after glow from - // current value. - byte value = wavePWMHeatUp->getExponentialValue(millis() - - heatUp[number]); - heatUp[number] = 0; - for (int ms = msAfterGlow; ms <= (msAfterGlow * 2); ms++) { - if (wavePWMAfterGlow->getExponentialValue(ms) <= value) { - afterGlow[number] = millis() - ms; - break; - } - } - // safety net - if (afterGlow[number] == 0) { - afterGlow[number] = millis() - (2 * msAfterGlow) + 1; - } - } - } - - // terminate the loop - return; - } +void CombinedGiAndLightMatrixWS2812FXDevice::intializeNewLEDState(LED* led, + bool on) { + if (on && msHeatUp == 0) { + ws2812FX->setPixelColor(led->position, led->color); + } else if (!on && msAfterGlow == 0) { + ws2812FX->setPixelColor(led->position, RGBW_BLACK); + } else if (on) { + if (led->heatUp == 0 && led->afterGlow == 0) { + led->heatUp = millis(); + } else if (led->afterGlow > 0) { + // There's still an after glow effect running. Start heat up + // from current value. + uint8_t value = wavePWMAfterGlow->getExponentialValue( + millis() - led->afterGlow + msAfterGlow); + led->afterGlow = 0; + for (int ms = 1; ms <= msHeatUp; ms++) { + if (wavePWMHeatUp->getExponentialValue(ms) >= value) { + led->heatUp = millis() - ms; + break; } } + // safety net + if (led->heatUp == 0) { + led->heatUp = millis() - msHeatUp + 1; + } + } + } else { + if (led->afterGlow == 0 && led->heatUp == 0) { + led->afterGlow = millis(); + } else if (led->heatUp > 0) { + // There's still a heat up effect running. Start after glow from + // current value. + uint8_t value = wavePWMHeatUp->getExponentialValue(millis() - led->heatUp); + led->heatUp = 0; + for (int ms = msAfterGlow; ms <= (msAfterGlow * 2); ms++) { + if (wavePWMAfterGlow->getExponentialValue(ms) <= value) { + led->afterGlow = millis() - ms; + break; + } + } + // safety net + if (led->afterGlow == 0) { + led->afterGlow = millis() - (2 * msAfterGlow) + 1; + } } } } @@ -299,89 +131,68 @@ void CombinedGiAndLightMatrixWS2812FXDevice::handleEvent(Event *event) { void CombinedGiAndLightMatrixWS2812FXDevice::updateAfterGlow() { for (uint8_t giString = 0; giString < NUM_GI_STRINGS; giString++) { uint8_t glowBrightness = targetGIBrightness[giString]; - if (heatUpGI[giString] > 0) { - if ((millis() - heatUpGI[giString]) >= msHeatUp) { - heatUpGI[giString] = 0; - } else { - float diff = - targetGIBrightness[giString] - sourceGIBrightness[giString]; - float mult = diff / 255; - glowBrightness = - sourceGIBrightness[giString] + - (wavePWMHeatUp->getExponentialValue(millis() - heatUpGI[giString]) * - mult); - } - } else if (afterGlowGI[giString] > 0) { - if ((millis() - afterGlowGI[giString]) >= msAfterGlow) { - afterGlowGI[giString] = 0; - } else { - float diff = - sourceGIBrightness[giString] - targetGIBrightness[giString]; - float mult = diff / 255; - glowBrightness = targetGIBrightness[giString] + - (wavePWMAfterGlow->getExponentialValue( - millis() - afterGlowGI[giString] + msAfterGlow) * - mult); - } - } else { - continue; - } - for (int i = 0; i < numLEDsGI[giString]; i++) { - if (ledGIPositions[giString][i] != -1) { - setDimmedPixelColor(ledGIPositions[giString][i], - ledGIColors[giString][i], glowBrightness); + for (auto& led : getChangingGILEDsByNumber(giString)) { + if (led->heatUp > 0) { + if ((millis() - led->heatUp) >= msHeatUp) { + led->heatUp = 0; + } else { + float diff = + targetGIBrightness[giString] - sourceGIBrightness[giString]; + float mult = diff / 255; + glowBrightness = + sourceGIBrightness[giString] + + (wavePWMHeatUp->getExponentialValue(millis() - led->heatUp) * + mult); + } + } else if (led->afterGlow > 0) { + if ((millis() - led->afterGlow) >= msAfterGlow) { + led->afterGlow = 0; + } else { + float diff = + sourceGIBrightness[giString] - targetGIBrightness[giString]; + float mult = diff / 255; + glowBrightness = + targetGIBrightness[giString] + + (wavePWMAfterGlow->getExponentialValue( + millis() - led->afterGlow + msAfterGlow) * + mult); + } } + + ws2812FX->setPixelColor( + led->position, getDimmedPixelColor(led->color, glowBrightness)); } } - for (uint8_t number = 0; - number < _LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + _MAX_FLASHERS; - number++) { + for (auto& led : getChangingLightMatrixAndFlasherLEDs()) { uint8_t glowBrightness; - if (heatUp[number] > 0) { - if ((millis() - heatUp[number]) >= msHeatUp) { - heatUp[number] = 0; - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { - if (ledLightMatrixPositions[number][i] != -1) { - ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], - ledLightMatrixColors[number][i]); - } - } - continue; + if (led->heatUp > 0) { + if ((millis() - led->heatUp) >= msHeatUp) { + led->heatUp = 0; + ws2812FX->setPixelColor(led->position, led->color); } else { glowBrightness = - wavePWMHeatUp->getExponentialValue(millis() - heatUp[number]); + wavePWMHeatUp->getExponentialValue(millis() - led->heatUp); } - } else if (afterGlow[number] > 0) { - if ((millis() - afterGlow[number]) >= msAfterGlow) { - afterGlow[number] = 0; - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { - if (ledLightMatrixPositions[number][i] != -1) { - ws2812FX->setPixelColor(ledLightMatrixPositions[number][i], - RGBW_BLACK); - } - } - continue; + } else if (led->afterGlow > 0) { + if ((millis() - led->afterGlow) >= msAfterGlow) { + led->afterGlow = 0; + ws2812FX->setPixelColor(led->position, RGBW_BLACK); } else { glowBrightness = wavePWMAfterGlow->getExponentialValue( - millis() - afterGlow[number] + msAfterGlow); + millis() - led->afterGlow + msAfterGlow); } } - if (heatUp[number] > 0 || afterGlow[number] > 0) { - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { - if (ledLightMatrixPositions[number][i] != -1) { - setDimmedPixelColor(ledLightMatrixPositions[number][i], - ledLightMatrixColors[number][i], glowBrightness); - } - } + if (led->heatUp > 0 || led->afterGlow > 0) { + ws2812FX->setPixelColor( + led->position, getDimmedPixelColor(led->color, glowBrightness)); } } } -void CombinedGiAndLightMatrixWS2812FXDevice::setDimmedPixelColor( - int16_t led, uint32_t color, uint8_t brightness) { +uint32_t CombinedGiAndLightMatrixWS2812FXDevice::getDimmedPixelColor(uint32_t color, uint8_t brightness) { uint8_t w = (color >> 24) & 0xFF; uint8_t r = (color >> 16) & 0xFF; uint8_t g = (color >> 8) & 0xFF; @@ -394,7 +205,8 @@ void CombinedGiAndLightMatrixWS2812FXDevice::setDimmedPixelColor( r = (r * mult) >> 8; w = (w * mult) >> 8; - ws2812FX->setPixelColor(led, r, g, b, w); + return (uint32_t(w) << 24) | (uint32_t(r) << 16) | (uint32_t(g) << 8) | + uint32_t(b); } void CombinedGiAndLightMatrixWS2812FXDevice::setHeatUp() { setHeatUp(30); } diff --git a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h index 59cea01..b64be7c 100644 --- a/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h +++ b/src/EffectDevices/CombinedGiAndLightMatrixWS2812FXDevice.h @@ -70,9 +70,9 @@ lamps could be driven, for example used in Elektra to drive the lamps of two different playfields. In libpiname that is handled using a standard 8x8 matrix and adding a second (virtual) 8x8 matrix. We don't see the state of the relay, - but get dedicated lamp numbers from 1-60 and 65-124. So lamps that get triggered - in combination with the relay get offset of 64 to their number. So we have 120 - lamps out of 128. + but get dedicated lamp numbers from 1-60 and 65-124. So lamps that get + triggered in combination with the relay get offset of 64 to their number. So + we have 120 lamps out of 128. Capcom uses two real 8x8 matrix and has no GI. So we have 128 CPU-controlled lamps. @@ -80,11 +80,8 @@ In order to ease the AfterGlow handling and to avoid long iterations across arrays and to reduce the number of addressable LED strings, we extend the original Lamp Matrix. - The internal numbering to cover any matrix is 0 to 127, normalized to start at 0. - Starting at position 128 we add custom LEDs which are added to the playfield and - which are not part of the original matrix. The amount of custom LEDs is limited - by _MAX_CUSTOM_LEDS. - Flashers are added to the matrix at position (127 + _MAX_CUSTOM_LEDS). + Starting at position 129, we add custom LEDs which are added to the playfield + and which are not part of the original matrix. */ #ifndef CombinedGiAndLightMatrixWS2812FXDevice_h @@ -93,121 +90,173 @@ #include #include -#include "../PPUC.h" +#include +#include +#include + #include "../EventDispatcher/Event.h" #include "../EventDispatcher/EventDispatcher.h" #include "../EventDispatcher/EventListener.h" +#include "../PPUC.h" #include "WS2812FXDevice.h" -#define _MAX_LEDS_GI_STRING 50 -#define _LIGHT_MATRIX_SIZE 128 -#define _MAX_LEDS_PER_LIGHT 3 -#define _MAX_CUSTOM_LEDS 24 -#define _MAX_FLASHERS 12 - // Number of WPC GI strings #define NUM_GI_STRINGS 5 -// Number of WPC GI brightness steps -#define NUM_BRIGHTNESS 8 + +struct LED { + uint8_t number; // Original system number (GI string, light matrix pos, + // flasher port) + uint16_t position; // Position in WS2812 stripe + uint32_t color; // LED color + uint32_t heatUp; // Heat up effect value + uint32_t afterGlow; // After glow effect value + + LED(uint8_t num, uint16_t pos, uint32_t col = 0) + : number(num), position(pos), color(col), heatUp(0), afterGlow(0) {} +}; + class CombinedGiAndLightMatrixWS2812FXDevice : public WS2812FXDevice, public EventListener { public: - CombinedGiAndLightMatrixWS2812FXDevice(WS2812FX *ws2812FX, int firstLED, + CombinedGiAndLightMatrixWS2812FXDevice(WS2812FX* ws2812FX, int firstLED, int lastLED, int firstSegment, int lastSegment, - EventDispatcher *eventDispatcher) + EventDispatcher* eventDispatcher) : WS2812FXDevice(ws2812FX, firstLED, lastLED, firstSegment, lastSegment) { wavePWMHeatUp = new WavePWM(); wavePWMAfterGlow = new WavePWM(); afterGlowSupport = true; - for (int number = 0; number < NUM_GI_STRINGS; number++) { - for (int i = 0; i < _MAX_LEDS_GI_STRING; i++) { - ledGIPositions[number][i] = -1; - } - } - for (int number = 0; - number < (_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + _MAX_FLASHERS); - number++) { - for (int i = 0; i < _MAX_LEDS_PER_LIGHT; i++) { - ledLightMatrixPositions[number][i] = -1; - } - } eventDispatcher->addListener(this, EVENT_SOURCE_GI); - eventDispatcher->addListener(this, EVENT_SOURCE_SOLENOID); // Flasher + eventDispatcher->addListener(this, EVENT_SOURCE_SOLENOID); eventDispatcher->addListener(this, EVENT_SOURCE_LIGHT); } + ~CombinedGiAndLightMatrixWS2812FXDevice() { + delete wavePWMHeatUp; + delete wavePWMAfterGlow; + } + void on(); void off(); - void assignLedToGiString(uint8_t giString, int16_t led); - void assignLedToGiString(uint8_t giString, int16_t led, uint32_t color); + void assignLedToGiString(uint8_t number, int16_t led, uint32_t color = 0) { + giLEDs.emplace_back(number, led, color); + rebuildGIIndex(); + } - void assignLedRangeToGiString(uint8_t giString, int16_t first, int16_t last); + void assignLedToLightMatrix(uint8_t number, int16_t led, uint32_t color = 0) { + lightMatrixLEDs.emplace_back(number, led, color); + rebuildLightMatrixIndex(); + } - void assignLedToLightMatrix(uint8_t column, uint8_t row, int16_t led); - void assignLedToLightMatrix(uint8_t column, uint8_t row, int16_t led, - uint32_t color); + void assignLedToFlasher(uint8_t number, int16_t led, uint32_t color = 0) { + flasherLEDs.emplace_back(number, led, color); + rebuildFlasherIndex(); + } - void assignLedToLightMatrixWPC(uint8_t number, int16_t led); - void assignLedToLightMatrixWPC(uint8_t number, int16_t led, uint32_t color); + // Fast access methods + std::vector getGILEDsByNumber(uint8_t number) { + auto it = giIndex.find(number); + if (it != giIndex.end()) return it->second; + return {}; + } - void assignLedToLightMatrixDE(uint8_t number, int16_t led); - void assignLedToLightMatrixDE(uint8_t number, int16_t led, uint32_t color); + std::vector getLightMatrixLEDsByNumber(uint8_t number) { + auto it = lightMatrixIndex.find(number); + if (it != lightMatrixIndex.end()) return it->second; + return {}; + } - void assignLedToLightMatrixSYS11(uint8_t number, int16_t led); - void assignLedToLightMatrixSYS11(uint8_t number, int16_t led, uint32_t color); + std::vector getFlasherLEDsByNumber(uint8_t number) { + auto it = flasherIndex.find(number); + if (it != flasherIndex.end()) return it->second; + return {}; + } - void assignCustomLed(uint8_t number, int16_t led, uint32_t color); + std::vector getChangingGILEDsByNumber(uint8_t number) { + std::vector result; + for (auto led : getGILEDsByNumber(number)) { + if (led->heatUp > 0 || led->afterGlow > 0) { + result.push_back(led); + } + } + return result; + } - void assignLedToFlasher(uint8_t number, int16_t led, uint32_t color); + std::vector getChangingLightMatrixAndFlasherLEDs() { + std::vector result; + for (auto& led : getLightMatrixLEDs()) { + if (led.heatUp > 0 || led.afterGlow > 0) { + result.push_back(&led); // Use &led to get the pointer + } + } + for (auto& led : getFlasherLEDs()) { + if (led.heatUp > 0 || led.afterGlow > 0) { + result.push_back(&led); // Use &led to get the pointer + } + } + return result; + } - void setDimmedPixelColor(int16_t led, uint32_t color, uint8_t brightness); + // Direct access to vectors for iteration + std::vector& getGILEDs() { return giLEDs; } + std::vector& getLightMatrixLEDs() { return lightMatrixLEDs; } + std::vector& getFlasherLEDs() { return flasherLEDs; } + uint32_t getDimmedPixelColor(uint32_t color, uint8_t brightness); void setHeatUp(); void setAfterGlow(); - void setHeatUp(int ms); void setAfterGlow(int ms); - - void handleEvent(Event *event); - void handleEvent(ConfigEvent *event) {} + void handleEvent(Event* event); + void handleEvent(ConfigEvent* event) {} void updateAfterGlow(); protected: - int16_t numLEDsGI[NUM_GI_STRINGS] = {0}; + std::vector giLEDs; + std::vector lightMatrixLEDs; + std::vector flasherLEDs; + + // Indexes for fast lookup by number + std::unordered_map> giIndex; + std::unordered_map> lightMatrixIndex; + std::unordered_map> flasherIndex; - int16_t ledGIPositions[NUM_GI_STRINGS][_MAX_LEDS_GI_STRING] = {{0}}; - uint32_t ledGIColors[NUM_GI_STRINGS][_MAX_LEDS_GI_STRING] = {{0}}; uint8_t sourceGIBrightness[NUM_GI_STRINGS] = {0}; uint8_t targetGIBrightness[NUM_GI_STRINGS] = {0}; - // Internally we store the positions in Data East numbering from 1 to 64. - // The WPC-specific functions convert the WPC-specific numbering. - // For other systems, the numbering can go up to 128. - int16_t ledLightMatrixPositions[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + - _MAX_FLASHERS][_MAX_LEDS_PER_LIGHT] = {{0}}; - uint32_t ledLightMatrixColors[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + - _MAX_FLASHERS][_MAX_LEDS_PER_LIGHT] = {{0}}; + void intializeNewLEDState(LED* led, bool on); + + void rebuildGIIndex() { + giIndex.clear(); + for (auto& led : giLEDs) { + giIndex[led.number].push_back(&led); + } + } + + void rebuildLightMatrixIndex() { + lightMatrixIndex.clear(); + for (auto& led : lightMatrixLEDs) { + lightMatrixIndex[led.number].push_back(&led); + } + } - uint8_t flasherNumber[_MAX_FLASHERS] = {0}; + void rebuildFlasherIndex() { + flasherIndex.clear(); + for (auto& led : flasherLEDs) { + flasherIndex[led.number].push_back(&led); + } + } - WavePWM *wavePWMHeatUp; - WavePWM *wavePWMAfterGlow; + WavePWM* wavePWMHeatUp; + WavePWM* wavePWMAfterGlow; // When no effects are running, we're in normal GI and Light Matrix mode. bool stopped = false; // Never stop the updates. bool effectRunning = false; - bool wpc = false; - int16_t msHeatUp = 0; int16_t msAfterGlow = 0; - uint32_t heatUpGI[NUM_GI_STRINGS] = {0}; - uint32_t afterGlowGI[NUM_GI_STRINGS] = {0}; - uint32_t heatUp[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + _MAX_FLASHERS] = {0}; - uint32_t afterGlow[_LIGHT_MATRIX_SIZE + _MAX_CUSTOM_LEDS + _MAX_FLASHERS] = { - 0}; }; #endif diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 247646a..169deb0 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -359,22 +359,10 @@ void EffectsController::handleEvent(ConfigEvent *event) { config_payload); break; case LED_TYPE_LAMP: - if (config_values[2] >= CUSTOM_LED_OFFSET) { - ((CombinedGiAndLightMatrixWS2812FXDevice *) - ws2812FXDevices[0][0]) - ->assignCustomLed(config_values[2], config_values[3], - config_payload); - } else if (platform == PLATFORM_WPC) { - ((CombinedGiAndLightMatrixWS2812FXDevice *) - ws2812FXDevices[0][0]) - ->assignLedToLightMatrixWPC( - config_values[2], config_values[3], config_payload); - } else { - ((CombinedGiAndLightMatrixWS2812FXDevice *) - ws2812FXDevices[0][0]) - ->assignLedToLightMatrixDE( - config_values[2], config_values[3], config_payload); - } + ((CombinedGiAndLightMatrixWS2812FXDevice *) + ws2812FXDevices[0][0]) + ->assignLedToLightMatrix( + config_values[2], config_values[3], config_payload); break; case LED_TYPE_FLASHER: ((CombinedGiAndLightMatrixWS2812FXDevice *) diff --git a/src/PPUC.h b/src/PPUC.h index 1b0c5a3..be26b4e 100644 --- a/src/PPUC.h +++ b/src/PPUC.h @@ -19,6 +19,4 @@ #include -#define CUSTOM_LED_OFFSET 130 - #endif From 6797337292afbd23f66d52004a7ca0620daaef2e Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 15 Nov 2025 21:29:21 +0100 Subject: [PATCH 083/102] fixed uf2 upload --- .github/workflows/io-bords.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/io-bords.yml b/.github/workflows/io-bords.yml index bb7f4e2..d1a42d3 100644 --- a/.github/workflows/io-bords.yml +++ b/.github/workflows/io-bords.yml @@ -88,7 +88,7 @@ jobs: ELF_FILE=$(find .pio/build/ -name "*.elf" | head -n 1) echo "Found ELF file: $ELF_FILE" elf2uf2 "$ELF_FILE" "${ELF_FILE%.elf}.uf2" - cp ${ELF_FILE%.elf}.uf2 ../../${{ matrix.controller }}-${{ needs.version.outputs.tag }}.uf2 + cp ${ELF_FILE%.elf}.uf2 ${{ matrix.controller }}-${{ needs.version.outputs.tag }}.uf2 - name: Upload UF2 artifact uses: actions/upload-artifact@v4 with: From d0889d365d0e3c972174f26f6a79db12a6507108 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 17 Nov 2025 09:56:41 +0100 Subject: [PATCH 084/102] configured include path for vscode --- .gitignore | 1 - .vscode/c_cpp_properties.json | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 .vscode/c_cpp_properties.json diff --git a/.gitignore b/.gitignore index c30f8ea..bf10959 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ .idea .pio -.vscode .DS_Store \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..1fb4880 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,14 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": [ + "${workspaceFolder}/**", + "${env:HOME}/.platformio/packages/framework-arduinopico/**" + ], + "defines": [], + "intelliSenseMode": "macos-clang-arm64" + } + ], + "version": 4 +} \ No newline at end of file From 898e98bbfe34422552679b19f0709668d2dc3f7d Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 17 Nov 2025 23:16:23 +0100 Subject: [PATCH 085/102] migrsated switch reading to PIO --- .gitignore | 3 +- .vscode/c_cpp_properties.json | 6 +- src/IOBoardController.cpp | 9 +-- src/IODevices/Switches.cpp | 135 +++++++++++++++------------------- src/IODevices/Switches.h | 48 ++++++++---- src/IODevices/Switches.pio | 37 ++++++++++ 6 files changed, 137 insertions(+), 101 deletions(-) create mode 100644 src/IODevices/Switches.pio diff --git a/.gitignore b/.gitignore index bf10959..5286d05 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea .pio -.DS_Store \ No newline at end of file +.DS_Store +*.pio.h diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 1fb4880..f6141a2 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,8 +3,10 @@ { "name": "Mac", "includePath": [ - "${workspaceFolder}/**", - "${env:HOME}/.platformio/packages/framework-arduinopico/**" + "${workspaceFolder}/src", + "${workspaceFolder}/.pio/libdeps/IO_16_8_1/**", + "${env:HOME}/.platformio/packages/framework-arduinopico/**", + "/Library/Developer/CommandLineTools/usr/lib/clang/*/include" ], "defines": [], "intelliSenseMode": "macos-clang-arm64" diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 858bff1..fc5d58f 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -31,9 +31,6 @@ IOBoardController::IOBoardController(int cT) { void IOBoardController::update() { if (running) { - if (activeSwitches) { - switches()->update(); - } if (activeSwitchMatrix) { switchMatrix()->update(); } @@ -75,7 +72,6 @@ void IOBoardController::handleEvent(Event *event) { case EVENT_RESET: // Clear all configurations or reboot the device. _pwmDevices->reset(); - _switches->reset(); _switchMatrix->reset(); // Issue a delayed reset of the board. @@ -95,10 +91,7 @@ void IOBoardController::handleEvent(ConfigEvent *event) { port = event->value; break; case CONFIG_TOPIC_NUMBER: - // Ports 15-18 (labeled as 13-16) of IO_16_8_1 are stateful. - _switches->registerSwitch((byte)port, event->value, - (controllerType == CONTROLLER_16_8_1 && - port >= 15 && port <= 18)); + _switches->registerSwitch((byte)port, event->value); activeSwitches = true; break; } diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index fc38531..e2726f7 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -1,98 +1,85 @@ #include "Switches.h" -void Switches::registerSwitch(byte p, byte n, bool s) { - if (last < (MAX_SWITCHES - 1)) { - if (s) { - resetStatefulPort(p); - } +#include "Switches.pio.h" - pinMode(p, INPUT); +Switches* Switches::instance = nullptr; + +void Switches::registerSwitch(byte p, byte n) { + if (last < (MAX_SWITCHES - 1)) { port[++last] = p; number[last] = n; - toggled[last] = false; - stateful[last] = s; - delayMicroseconds(10); - // Note, we have active LOW! - state[last] = !digitalRead(p); + active = true; } } -void Switches::resetStatefulPort(byte p) { - // Set mid power output as input. - pinMode(p, OUTPUT); - digitalWrite(p, HIGH); - pinMode(p, INPUT); -} +void Switches::handleSwitchChanges(uint16_t raw) { + absolute_time_t now = get_absolute_time(); + uint16_t changed = raw ^ lastStable; -void Switches::reset() { - for (uint8_t i = 0; i < MAX_SWITCHES; i++) { - if (stateful[i]) resetStatefulPort(port[i]); - } + for (int i = 0; i < MAX_SWITCHES; i++) { + uint16_t mask = 1u << i; - for (uint8_t i = 0; i < MAX_SWITCHES; i++) { - port[i] = 0; - number[i] = 0; - state[i] = 0; - toggled[i] = false; - stateful[i] = false; - } - - last = -1; -} - -void Switches::update() { - // Wait for SWITCH_DEBOUNCE milliseconds to debounce the switches. That covers - // the edge case that a switch was hit right before the last polling of - // events. After SWITCH_DEBOUNCE milliseconds every switch is allowed to - // toggle once until the events get polled again. - if (millis() - _ms >= SWITCH_DEBOUNCE) { - for (int i = 0; i <= last; i++) { - if (!toggled[i]) { - // Note, we have active LOW! - bool new_state = !digitalRead(port[i]); - if (new_state != state[i]) { - state[i] = new_state; - toggled[i] = true; - // Dispatch all switch events as "local fast". - // If a PWM output registered to it, we have "fast flip". Useful for - // flippers, kick backs, jets and sling shots. - _eventDispatcher->dispatch(new Event( - EVENT_SOURCE_SWITCH, word(0, number[i]), state[i], true)); - } + if (changed & mask) { + // Debounce + if (absolute_time_diff_us(debounceTime[i], now) >= + SWITCH_DEBOUNCE * 1000) { + bool newState = !(raw & mask); // active-low + debounceTime[i] = now; + lastStable = (lastStable & ~mask) | (newState ? mask : 0); + // Dispatch all switch events as "local fast". + // If a PWM output registered to it, we have "fast flip". Useful for + // flippers, kick backs, jets and sling shots. + _eventDispatcher->dispatch( + new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), newState, true)); } } } } -void Switches::handleEvent(Event *event) { +void Switches::handleEvent(Event* event) { switch (event->sourceId) { - case EVENT_POLL_EVENTS: - if (running && boardId == (byte)event->value) { - // This I/O board has been polled for events, so all current switch - // states are transmitted. Reset switch debounce timer and toggles. - _ms = millis(); + case EVENT_READ_SWITCHES: + // The CPU requested all current states. Usually this event is sent when + // the game gets started. + if (active) { + // First, send OFF for all switches then ON for the active ones using + // the IRQ handler. for (int i = 0; i <= last; i++) { - toggled[i] = false; - if (stateful[i]) resetStatefulPort(port[i]); + _eventDispatcher->dispatch( + new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), 0)); } - } - break; - case EVENT_READ_SWITCHES: - // The CPU requested all current states. - for (int i = 0; i <= last; i++) { - // Send all states of switches that haven't been toggled since last poll - // (and dispatched their event already). - if (!toggled[i]) { - _eventDispatcher->dispatch( - new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), state[i])); - } else { - toggled[i] = false; - if (stateful[i]) resetStatefulPort(port[i]); + if (!running) { + instance = this; + running = true; + + extern const pio_program_t switches_pio_program; + uint offset = pio_add_program(pio, &switches_pio_program); + pio_sm_config c = switches_pio_program_get_default_config(offset); + + sm_config_set_in_pins(&c, SWITCHES_BASE_PIN); + sm_config_set_sideset_pins(&c, 15); // Side-set begins at GPIO 15 + sm_config_set_set_pins(&c, 15, 4); // Set begins at GPIO 15 + + // Connect 16 GPIOs to this PIO block + for (uint i = 0; i < 16; i++) { + pio_gpio_init(pio, SWITCHES_BASE_PIN + i); + } + + // Set the pin direction at the PIO + pio_sm_set_consecutive_pindirs(pio, sm, SWITCHES_BASE_PIN, 16, false); + + sm_config_set_in_shift(&c, true, false, 16); + + pio_sm_init(pio, sm, offset, &c); + + irq_set_exclusive_handler(PIO0_IRQ_0, onSwitchCanges); + irq_set_enabled(PIO0_IRQ_0, true); + pio_set_irq0_source_enabled(pio, pis_interrupt0, true); + + pio_sm_set_enabled(pio, sm, true); } } - _ms = millis(); - running = true; break; } } diff --git a/src/IODevices/Switches.h b/src/IODevices/Switches.h index 213ae2c..01430a7 100644 --- a/src/IODevices/Switches.h +++ b/src/IODevices/Switches.h @@ -12,49 +12,65 @@ #include "../EventDispatcher/Event.h" #include "../EventDispatcher/EventDispatcher.h" +#include "hardware/gpio.h" +#include "hardware/pio.h" -#ifndef MAX_SWITCHES +#define SWITCHES_BASE_PIN 3 #define MAX_SWITCHES 16 -#endif - -#ifndef SWITCH_DEBOUNCE #define SWITCH_DEBOUNCE 2 -#endif class Switches : public EventListener { public: Switches(byte bId, EventDispatcher* eD) { boardId = bId; - _ms = millis(); _eventDispatcher = eD; _eventDispatcher->addListener(this, EVENT_POLL_EVENTS); _eventDispatcher->addListener(this, EVENT_READ_SWITCHES); - } - void registerSwitch(byte p, byte n, bool stateful = false); + pio = pio0; + sm = 0; - void update(); - void reset(); + lastStable = 0; + for (int i = 0; i < MAX_SWITCHES; i++) { + debounceTime[i] = 0; + } + } + + void registerSwitch(byte p, byte n); void handleEvent(Event* event); void handleEvent(ConfigEvent* event) {} - private: - void resetStatefulPort(byte p); + void handleSwitchChanges(uint16_t raw); + PIO pio; + int sm; + + private: byte boardId; - unsigned long _ms; bool running = false; + bool active = false; byte port[MAX_SWITCHES] = {0}; byte number[MAX_SWITCHES] = {0}; - bool state[MAX_SWITCHES] = {0}; - bool toggled[MAX_SWITCHES] = {0}; - bool stateful[MAX_SWITCHES] = {0}; int last = -1; + uint16_t lastStable; + absolute_time_t debounceTime[MAX_SWITCHES]; + EventDispatcher* _eventDispatcher; + + static Switches* instance; + + static void __not_in_flash_func(onSwitchCanges)() { + // IRQ0 clear + pio0_hw->irq = 1u << 0; + + // Get 16 bit from FIFO + uint32_t raw = pio_sm_get_blocking(instance->pio, instance->sm); + instance->handleSwitchChanges(raw & 0xFFFF); + } }; #endif diff --git a/src/IODevices/Switches.pio b/src/IODevices/Switches.pio new file mode 100644 index 0000000..6dfe53b --- /dev/null +++ b/src/IODevices/Switches.pio @@ -0,0 +1,37 @@ +.program switches_pio +.side_set 4 opt + + ; Initialize X to all pins HIGH. Max. 16 switches, so 16 bit, so 0xFFFF: + ; But "set" can only set 5 bits, so a max value of 31 (0x1F). + set x, 31 ; X = 0x1F + in x, 5 ; shift 5 bits from X into ISR, now ISR = 0x1F + in x, 5 ; shift 5 bits from X into ISR, now ISR = 0x3FF + in x, 5 ; shift 5 bits from X into ISR, now ISR = 0x7FFF + in x, 1 ; shift 1 bit from X into ISR, now ISR = 0xFFFF + mov x, isr ; copy ISR to X, now X = 0xFFFF + set y, 0 ; Y = 0x0 + +loop: + mov isr, y ; ISR = 0x0 + in pins, 16 ; read 16 switches to ISR (filling lower 16 bits of the 32bit ISR) + mov y, isr ; copy ISR to Y for comparison + jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) + jmp loop + +changed: + mov osr, y + push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it + irq 0 ; trigger interrupt 0 to notify the main CPU that a switch state has changed + mov x, y ; update X to the new switch states + set y, 0 ; Y = 0x0 + + ; Reset stateful pins (GPIO 15-18) + set pindirs, 0b1111 side 0 ; change direction of 4 pins (15-18) to output, set LOW + nop side 0b1111 ; set 4 pins to HIGH + nop side 0b1111 ; short delay + nop side 0b1111 ; short delay + nop side 0b1111 ; short delay + nop side 0 ; set LOW + set pindirs, 0 side 0 ; change direction all pins back to input + + jmp loop From a5c8e3fbe181f57f694ac800f398a441c0f8ff3a Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 19 Nov 2025 12:55:37 +0100 Subject: [PATCH 086/102] migrated 8x8 matrix to PIOs --- src/IODevices/SwitchMatrix.pio | 149 +++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 src/IODevices/SwitchMatrix.pio diff --git a/src/IODevices/SwitchMatrix.pio b/src/IODevices/SwitchMatrix.pio new file mode 100644 index 0000000..eeb6014 --- /dev/null +++ b/src/IODevices/SwitchMatrix.pio @@ -0,0 +1,149 @@ +.program columns_active_high_pio +.wrap_target + set x, 1 + mov isr, x ; initialize ISR with 0x00000001 + set x, 0 ; X = 0 + set y, 7 ; 8 columns (0-7) + +loop: + mov osr, isr ; copy ISR to OSR for output + out pins, 8 ; set 8 pins for columns, one is HIGH, others LOW + in x, 1 ; shift left ISR by 1 bit + nop [16] ; short delay to let other state machines read rows + jmp y-- loop ; decrement Y, loop until Y < 0 +.wrap + + +.program odd_rows_active_high_pio + ; Initialize X to all pins LOW. Max. 4x8 rows, so 32 bit, so 0x0: + set x, 0 ; X = 0x0 + mov y, x ; Y = 0x0 + mov isr, y ; ISR = 0x0 + +loop: + wait 0 PIN 8 ; wait for odd column 1 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 10 ; wait for odd column 3 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 12 ; wait for odd column 5 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 14 ; wait for odd column 7 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + + mov y, isr ; copy ISR to Y for comparison + jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) + jmp loop + +changed: + mov osr, y + push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it + irq 0 ; trigger interrupt 0 to notify the main CPU that a odd columns state has changed + mov x, y ; update X to the new odd columns state + jmp loop + + +.program even_rows_active_high_pio + ; Initialize X to all pins LOW. Max. 4x8 rows, so 32 bit, so 0x0: + set x, 0 ; X = 0x0 + mov y, x ; Y = 0x0 + mov isr, y ; ISR = 0x0 + +loop: + wait 0 PIN 9 ; wait for even column 2 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 11 ; wait for even column 4 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 13 ; wait for even column 6 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 15 ; wait for even column 8 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + + mov y, isr ; copy ISR to Y for comparison + jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) + jmp loop + +changed: + mov osr, y + push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it + irq 1 ; trigger interrupt 1 to notify the main CPU that a even columns state has changed + mov x, y ; update X to the new switch states + jmp loop + + +; ---------------------------------------------------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------------------------------------------------- + + +.program columns_active_low_pio +.wrap_target + set y, 1 + mov isr, ~y ; initialize ISR with 0xFFFFFFFE + set y, 0 ; Y = 0 + mov x, ~y ; X = 0xFFFFFFFF + set y, 7 ; 8 columns (0-7) + +loop: + mov osr, isr ; copy ISR to OSR for output + out pins, 8 ; set 8 pins for columns, one is HIGH, others LOW + in x, 1 ; shift left ISR by 1 bit + nop [16] ; short delay to let other state machines read rows + jmp y-- loop ; decrement Y, loop until Y < 0 +.wrap + + +.program odd_rows_active_low_pio + ; Initialize X to all pins HIGH. Max. 4x8 rows, so 32 bit: + set x, 0 ; X = 0x0 + mov y, ~x ; Y = 0xFFFFFFFF + mov x, y ; X = 0xFFFFFFFF + mov isr, y ; ISR = 0xFFFFFFFF + +loop: + wait 0 PIN 8 ; wait for odd column 1 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 10 ; wait for odd column 3 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 12 ; wait for odd column 5 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 14 ; wait for odd column 7 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + + mov y, isr ; copy ISR to Y for comparison + jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) + jmp loop + +changed: + mov osr, y + push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it + irq 0 ; trigger interrupt 0 to notify the main CPU that a odd columns state has changed + mov x, y ; update X to the new odd columns state + jmp loop + + +.program even_rows_active_low_pio + ; Initialize X to all pins HIGH. Max. 4x8 rows, so 32 bit: + set x, 0 ; X = 0x0 + mov y, ~x ; Y = 0xFFFFFFFF + mov x, y ; X = 0xFFFFFFFF + mov isr, y ; ISR = 0xFFFFFFFF + +loop: + wait 0 PIN 9 ; wait for even column 2 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 11 ; wait for even column 4 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 13 ; wait for even column 6 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 15 ; wait for even column 8 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + + mov y, isr ; copy ISR to Y for comparison + jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) + jmp loop + +changed: + mov osr, y + push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it + irq 1 ; trigger interrupt 1 to notify the main CPU that a even columns state has changed + mov x, y ; update X to the new switch states + jmp loop From b8d73549aecf8d5e1bdb8d7f72769b4dcafce783 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 19 Nov 2025 12:56:26 +0100 Subject: [PATCH 087/102] 8x8 matrix PIO --- .vscode/c_cpp_properties.json | 463 ++++++++++++++++++++++++++++++++- src/EventDispatcher/Event.h | 3 - src/IOBoardController.cpp | 26 +- src/IOBoardController.h | 4 +- src/IODevices/SwitchMatrix.cpp | 240 ++++++++++------- src/IODevices/SwitchMatrix.h | 81 +++--- src/IODevices/Switches.cpp | 26 +- src/IODevices/Switches.h | 11 +- 8 files changed, 678 insertions(+), 176 deletions(-) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index f6141a2..106f88c 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -1,16 +1,463 @@ +// +// !!! WARNING !!! AUTO-GENERATED FILE! +// PLEASE DO NOT MODIFY IT AND USE "platformio.ini": +// https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags +// { "configurations": [ { - "name": "Mac", + "name": "PlatformIO", "includePath": [ - "${workspaceFolder}/src", - "${workspaceFolder}/.pio/libdeps/IO_16_8_1/**", - "${env:HOME}/.platformio/packages/framework-arduinopico/**", - "/Library/Developer/CommandLineTools/usr/lib/clang/*/include" + "/Volumes/data/workspace/PPUC/io-boards/src", + "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/RPI_PICO_TimerInterrupt/src", + "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/Bounce2/src", + "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/WS2812FX/src", + "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/Adafruit NeoPixel", + "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/WavePWM/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040/api/deprecated", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040/api/deprecated-avr-comp", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/include/rp2040", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/include/rp2040/pico_base", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2040/hardware_regs/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2040/hardware_structs/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2040/pico_platform/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_btstack/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_cyw43_arch/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_cyw43_driver/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/cyw43-driver/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/3rd-party/bluedroid/decoder/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/3rd-party/bluedroid/encoder/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/3rd-party/yxml", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/platform/embedded", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Device/RP2040/Include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/tinyusb/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/boards/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/hardware_claim/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_base_headers/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_binary_info/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_sync/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_time/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_util/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_stdlib_headers/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_usb_reset_interface_headers/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/boot_bootrom_headers/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/cmsis/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Core/Include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_adc/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_base/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_boot_lock/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_clocks/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_divider/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_dma/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_exception/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_flash/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_gpio/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_i2c/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_interp/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_irq/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_rtc/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_pio/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_pll/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_pwm/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_resets/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_spi/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_sync/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_sync_spin_lock/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_timer/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_uart/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_vreg/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_watchdog/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_xosc/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_aon_timer/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_async_context/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_bootrom/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_double/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_flash/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_float/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_int64_ops/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_lwip/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_multicore/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_common/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_compiler/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_sections/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_panic/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_printf/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_runtime/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_runtime_init/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_rand/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_stdio/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_stdio_uart/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_unique_id/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/lwip/src/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040/freertos", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/variants/rpipico", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/ADCInput/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/ArduinoOTA/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/AsyncUDP/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/AudioBufferManager/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BTstackLib/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BluetoothAudio/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BluetoothHCI/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BluetoothHIDMaster/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/DNSServer/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/EEPROM/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/ESPHost/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/FatFS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/FatFSUSB/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Bluetooth/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Joystick/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Keyboard/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Mouse/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HTTPClient/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HTTPUpdate/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HTTPUpdateServer/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Hash/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/I2S/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Joystick/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/JoystickBLE/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/JoystickBT/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Keyboard/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/KeyboardBLE/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/KeyboardBT/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/LEAmDNS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/LittleFS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MD5Builder/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MIDIUSB/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Mouse/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MouseAbsolute/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MouseBLE/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MouseBT/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/NetBIOS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/PDM/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/PWMAudio/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/PicoOTA/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SD/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SDFS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SPI/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SPISlave/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SdFat/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SerialBT/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Servo/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SimpleMDNS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SingleFileDrive/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SoftwareSPI/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Ticker/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Updater/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/VFS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/WebServer/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/WiFi/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Wire/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/http-parser/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_CYW43/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_ESPHost/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_Ethernet/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_WINC1500/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_enc28j60/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w5100/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w5500/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w55rp20/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w6100/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w6300/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/rp2040", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/rp2350", + "" ], - "defines": [], - "intelliSenseMode": "macos-clang-arm64" + "browse": { + "limitSymbolsToIncludedHeaders": true, + "path": [ + "/Volumes/data/workspace/PPUC/io-boards/src", + "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/RPI_PICO_TimerInterrupt/src", + "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/Bounce2/src", + "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/WS2812FX/src", + "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/Adafruit NeoPixel", + "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/WavePWM/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040/api/deprecated", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040/api/deprecated-avr-comp", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/include/rp2040", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/include/rp2040/pico_base", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2040/hardware_regs/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2040/hardware_structs/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2040/pico_platform/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_btstack/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_cyw43_arch/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_cyw43_driver/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/cyw43-driver/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/3rd-party/bluedroid/decoder/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/3rd-party/bluedroid/encoder/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/3rd-party/yxml", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/platform/embedded", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Device/RP2040/Include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/tinyusb/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/boards/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/hardware_claim/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_base_headers/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_binary_info/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_sync/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_time/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_util/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_stdlib_headers/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_usb_reset_interface_headers/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/boot_bootrom_headers/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/cmsis/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Core/Include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_adc/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_base/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_boot_lock/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_clocks/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_divider/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_dma/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_exception/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_flash/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_gpio/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_i2c/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_interp/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_irq/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_rtc/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_pio/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_pll/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_pwm/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_resets/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_spi/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_sync/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_sync_spin_lock/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_timer/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_uart/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_vreg/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_watchdog/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_xosc/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_aon_timer/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_async_context/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_bootrom/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_double/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_flash/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_float/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_int64_ops/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_lwip/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_multicore/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_common/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_compiler/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_sections/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_panic/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_printf/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_runtime/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_runtime_init/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_rand/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_stdio/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_stdio_uart/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_unique_id/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/lwip/src/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040/freertos", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/include", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/variants/rpipico", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/ADCInput/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/ArduinoOTA/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/AsyncUDP/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/AudioBufferManager/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BTstackLib/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BluetoothAudio/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BluetoothHCI/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BluetoothHIDMaster/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/DNSServer/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/EEPROM/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/ESPHost/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/FatFS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/FatFSUSB/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Bluetooth/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Joystick/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Keyboard/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Mouse/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HTTPClient/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HTTPUpdate/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HTTPUpdateServer/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Hash/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/I2S/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Joystick/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/JoystickBLE/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/JoystickBT/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Keyboard/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/KeyboardBLE/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/KeyboardBT/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/LEAmDNS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/LittleFS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MD5Builder/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MIDIUSB/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Mouse/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MouseAbsolute/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MouseBLE/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MouseBT/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/NetBIOS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/PDM/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/PWMAudio/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/PicoOTA/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SD/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SDFS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SPI/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SPISlave/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SdFat/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SerialBT/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Servo/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SimpleMDNS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SingleFileDrive/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SoftwareSPI/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Ticker/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Updater/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/VFS/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/WebServer/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/WiFi/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Wire/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/http-parser/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_CYW43/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_ESPHost/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_Ethernet/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_WINC1500/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_enc28j60/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w5100/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w5500/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w55rp20/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w6100/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w6300/src", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/rp2040", + "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/rp2350", + "" + ] + }, + "defines": [ + "PLATFORMIO=60118", + "ARDUINO_RASPBERRY_PI_PICO", + "ARDUINO_ARCH_RP2040", + "USBD_MAX_POWER_MA=500", + "PICO_STDIO_USB", + "CFG_TUSB_MCU=OPT_MCU_RP2040", + "CFG_TUSB_OS=OPT_OS_PICO", + "CYW43_DEFAULT_PIN_WL_CLOCK=29u", + "CYW43_DEFAULT_PIN_WL_CS=25u", + "CYW43_DEFAULT_PIN_WL_DATA_IN=24u", + "CYW43_DEFAULT_PIN_WL_DATA_OUT=24u", + "CYW43_DEFAULT_PIN_WL_HOST_WAKE=24u", + "CYW43_DEFAULT_PIN_WL_REG_ON=23u", + "CYW43_PIN_WL_DYNAMIC=1", + "CYW43_PIO_CLOCK_DIV_DYNAMIC=1", + "CYW43_WARN=//", + "LIB_BOOT_STAGE2_HEADERS=1", + "LIB_PICO_AON_TIMER=1", + "LIB_PICO_ATOMIC=1", + "LIB_PICO_BIT_OPS=1", + "LIB_PICO_BIT_OPS_PICO=1", + "LIB_PICO_BOOTSEL_VIA_DOUBLE_RESET=1", + "LIB_PICO_CLIB_INTERFACE=1", + "LIB_PICO_CRT0=1", + "LIB_PICO_CXX_OPTIONS=1", + "LIB_PICO_DIVIDER=1", + "LIB_PICO_DIVIDER_COMPILER=1", + "LIB_PICO_DOUBLE=1", + "LIB_PICO_FIX_RP2040_USB_DEVICE_ENUMERATION=1", + "LIB_PICO_FLASH=1", + "LIB_PICO_FLOAT=1", + "LIB_PICO_FLOAT_PICO=1", + "LIB_PICO_INT64_OPS=1", + "LIB_PICO_INT64_OPS_COMPILER=1", + "LIB_PICO_MALLOC=1", + "LIB_PICO_MEM_OPS=1", + "LIB_PICO_MEM_OPS_COMPILER=1", + "LIB_PICO_MULTICORE=1", + "LIB_PICO_NEWLIB_INTERFACE=1", + "LIB_PICO_PLATFORM=1", + "LIB_PICO_PLATFORM_COMMON=1", + "LIB_PICO_PLATFORM_COMPILER=1", + "LIB_PICO_PLATFORM_PANIC=1", + "LIB_PICO_PLATFORM_SECTIONS=1", + "LIB_PICO_PRINTF=1", + "LIB_PICO_PRINTF_PICO=1", + "LIB_PICO_RAND=1", + "LIB_PICO_RUNTIME=1", + "LIB_PICO_RUNTIME_INIT=1", + "LIB_PICO_STANDARD_BINARY_INFO=1", + "LIB_PICO_STANDARD_LINK=1", + "LIB_PICO_STDIO=0", + "LIB_PICO_STDIO_UART=0", + "LIB_PICO_STDLIB=1", + "LIB_PICO_SYNC=1", + "LIB_PICO_SYNC_CRITICAL_SECTION=1", + "LIB_PICO_SYNC_MUTEX=1", + "LIB_PICO_SYNC_SEM=1", + "LIB_PICO_TIME=1", + "LIB_PICO_TIME_ADAPTER=1", + "LIB_PICO_UNIQUE_ID=1", + "LIB_PICO_UTIL=1", + "LIB_TINYUSB_BOARD=1", + "LIB_TINYUSB_DEVICE=1", + "PICO_32BIT=1", + "PICO_BUILD=1", + "PICO_COPY_TO_RAM=0", + "PICO_NO_BINARY_INFO=1", + "PICO_NO_FLASH=0", + "PICO_NO_HARDWARE=0", + "PICO_ON_DEVICE=1", + "PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1", + "PICO_RP2040_USB_DEVICE_UFRAME_FIX=1", + "PICO_USE_BLOCKED_RAM=0", + "PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64", + "PICO_MAX_SHARED_IRQ_HANDLERS=6", + "PICO_CYW43_ARCH_HEADER=stdint.h", + "CYW43_TASK_STACK_SIZE=1024", + "LIB_PICO_DIVIDER_HARDWARE=1", + "LIB_PICO_DOUBLE_PICO=1", + "LIB_PICO_INT64_OPS_PICO=1", + "LIB_PICO_MEM_OPS_PICO=1", + "PICO_DOUBLE_SUPPORT_ROM_V1=1", + "PICO_FLOAT_SUPPORT_ROM_V1=1", + "PICO_PLATFORM=rp2040", + "PICO_RP2040=1", + "PICO_RP2040_B0_SUPPORTED=1", + "PICO_RP2040_B1_SUPPORTED=1", + "PICO_RP2040_B2_SUPPORTED=1", + "ARM_MATH_CM0_FAMILY", + "ARM_MATH_CM0_PLUS", + "TARGET_RP2040", + "ARDUINO=10810", + "ARDUINO_ARCH_RP2040", + "F_CPU=133000000L", + "BOARD_NAME=\"pico\"", + "PICO_FLASH_SIZE_BYTES=2097152", + "FILE_COPY_CONSTRUCTOR_SELECT=FILE_COPY_CONSTRUCTOR_PUBLIC", + "USE_UTF8_LONG_NAMES=1", + "DISABLE_FS_H_WARNING=1", + "CFG_TUSB_MCU=OPT_MCU_RP2040", + "USB_VID=0x2e8a", + "USB_PID=0x000a", + "USBD_VID=0x2e8a", + "USBD_PID=0x000a", + "USB_MANUFACTURER=\"Raspberry Pi\"", + "USB_PRODUCT=\"Pico\"", + "PICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1", + "CYW43_LWIP=1", + "CYW43_PIO_CLOCK_DIV_DYNAMIC=1", + "LWIP_IPV4=1", + "LWIP_IGMP=1", + "LWIP_CHECKSUM_CTRL_PER_NETIF=1", + "LWIP_IPV6=0", + "ARDUINO_VARIANT=\"rpipico\"", + "" + ], + "cStandard": "gnu17", + "cppStandard": "gnu++17", + "compilerPath": "/Users/markus.kalkbrenner/.platformio/packages/toolchain-rp2040-earlephilhower/bin/arm-none-eabi-gcc", + "compilerArgs": [ + "-march=armv6-m", + "-mcpu=cortex-m0plus", + "-mthumb", + "" + ] } ], "version": 4 -} \ No newline at end of file +} diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 56381b6..7c3eb8e 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -91,9 +91,6 @@ #define LED_TYPE_FLASHER 2 // Flasher #define LED_TYPE_LAMP 3 // Lamp -#define MATRIX_TYPE_COLUMN 1 // Column -#define MATRIX_TYPE_ROW 2 // Row - #define PWM_EFFECT_SINE 1 #define PWM_EFFECT_RAMP_DOWN_STOP 2 #define PWM_EFFECT_IMPULSE 3 diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index fc5d58f..db6f622 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -31,9 +31,6 @@ IOBoardController::IOBoardController(int cT) { void IOBoardController::update() { if (running) { - if (activeSwitchMatrix) { - switchMatrix()->update(); - } if (activePwmDevices) { pwmDevices()->update(); } @@ -72,7 +69,6 @@ void IOBoardController::handleEvent(Event *event) { case EVENT_RESET: // Clear all configurations or reboot the device. _pwmDevices->reset(); - _switchMatrix->reset(); // Issue a delayed reset of the board. // Core 1 should have enough time to turn off it's devices. @@ -92,7 +88,6 @@ void IOBoardController::handleEvent(ConfigEvent *event) { break; case CONFIG_TOPIC_NUMBER: _switches->registerSwitch((byte)port, event->value); - activeSwitches = true; break; } break; @@ -104,28 +99,13 @@ void IOBoardController::handleEvent(ConfigEvent *event) { _switchMatrix->setActiveLow(); } break; - case CONFIG_TOPIC_MAX_PULSE_TIME: - _switchMatrix->setPulseTime((byte)event->value); - break; - case CONFIG_TOPIC_TYPE: - type = event->value; - number = 0; - port = 0; - break; - case CONFIG_TOPIC_NUMBER: - number = event->value; - break; case CONFIG_TOPIC_PORT: port = event->value; - if (MATRIX_TYPE_COLUMN == type) { - _switchMatrix->registerColumn(port, number); - } else { - _switchMatrix->registerRow(port, number); - } - activeSwitchMatrix = true; + break; + case CONFIG_TOPIC_NUMBER: + _switchMatrix->registerSwitch((byte)port, event->value); break; } - break; case CONFIG_TOPIC_PWM: diff --git a/src/IOBoardController.h b/src/IOBoardController.h index b07f627..17af7d6 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -7,7 +7,7 @@ GPIO16,17,18: UART TX, UART RX, RS485 Direction GPIO19-24, 26, 27: Power Out (PWM) GPIO25: Status-LED - GPIO28: ADC für Adressierung + GPIO28: ADC for Board ID GPIO29: Reserve (z.B. für einen LED-Strip oder zweite Status-LED) */ @@ -49,8 +49,6 @@ class IOBoardController : public EventListener { bool running = false; bool activePwmDevices = false; - bool activeSwitches = false; - bool activeSwitchMatrix = false; bool m_debug = false; int controllerType; diff --git a/src/IODevices/SwitchMatrix.cpp b/src/IODevices/SwitchMatrix.cpp index ecf466b..0469904 100644 --- a/src/IODevices/SwitchMatrix.cpp +++ b/src/IODevices/SwitchMatrix.cpp @@ -1,113 +1,173 @@ #include "SwitchMatrix.h" -void SwitchMatrix::setActiveLow() { activeLow = true; } +#include "SwitchMatrix.pio.h" -void SwitchMatrix::setPulseTime(byte pT) { pulseTime = pT; } +SwitchMatrix* SwitchMatrix::instance = nullptr; -void SwitchMatrix::registerColumn(byte p, byte n) { - if (n > 0 && n < MAX_COLUMNS) { - columns[n - 1] = p; - pinMode(p, OUTPUT); - } -} +void SwitchMatrix::setActiveLow() { activeLow = true; } -void SwitchMatrix::registerRow(byte p, byte n) { - if (n > 0 && n < MAX_ROWS) { - rows[n - 1] = p; - pinMode(p, INPUT); +void SwitchMatrix::registerSwitch(byte p, byte n) { + if (p < MATRIX_SWITCHES) { + mapping[p] = n; + active = true; } } -void SwitchMatrix::reset() { - pulseTime = 2; - pauseTime = 2; - activeLow = false; - active = false; - column = 0; - - for (uint8_t col = 0; col < MAX_COLUMNS; col++) { - columns[col] = -1; - for (uint8_t row = 0; row < MAX_ROWS; row++) { - rows[row] = -1; - state[col][row] = 0; - toggled[col][row] = 0; - } - } -} +void SwitchMatrix::handleRowChanges(uint32_t raw, uint8_t even) { + absolute_time_t now = get_absolute_time(); + uint32_t changed = raw ^ lastStable[even]; // raw to raw comparison -void SwitchMatrix::update() { - unsigned long ms = millis(); - if (active) { - if (ms > (_ms + (int)(pulseTime / 2))) { - for (int row = 0; row < MAX_ROWS; row++) { - if (rows[row] != -1 && !toggled[column][row]) { - bool new_state = digitalRead(rows[row]); - if (new_state != state[column][row]) { - state[column][row] = new_state; - toggled[column][row] = true; - - word number = (column + 1) * (row + 1); - if (platform != PLATFORM_DATA_EAST) { - number = ((column + 1) * 10) + (row + 1); - } - // Dispatch all switch events as "local fast". - // If a PWM output registered to it, we have "fast flip". Useful for - // flippers, kick backs, jets and sling shots. - _eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, number, - state[column][row], true)); - } - } - } - } + for (int column = 0; column < 4; column++) { + for (int row = 0; row < 8; row++) { + uint8_t pos = ((column * 2) + even) * 8 + row; + if (mapping[pos] == 0) continue; // Not registered - if (ms > (_ms + pulseTime)) { - digitalWrite(columns[column], activeLow); - active = false; - _ms = ms; - } - } else if (!active && (ms > (_ms + pauseTime))) { - column++; - if (column >= MAX_COLUMNS) { - column = 0; - } + uint32_t mask = 0x80000000 >> (column * 8 + row); + + if (changed & mask) { + // Debounce + if (absolute_time_diff_us(debounceTime[pos], now) >= + MATRIX_SWITCH_DEBOUNCE * 1000) { + debounceTime[pos] = now; - // If column is not in use (-1), the next update will increase the column. - if (columns[column] != -1) { - digitalWrite(columns[column], !activeLow); - active = true; - _ms = ms; + // Convert RAW to logical pressed/released + // ----------------------------------------- + // activeLow : pressed = raw_bit == 0 + // activeHigh: pressed = raw_bit == 1 + bool rawBit = (raw & mask) != 0; + + bool newState = activeLow ? (!rawBit) // active-low: 0 = pressed + : rawBit; // active-high: 1 = pressed + + // Store the *raw* stable state + if (rawBit) + lastStable[even] |= mask; // raw=1 + else + lastStable[even] &= ~mask; // raw=0 + + // Dispatch all switch events as "local fast". + // If a PWM output registered to it, we have "fast flip". Useful for + // flippers, kick backs, jets and sling shots. + _eventDispatcher->dispatch(new Event( + EVENT_SOURCE_SWITCH, word(0, mapping[pos]), newState, true)); + } + } } } } -void SwitchMatrix::handleEvent(Event *event) { +void SwitchMatrix::handleEvent(Event* event) { switch (event->sourceId) { - case EVENT_POLL_EVENTS: - if (boardId == (byte)event->value) { - // This I/O board has been polled for events, so all current switch - // states are transmitted. Reset switch toggles. - for (int col = 0; col < MAX_COLUMNS; col++) { - for (int row = 0; row < MAX_ROWS; row++) { - toggled[col][row] = false; + case EVENT_READ_SWITCHES: + // The CPU requested all current states. Usually this event is sent when + // the game gets started. + if (active) { + // First, send OFF for all switches then ON for the active ones using + // the IRQ handler. + for (int i = 0; i < MATRIX_SWITCHES; i++) { + if (mapping[i] != 0) { + _eventDispatcher->dispatch( + new Event(EVENT_SOURCE_SWITCH, word(0, mapping[i]), 0)); } } - } - break; - case EVENT_READ_SWITCHES: - // The CPU requested all current states. - for (int col = 0; col < MAX_COLUMNS; col++) { - if (columns[col] != -1) { - for (int row = 0; row < MAX_ROWS; row++) { - if (rows[row] != -1) { - word number = (column + 1) * (row + 1); - if (platform != PLATFORM_DATA_EAST) { - number = ((column + 1) * 10) + (row + 1); - } - _eventDispatcher->dispatch( - new Event(EVENT_SOURCE_SWITCH, number, state[column][row])); - } + if (!running) { + instance = this; + running = true; + + uint columns_offset; + pio_sm_config c_columns_pio; + uint odd_rows_offset; + pio_sm_config c_odd_rows; + uint even_rows_offset; + pio_sm_config c_even_rows; + + if (activeLow) { + extern const pio_program_t columns_active_low_pio_program; + columns_offset = + pio_add_program(pio, &columns_active_low_pio_program); + c_columns_pio = columns_active_low_pio_program_get_default_config( + columns_offset); + + extern const pio_program_t odd_rows_active_low_pio_program; + uint odd_rows_offset = + pio_add_program(pio, &odd_rows_active_low_pio_program); + pio_sm_config c_odd_rows = + odd_rows_active_low_pio_program_get_default_config( + odd_rows_offset); + + extern const pio_program_t even_rows_active_low_pio_program; + uint even_rows_offset = + pio_add_program(pio, &even_rows_active_low_pio_program); + pio_sm_config c_even_rows = + even_rows_active_low_pio_program_get_default_config( + even_rows_offset); + } else { + extern const pio_program_t columns_active_high_pio_program; + columns_offset = + pio_add_program(pio, &columns_active_high_pio_program); + c_columns_pio = columns_active_high_pio_program_get_default_config( + columns_offset); + + extern const pio_program_t odd_rows_active_high_pio_program; + uint odd_rows_offset = + pio_add_program(pio, &odd_rows_active_high_pio_program); + pio_sm_config c_odd_rows = + odd_rows_active_high_pio_program_get_default_config( + odd_rows_offset); + + extern const pio_program_t even_rows_active_high_pio_program; + uint even_rows_offset = + pio_add_program(pio, &even_rows_active_high_pio_program); + pio_sm_config c_even_rows = + even_rows_active_high_pio_program_get_default_config( + even_rows_offset); + } + + // Columns + sm_config_set_in_pins(&c_columns_pio, COLUMNS_BASE_PIN); + // Connect 8 GPIOs to this PIO block + for (uint i = 0; i < 8; i++) { + pio_gpio_init(pio, COLUMNS_BASE_PIN + i); + } + // Set the pin direction at the PIO + pio_sm_set_consecutive_pindirs(pio, sm_even_rows, COLUMNS_BASE_PIN, 8, + true); + sm_config_set_out_shift(&c_columns_pio, true, false, 8); + pio_sm_init(pio, sm_columns, columns_offset, &c_columns_pio); + pio_sm_set_enabled(pio, sm_columns, true); + + // Odd Rows + sm_config_set_in_pins(&c_odd_rows, SWITCH_MATRIX_BASE_PIN); + // Connect 16 GPIOs to this PIO block + for (uint i = 0; i < 16; i++) { + pio_gpio_init(pio, SWITCH_MATRIX_BASE_PIN + i); + } + // Set the pin direction at the PIO + pio_sm_set_consecutive_pindirs(pio, sm_odd_rows, + SWITCH_MATRIX_BASE_PIN, 16, false); + sm_config_set_in_shift(&c_odd_rows, true, false, 8); + pio_sm_init(pio, sm_odd_rows, odd_rows_offset, &c_odd_rows); + irq_set_exclusive_handler(PIO0_IRQ_0, onOddRowChanges); + irq_set_enabled(PIO0_IRQ_0, true); + pio_set_irq0_source_enabled(pio, pis_interrupt0, true); + pio_sm_set_enabled(pio, sm_odd_rows, true); + + // Even Rows + sm_config_set_in_pins(&c_even_rows, SWITCH_MATRIX_BASE_PIN); + // Connect 16 GPIOs to this PIO block + for (uint i = 0; i < 16; i++) { + pio_gpio_init(pio, SWITCH_MATRIX_BASE_PIN + i); } + // Set the pin direction at the PIO + pio_sm_set_consecutive_pindirs(pio, sm_even_rows, + SWITCH_MATRIX_BASE_PIN, 16, false); + sm_config_set_in_shift(&c_even_rows, true, false, 8); + pio_sm_init(pio, sm_even_rows, even_rows_offset, &c_even_rows); + irq_set_exclusive_handler(PIO0_IRQ_1, onEvenRowChanges); + irq_set_enabled(PIO0_IRQ_1, true); + pio_set_irq0_source_enabled(pio, pis_interrupt1, true); + pio_sm_set_enabled(pio, sm_even_rows, true); } } break; diff --git a/src/IODevices/SwitchMatrix.h b/src/IODevices/SwitchMatrix.h index 221a8c8..994da12 100644 --- a/src/IODevices/SwitchMatrix.h +++ b/src/IODevices/SwitchMatrix.h @@ -1,6 +1,6 @@ /* SwitchMatrix_h. - Created by Markus Kalkbrenner, 2023. + Created by Markus Kalkbrenner, 2023-2025. */ #ifndef SwitchMatrix_h @@ -8,60 +8,71 @@ #include "../EventDispatcher/Event.h" #include "../EventDispatcher/EventDispatcher.h" -#include "../PPUC.h" +#include "hardware/gpio.h" +#include "hardware/pio.h" -#ifndef MAX_COLUMNS -#define MAX_COLUMNS 10 -#endif - -#ifndef MAX_ROWS -#define MAX_ROWS 8 -#endif +#define SWITCH_MATRIX_BASE_PIN 0 +#define COLUMNS_BASE_PIN (SWITCH_MATRIX_BASE_PIN + 8) +#define MATRIX_SWITCHES 64 +#define MATRIX_SWITCH_DEBOUNCE 2 class SwitchMatrix : public EventListener { public: - SwitchMatrix(byte bId, EventDispatcher *eD) { + SwitchMatrix(byte bId, EventDispatcher* eD) { boardId = bId; - platform = PLATFORM_LIBPINMAME; - - reset(); - - _ms = millis(); _eventDispatcher = eD; _eventDispatcher->addListener(this, EVENT_POLL_EVENTS); _eventDispatcher->addListener(this, EVENT_READ_SWITCHES); - } - void registerColumn(byte p, byte n); - void registerRow(byte p, byte n); + pio = pio0; + sm_columns = 0; + sm_odd_rows = 2; + sm_even_rows = 1; + } void setActiveLow(); - void setPulseTime(byte pT); + void registerSwitch(byte p, byte n); - void update(); - void reset(); + void handleEvent(Event* event); - void handleEvent(Event *event); + void handleEvent(ConfigEvent* event) {} - void handleEvent(ConfigEvent *event) {} + void handleRowChanges(uint32_t raw, uint8_t even); + + PIO pio; + int sm_columns; + int sm_even_rows; + int sm_odd_rows; private: byte boardId; - byte platform; - byte pulseTime; - byte pauseTime; - bool activeLow; - bool active; + bool activeLow = false; + bool running = false; + bool active = false; + + byte mapping[MATRIX_SWITCHES] = {0}; + uint32_t lastStable[2] = {0}; + absolute_time_t debounceTime[MATRIX_SWITCHES] = {0}; - unsigned long _ms; + EventDispatcher* _eventDispatcher; - int8_t columns[MAX_COLUMNS]; - int8_t rows[MAX_ROWS]; - bool state[MAX_COLUMNS][MAX_ROWS] = {0}; - bool toggled[MAX_COLUMNS][MAX_ROWS] = {0}; - byte column = 0; + static SwitchMatrix* instance; - EventDispatcher *_eventDispatcher; + static void __not_in_flash_func(onOddRowChanges)() { + // IRQ0 clear + pio0_hw->irq = 1u << 0; + + uint32_t raw = pio_sm_get_blocking(instance->pio, instance->sm_odd_rows); + instance->handleRowChanges(raw, 0); + } + + static void __not_in_flash_func(onEvenRowChanges)() { + // IRQ1 clear + pio0_hw->irq = 1u << 1; + + uint32_t raw = pio_sm_get_blocking(instance->pio, instance->sm_even_rows); + instance->handleRowChanges(raw, 1); + } }; #endif diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index e2726f7..cefebe1 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -14,18 +14,30 @@ void Switches::registerSwitch(byte p, byte n) { void Switches::handleSwitchChanges(uint16_t raw) { absolute_time_t now = get_absolute_time(); - uint16_t changed = raw ^ lastStable; + uint16_t changed = raw ^ lastStable; // raw to raw comparison for (int i = 0; i < MAX_SWITCHES; i++) { + if (number[i] == 0) continue; // Not registered + uint16_t mask = 1u << i; if (changed & mask) { // Debounce if (absolute_time_diff_us(debounceTime[i], now) >= SWITCH_DEBOUNCE * 1000) { - bool newState = !(raw & mask); // active-low debounceTime[i] = now; - lastStable = (lastStable & ~mask) | (newState ? mask : 0); + + bool rawBit = (raw & mask) != 0; + + // logical pressed state for active-low + bool newState = !rawBit; + + // store raw stable bit (not logical) + if (rawBit) + lastStable |= mask; // raw = 1 + else + lastStable &= ~mask; // raw = 0 + // Dispatch all switch events as "local fast". // If a PWM output registered to it, we have "fast flip". Useful for // flippers, kick backs, jets and sling shots. @@ -45,8 +57,10 @@ void Switches::handleEvent(Event* event) { // First, send OFF for all switches then ON for the active ones using // the IRQ handler. for (int i = 0; i <= last; i++) { - _eventDispatcher->dispatch( - new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), 0)); + if (number[i] != 0) { + _eventDispatcher->dispatch( + new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), 0)); + } } if (!running) { @@ -73,7 +87,7 @@ void Switches::handleEvent(Event* event) { pio_sm_init(pio, sm, offset, &c); - irq_set_exclusive_handler(PIO0_IRQ_0, onSwitchCanges); + irq_set_exclusive_handler(PIO0_IRQ_0, onSwitchChanges); irq_set_enabled(PIO0_IRQ_0, true); pio_set_irq0_source_enabled(pio, pis_interrupt0, true); diff --git a/src/IODevices/Switches.h b/src/IODevices/Switches.h index 01430a7..982c0e0 100644 --- a/src/IODevices/Switches.h +++ b/src/IODevices/Switches.h @@ -29,11 +29,6 @@ class Switches : public EventListener { pio = pio0; sm = 0; - - lastStable = 0; - for (int i = 0; i < MAX_SWITCHES; i++) { - debounceTime[i] = 0; - } } void registerSwitch(byte p, byte n); @@ -56,14 +51,14 @@ class Switches : public EventListener { byte number[MAX_SWITCHES] = {0}; int last = -1; - uint16_t lastStable; - absolute_time_t debounceTime[MAX_SWITCHES]; + uint16_t lastStable = 0; + absolute_time_t debounceTime[MAX_SWITCHES] = {0}; EventDispatcher* _eventDispatcher; static Switches* instance; - static void __not_in_flash_func(onSwitchCanges)() { + static void __not_in_flash_func(onSwitchChanges)() { // IRQ0 clear pio0_hw->irq = 1u << 0; From 9a02486ca3be20ca494ae4c9d3db324a67979457 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 19 Nov 2025 19:13:25 +0100 Subject: [PATCH 088/102] migrated switch matrix support to PIOs --- src/EventDispatcher/Event.h | 1 + src/IOBoardController.cpp | 23 ++- src/IOBoardController.h | 1 + src/IODevices/SwitchMatrix.cpp | 183 ++++++++---------- src/IODevices/SwitchMatrix.h | 45 ++--- src/IODevices/SwitchMatrix.pio | 149 -------------- .../SwitchMatrixPIO/ActiveHigh4Columns.pio | 15 ++ .../SwitchMatrixPIO/ActiveHigh4Rows.pio | 35 ++++ .../SwitchMatrixPIO/ActiveHigh8Rows.pio | 35 ++++ .../SwitchMatrixPIO/ActiveLow4Columns.pio | 16 ++ .../SwitchMatrixPIO/ActiveLow4Rows.pio | 37 ++++ .../SwitchMatrixPIO/ActiveLow8Rows.pio | 37 ++++ src/IODevices/Switches.cpp | 89 +++++---- src/IODevices/Switches.h | 17 +- src/IODevices/Switches.pio | 37 ---- .../SwitchesPIO/ActiveLow16Switches.pio | 48 +++++ .../SwitchesPIO/ActiveLow4Switches.pio | 31 +++ .../SwitchesPIO/ActiveLow8Switches.pio | 31 +++ 18 files changed, 462 insertions(+), 368 deletions(-) delete mode 100644 src/IODevices/SwitchMatrix.pio create mode 100644 src/IODevices/SwitchMatrixPIO/ActiveHigh4Columns.pio create mode 100644 src/IODevices/SwitchMatrixPIO/ActiveHigh4Rows.pio create mode 100644 src/IODevices/SwitchMatrixPIO/ActiveHigh8Rows.pio create mode 100644 src/IODevices/SwitchMatrixPIO/ActiveLow4Columns.pio create mode 100644 src/IODevices/SwitchMatrixPIO/ActiveLow4Rows.pio create mode 100644 src/IODevices/SwitchMatrixPIO/ActiveLow8Rows.pio delete mode 100644 src/IODevices/Switches.pio create mode 100644 src/IODevices/SwitchesPIO/ActiveLow16Switches.pio create mode 100644 src/IODevices/SwitchesPIO/ActiveLow4Switches.pio create mode 100644 src/IODevices/SwitchesPIO/ActiveLow8Switches.pio diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 7c3eb8e..9850437 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -65,6 +65,7 @@ #define CONFIG_TOPIC_MIN_INTENSITY 77 // "M" #define CONFIG_TOPIC_NUMBER 78 // "N" #define CONFIG_TOPIC_AMOUNT_LEDS 79 // "O" +#define CONFIG_TOPIC_NUM_ROWS 79 // "O" #define CONFIG_TOPIC_PORT 80 // "P" #define CONFIG_TOPIC_SPEED 83 // "S" #define CONFIG_TOPIC_SOURCE 83 // "S" diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index db6f622..beee24a 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -81,29 +81,34 @@ void IOBoardController::handleEvent(Event *event) { void IOBoardController::handleEvent(ConfigEvent *event) { if (event->boardId == boardId) { switch (event->topic) { - case CONFIG_TOPIC_SWITCHES: + case CONFIG_TOPIC_SWITCH_MATRIX: switch (event->key) { + case CONFIG_TOPIC_ACTIVE_LOW: + if (event->value) { + _switchMatrix->setActiveLow(); + } + break; + case CONFIG_TOPIC_NUM_ROWS: + rows = (uint8_t)event->value; + _switchMatrix->setNumRows(rows); + _switches->setNumSwitches(MAX_SWITCHES - NUM_COLUMNS - rows); + break; case CONFIG_TOPIC_PORT: port = event->value; break; case CONFIG_TOPIC_NUMBER: - _switches->registerSwitch((byte)port, event->value); + _switchMatrix->registerSwitch((byte)port, event->value); break; } break; - case CONFIG_TOPIC_SWITCH_MATRIX: + case CONFIG_TOPIC_SWITCHES: switch (event->key) { - case CONFIG_TOPIC_ACTIVE_LOW: - if (event->value) { - _switchMatrix->setActiveLow(); - } - break; case CONFIG_TOPIC_PORT: port = event->value; break; case CONFIG_TOPIC_NUMBER: - _switchMatrix->registerSwitch((byte)port, event->value); + _switches->registerSwitch((byte)port, event->value); break; } break; diff --git a/src/IOBoardController.h b/src/IOBoardController.h index 17af7d6..1dcfc24 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -56,6 +56,7 @@ class IOBoardController : public EventListener { byte port = 0; byte number = 0; byte power = 0; + byte rows = 0; uint16_t minPulseTime = 0; uint16_t maxPulseTime = 0; byte holdPower = 0; diff --git a/src/IODevices/SwitchMatrix.cpp b/src/IODevices/SwitchMatrix.cpp index 0469904..7a8eec2 100644 --- a/src/IODevices/SwitchMatrix.cpp +++ b/src/IODevices/SwitchMatrix.cpp @@ -1,55 +1,55 @@ #include "SwitchMatrix.h" -#include "SwitchMatrix.pio.h" +#include "SwitchMatrixPIO/ActiveHigh4Columns.pio.h" +#include "SwitchMatrixPIO/ActiveHigh4Rows.pio.h" +#include "SwitchMatrixPIO/ActiveHigh8Rows.pio.h" +#include "SwitchMatrixPIO/ActiveLow4Columns.pio.h" +#include "SwitchMatrixPIO/ActiveLow4Rows.pio.h" +#include "SwitchMatrixPIO/ActiveLow8Rows.pio.h" SwitchMatrix* SwitchMatrix::instance = nullptr; -void SwitchMatrix::setActiveLow() { activeLow = true; } - void SwitchMatrix::registerSwitch(byte p, byte n) { - if (p < MATRIX_SWITCHES) { + if (p < (NUM_COLUMNS * numRows)) { mapping[p] = n; active = true; } } -void SwitchMatrix::handleRowChanges(uint32_t raw, uint8_t even) { +void SwitchMatrix::handleRowChanges(uint32_t raw) { absolute_time_t now = get_absolute_time(); - uint32_t changed = raw ^ lastStable[even]; // raw to raw comparison + uint32_t changed = raw ^ lastStable; // raw to raw comparison - for (int column = 0; column < 4; column++) { - for (int row = 0; row < 8; row++) { - uint8_t pos = ((column * 2) + even) * 8 + row; + for (int column = 0; column < NUM_COLUMNS; column++) { + for (int row = 0; row < numRows; row++) { + uint8_t pos = column * numRows + row; if (mapping[pos] == 0) continue; // Not registered - uint32_t mask = 0x80000000 >> (column * 8 + row); + uint32_t mask = 1u << ((NUM_COLUMNS - 1 - column) * numRows + row); if (changed & mask) { + // Convert RAW to logical pressed/released + // ----------------------------------------- + // activeLow : pressed = raw_bit == 0 + // activeHigh: pressed = raw_bit == 1 + bool rawBit = (raw & mask) != 0; + bool switchState = activeLow ? (!rawBit) // active-low: 0 = pressed + : rawBit; // active-high: 1 = pressed // Debounce - if (absolute_time_diff_us(debounceTime[pos], now) >= + if (absolute_time_diff_us(debounceTime[pos][switchState], now) >= MATRIX_SWITCH_DEBOUNCE * 1000) { - debounceTime[pos] = now; - - // Convert RAW to logical pressed/released - // ----------------------------------------- - // activeLow : pressed = raw_bit == 0 - // activeHigh: pressed = raw_bit == 1 - bool rawBit = (raw & mask) != 0; - - bool newState = activeLow ? (!rawBit) // active-low: 0 = pressed - : rawBit; // active-high: 1 = pressed - + debounceTime[pos][switchState] = now; // Store the *raw* stable state if (rawBit) - lastStable[even] |= mask; // raw=1 + lastStable |= mask; // raw=1 else - lastStable[even] &= ~mask; // raw=0 + lastStable &= ~mask; // raw=0 // Dispatch all switch events as "local fast". // If a PWM output registered to it, we have "fast flip". Useful for // flippers, kick backs, jets and sling shots. _eventDispatcher->dispatch(new Event( - EVENT_SOURCE_SWITCH, word(0, mapping[pos]), newState, true)); + EVENT_SOURCE_SWITCH, word(0, mapping[pos]), switchState, true)); } } } @@ -64,7 +64,7 @@ void SwitchMatrix::handleEvent(Event* event) { if (active) { // First, send OFF for all switches then ON for the active ones using // the IRQ handler. - for (int i = 0; i < MATRIX_SWITCHES; i++) { + for (int i = 0; i < (NUM_COLUMNS * numRows); i++) { if (mapping[i] != 0) { _eventDispatcher->dispatch( new Event(EVENT_SOURCE_SWITCH, word(0, mapping[i]), 0)); @@ -76,98 +76,83 @@ void SwitchMatrix::handleEvent(Event* event) { running = true; uint columns_offset; - pio_sm_config c_columns_pio; - uint odd_rows_offset; - pio_sm_config c_odd_rows; - uint even_rows_offset; - pio_sm_config c_even_rows; + pio_sm_config c_columns; + uint rows_offset; + pio_sm_config c_rows; if (activeLow) { - extern const pio_program_t columns_active_low_pio_program; + extern const pio_program_t active_low_4_columns_pio_program; columns_offset = - pio_add_program(pio, &columns_active_low_pio_program); - c_columns_pio = columns_active_low_pio_program_get_default_config( + pio_add_program(pio, &active_low_4_columns_pio_program); + c_columns = active_low_4_columns_pio_program_get_default_config( columns_offset); - extern const pio_program_t odd_rows_active_low_pio_program; - uint odd_rows_offset = - pio_add_program(pio, &odd_rows_active_low_pio_program); - pio_sm_config c_odd_rows = - odd_rows_active_low_pio_program_get_default_config( - odd_rows_offset); - - extern const pio_program_t even_rows_active_low_pio_program; - uint even_rows_offset = - pio_add_program(pio, &even_rows_active_low_pio_program); - pio_sm_config c_even_rows = - even_rows_active_low_pio_program_get_default_config( - even_rows_offset); - } else { - extern const pio_program_t columns_active_high_pio_program; + if (4 == numRows) { + extern const pio_program_t active_low_4_rows_pio_program; + uint rows_offset = + pio_add_program(pio, &active_low_4_rows_pio_program); + pio_sm_config c_rows = + active_low_4_rows_pio_program_get_default_config(rows_offset); + } else { // 8 rows + extern const pio_program_t active_low_8_rows_pio_program; + uint rows_offset = + pio_add_program(pio, &active_low_8_rows_pio_program); + pio_sm_config c_rows = + active_low_8_rows_pio_program_get_default_config(rows_offset); + } + } else { // active high + extern const pio_program_t active_high_4_columns_pio_program; columns_offset = - pio_add_program(pio, &columns_active_high_pio_program); - c_columns_pio = columns_active_high_pio_program_get_default_config( + pio_add_program(pio, &active_high_4_columns_pio_program); + c_columns = active_high_4_columns_pio_program_get_default_config( columns_offset); - extern const pio_program_t odd_rows_active_high_pio_program; - uint odd_rows_offset = - pio_add_program(pio, &odd_rows_active_high_pio_program); - pio_sm_config c_odd_rows = - odd_rows_active_high_pio_program_get_default_config( - odd_rows_offset); - - extern const pio_program_t even_rows_active_high_pio_program; - uint even_rows_offset = - pio_add_program(pio, &even_rows_active_high_pio_program); - pio_sm_config c_even_rows = - even_rows_active_high_pio_program_get_default_config( - even_rows_offset); + if (4 == numRows) { + extern const pio_program_t active_high_4_rows_pio_program; + uint rows_offset = + pio_add_program(pio, &active_high_4_rows_pio_program); + pio_sm_config c_rows = + active_high_4_rows_pio_program_get_default_config( + rows_offset); + } else { // 8 rows + extern const pio_program_t active_high_8_rows_pio_program; + uint rows_offset = + pio_add_program(pio, &active_high_8_rows_pio_program); + pio_sm_config c_rows = + active_high_8_rows_pio_program_get_default_config( + rows_offset); + } } // Columns - sm_config_set_in_pins(&c_columns_pio, COLUMNS_BASE_PIN); - // Connect 8 GPIOs to this PIO block - for (uint i = 0; i < 8; i++) { + sm_config_set_in_pins(&c_columns, COLUMNS_BASE_PIN); + // Connect GPIOs to this PIO block + for (uint i = 0; i < NUM_COLUMNS; i++) { pio_gpio_init(pio, COLUMNS_BASE_PIN + i); } // Set the pin direction at the PIO - pio_sm_set_consecutive_pindirs(pio, sm_even_rows, COLUMNS_BASE_PIN, 8, - true); - sm_config_set_out_shift(&c_columns_pio, true, false, 8); - pio_sm_init(pio, sm_columns, columns_offset, &c_columns_pio); + pio_sm_set_consecutive_pindirs(pio, sm_rows, COLUMNS_BASE_PIN, + NUM_COLUMNS, true); + sm_config_set_out_shift(&c_columns, false, false, 0); + pio_sm_init(pio, sm_columns, columns_offset, &c_columns); pio_sm_set_enabled(pio, sm_columns, true); - // Odd Rows - sm_config_set_in_pins(&c_odd_rows, SWITCH_MATRIX_BASE_PIN); - // Connect 16 GPIOs to this PIO block - for (uint i = 0; i < 16; i++) { - pio_gpio_init(pio, SWITCH_MATRIX_BASE_PIN + i); + // Rows + sm_config_set_in_pins(&c_rows, COLUMNS_BASE_PIN - numRows); + // Connect GPIOs to this PIO block + for (uint i = 0; i < (numRows + NUM_COLUMNS); i++) { + pio_gpio_init(pio, COLUMNS_BASE_PIN - numRows + i); } - // Set the pin direction at the PIO - pio_sm_set_consecutive_pindirs(pio, sm_odd_rows, - SWITCH_MATRIX_BASE_PIN, 16, false); - sm_config_set_in_shift(&c_odd_rows, true, false, 8); - pio_sm_init(pio, sm_odd_rows, odd_rows_offset, &c_odd_rows); - irq_set_exclusive_handler(PIO0_IRQ_0, onOddRowChanges); + // Set the pin direction at the PIO, we also read the 4 column pins + pio_sm_set_consecutive_pindirs(pio, sm_rows, + COLUMNS_BASE_PIN - numRows, + numRows + NUM_COLUMNS, false); + sm_config_set_in_shift(&c_rows, false, false, 0); + pio_sm_init(pio, sm_rows, rows_offset, &c_rows); + irq_set_exclusive_handler(PIO0_IRQ_0, onRowChanges); irq_set_enabled(PIO0_IRQ_0, true); pio_set_irq0_source_enabled(pio, pis_interrupt0, true); - pio_sm_set_enabled(pio, sm_odd_rows, true); - - // Even Rows - sm_config_set_in_pins(&c_even_rows, SWITCH_MATRIX_BASE_PIN); - // Connect 16 GPIOs to this PIO block - for (uint i = 0; i < 16; i++) { - pio_gpio_init(pio, SWITCH_MATRIX_BASE_PIN + i); - } - // Set the pin direction at the PIO - pio_sm_set_consecutive_pindirs(pio, sm_even_rows, - SWITCH_MATRIX_BASE_PIN, 16, false); - sm_config_set_in_shift(&c_even_rows, true, false, 8); - pio_sm_init(pio, sm_even_rows, even_rows_offset, &c_even_rows); - irq_set_exclusive_handler(PIO0_IRQ_1, onEvenRowChanges); - irq_set_enabled(PIO0_IRQ_1, true); - pio_set_irq0_source_enabled(pio, pis_interrupt1, true); - pio_sm_set_enabled(pio, sm_even_rows, true); + pio_sm_set_enabled(pio, sm_rows, true); } } break; diff --git a/src/IODevices/SwitchMatrix.h b/src/IODevices/SwitchMatrix.h index 994da12..8739b52 100644 --- a/src/IODevices/SwitchMatrix.h +++ b/src/IODevices/SwitchMatrix.h @@ -11,9 +11,9 @@ #include "hardware/gpio.h" #include "hardware/pio.h" -#define SWITCH_MATRIX_BASE_PIN 0 -#define COLUMNS_BASE_PIN (SWITCH_MATRIX_BASE_PIN + 8) -#define MATRIX_SWITCHES 64 +#define COLUMNS_BASE_PIN 13 // GPIO 13-16 for columns, the only pins with required hardware on IO_16_8_1 board +#define NUM_COLUMNS 4 +#define MAX_ROWS 8 #define MATRIX_SWITCH_DEBOUNCE 2 class SwitchMatrix : public EventListener { @@ -23,55 +23,42 @@ class SwitchMatrix : public EventListener { _eventDispatcher = eD; _eventDispatcher->addListener(this, EVENT_POLL_EVENTS); _eventDispatcher->addListener(this, EVENT_READ_SWITCHES); - - pio = pio0; - sm_columns = 0; - sm_odd_rows = 2; - sm_even_rows = 1; } - void setActiveLow(); + void setActiveLow() { activeLow = true; } + void setNumRows(uint8_t n) { numRows = n; } void registerSwitch(byte p, byte n); void handleEvent(Event* event); void handleEvent(ConfigEvent* event) {} - void handleRowChanges(uint32_t raw, uint8_t even); + void handleRowChanges(uint32_t raw); - PIO pio; - int sm_columns; - int sm_even_rows; - int sm_odd_rows; + PIO pio = pio0; + int sm_columns = 0; + int sm_rows = 1; private: byte boardId; bool activeLow = false; + uint8_t numRows = 4; bool running = false; bool active = false; - byte mapping[MATRIX_SWITCHES] = {0}; - uint32_t lastStable[2] = {0}; - absolute_time_t debounceTime[MATRIX_SWITCHES] = {0}; - + byte mapping[NUM_COLUMNS * MAX_ROWS] = {0}; + uint32_t lastStable = 0; + absolute_time_t debounceTime[NUM_COLUMNS * MAX_ROWS][2] = {0}; EventDispatcher* _eventDispatcher; static SwitchMatrix* instance; - static void __not_in_flash_func(onOddRowChanges)() { + static void __not_in_flash_func(onRowChanges)() { // IRQ0 clear pio0_hw->irq = 1u << 0; - uint32_t raw = pio_sm_get_blocking(instance->pio, instance->sm_odd_rows); - instance->handleRowChanges(raw, 0); - } - - static void __not_in_flash_func(onEvenRowChanges)() { - // IRQ1 clear - pio0_hw->irq = 1u << 1; - - uint32_t raw = pio_sm_get_blocking(instance->pio, instance->sm_even_rows); - instance->handleRowChanges(raw, 1); + uint32_t raw = pio_sm_get_blocking(instance->pio, instance->sm_rows); + instance->handleRowChanges(raw); } }; diff --git a/src/IODevices/SwitchMatrix.pio b/src/IODevices/SwitchMatrix.pio deleted file mode 100644 index eeb6014..0000000 --- a/src/IODevices/SwitchMatrix.pio +++ /dev/null @@ -1,149 +0,0 @@ -.program columns_active_high_pio -.wrap_target - set x, 1 - mov isr, x ; initialize ISR with 0x00000001 - set x, 0 ; X = 0 - set y, 7 ; 8 columns (0-7) - -loop: - mov osr, isr ; copy ISR to OSR for output - out pins, 8 ; set 8 pins for columns, one is HIGH, others LOW - in x, 1 ; shift left ISR by 1 bit - nop [16] ; short delay to let other state machines read rows - jmp y-- loop ; decrement Y, loop until Y < 0 -.wrap - - -.program odd_rows_active_high_pio - ; Initialize X to all pins LOW. Max. 4x8 rows, so 32 bit, so 0x0: - set x, 0 ; X = 0x0 - mov y, x ; Y = 0x0 - mov isr, y ; ISR = 0x0 - -loop: - wait 0 PIN 8 ; wait for odd column 1 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 10 ; wait for odd column 3 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 12 ; wait for odd column 5 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 14 ; wait for odd column 7 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - - mov y, isr ; copy ISR to Y for comparison - jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) - jmp loop - -changed: - mov osr, y - push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it - irq 0 ; trigger interrupt 0 to notify the main CPU that a odd columns state has changed - mov x, y ; update X to the new odd columns state - jmp loop - - -.program even_rows_active_high_pio - ; Initialize X to all pins LOW. Max. 4x8 rows, so 32 bit, so 0x0: - set x, 0 ; X = 0x0 - mov y, x ; Y = 0x0 - mov isr, y ; ISR = 0x0 - -loop: - wait 0 PIN 9 ; wait for even column 2 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 11 ; wait for even column 4 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 13 ; wait for even column 6 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 15 ; wait for even column 8 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - - mov y, isr ; copy ISR to Y for comparison - jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) - jmp loop - -changed: - mov osr, y - push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it - irq 1 ; trigger interrupt 1 to notify the main CPU that a even columns state has changed - mov x, y ; update X to the new switch states - jmp loop - - -; ---------------------------------------------------------------------------------------------------------------------------- -; ---------------------------------------------------------------------------------------------------------------------------- - - -.program columns_active_low_pio -.wrap_target - set y, 1 - mov isr, ~y ; initialize ISR with 0xFFFFFFFE - set y, 0 ; Y = 0 - mov x, ~y ; X = 0xFFFFFFFF - set y, 7 ; 8 columns (0-7) - -loop: - mov osr, isr ; copy ISR to OSR for output - out pins, 8 ; set 8 pins for columns, one is HIGH, others LOW - in x, 1 ; shift left ISR by 1 bit - nop [16] ; short delay to let other state machines read rows - jmp y-- loop ; decrement Y, loop until Y < 0 -.wrap - - -.program odd_rows_active_low_pio - ; Initialize X to all pins HIGH. Max. 4x8 rows, so 32 bit: - set x, 0 ; X = 0x0 - mov y, ~x ; Y = 0xFFFFFFFF - mov x, y ; X = 0xFFFFFFFF - mov isr, y ; ISR = 0xFFFFFFFF - -loop: - wait 0 PIN 8 ; wait for odd column 1 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 10 ; wait for odd column 3 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 12 ; wait for odd column 5 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 14 ; wait for odd column 7 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - - mov y, isr ; copy ISR to Y for comparison - jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) - jmp loop - -changed: - mov osr, y - push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it - irq 0 ; trigger interrupt 0 to notify the main CPU that a odd columns state has changed - mov x, y ; update X to the new odd columns state - jmp loop - - -.program even_rows_active_low_pio - ; Initialize X to all pins HIGH. Max. 4x8 rows, so 32 bit: - set x, 0 ; X = 0x0 - mov y, ~x ; Y = 0xFFFFFFFF - mov x, y ; X = 0xFFFFFFFF - mov isr, y ; ISR = 0xFFFFFFFF - -loop: - wait 0 PIN 9 ; wait for even column 2 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 11 ; wait for even column 4 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 13 ; wait for even column 6 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 15 ; wait for even column 8 - in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - - mov y, isr ; copy ISR to Y for comparison - jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) - jmp loop - -changed: - mov osr, y - push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it - irq 1 ; trigger interrupt 1 to notify the main CPU that a even columns state has changed - mov x, y ; update X to the new switch states - jmp loop diff --git a/src/IODevices/SwitchMatrixPIO/ActiveHigh4Columns.pio b/src/IODevices/SwitchMatrixPIO/ActiveHigh4Columns.pio new file mode 100644 index 0000000..c054f12 --- /dev/null +++ b/src/IODevices/SwitchMatrixPIO/ActiveHigh4Columns.pio @@ -0,0 +1,15 @@ +.program active_high_4_columns_pio +.wrap_target + set x, 1 + mov isr, x ; initialize ISR with 0x00000001 + set x, 0 ; X = 0 + set y, 3 ; 4 columns (0-3) + nop [16] ; short delay to let other state machines perform debouncing + +loop: + mov osr, isr ; copy ISR to OSR for output + out pins, 4 ; set 4 pins for columns, one is HIGH, others LOW + in x, 1 ; shift left ISR by 1 bit + nop [16] ; short delay to let other state machines read rows + jmp y-- loop ; decrement Y, loop until Y < 0 +.wrap diff --git a/src/IODevices/SwitchMatrixPIO/ActiveHigh4Rows.pio b/src/IODevices/SwitchMatrixPIO/ActiveHigh4Rows.pio new file mode 100644 index 0000000..2adad9d --- /dev/null +++ b/src/IODevices/SwitchMatrixPIO/ActiveHigh4Rows.pio @@ -0,0 +1,35 @@ +.program active_high_4_rows_pio + ; Initialize X to all pins LOW + set x, 0 ; X = 0x0 + mov y, x ; Y = 0x0 + mov isr, y ; ISR = 0x0 + mov osr, y ; ISR = 0x0 + +loop: + wait 0 PIN 4 ; wait for column 1 + in pins, 4 ; read 4 rows to ISR (shifting into lower 4 bits of the 32bit ISR) + wait 0 PIN 5 ; wait for column 2 + in pins, 4 ; read 4 rows to ISR (shifting into lower 4 bits of the 32bit ISR) + wait 0 PIN 6 ; wait for odd column 3 + in pins, 4 ; read 4 rows to ISR (shifting into lower 4 bits of the 32bit ISR) + wait 0 PIN 7 ; wait for odd column 4 + in pins, 4 ; read 4 rows to ISR (shifting into lower 4 bits of the 32bit ISR) + + mov y, isr ; copy ISR to X for comparison + jmp x!=y changed + + ; two consecutive identical reads required for debouncing + mov y, osr ; copy OSR to Y for comparison + jmp x!=y new_stable_state + + jmp loop + +changed: + mov x, isr ; update X to the new state + jmp loop + +new_stable_state: + mov osr, isr ; update OSR to the new state, used for debouncing + push block ; push ISR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it, ISR is empty after that! + irq 0 ; trigger interrupt 0 to notify the main CPU that matrix changed + jmp loop diff --git a/src/IODevices/SwitchMatrixPIO/ActiveHigh8Rows.pio b/src/IODevices/SwitchMatrixPIO/ActiveHigh8Rows.pio new file mode 100644 index 0000000..2bd87cb --- /dev/null +++ b/src/IODevices/SwitchMatrixPIO/ActiveHigh8Rows.pio @@ -0,0 +1,35 @@ +.program active_high_8_rows_pio + ; Initialize X to all pins LOW + set x, 0 ; X = 0x0 + mov y, x ; Y = 0x0 + mov isr, y ; ISR = 0x0 + mov osr, y ; ISR = 0x0 + +loop: + wait 0 PIN 4 ; wait for column 1 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 5 ; wait for column 2 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 6 ; wait for odd column 3 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 7 ; wait for odd column 4 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + + mov y, isr ; copy ISR to X for comparison + jmp x!=y changed + + ; two consecutive identical reads required for debouncing + mov y, osr ; copy OSR to Y for comparison + jmp x!=y new_stable_state + + jmp loop + +changed: + mov x, isr ; update X to the new state + jmp loop + +new_stable_state: + mov osr, isr ; update OSR to the new state, used for debouncing + push block ; push ISR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it, ISR is empty after that! + irq 0 ; trigger interrupt 0 to notify the main CPU that matrix changed + jmp loop diff --git a/src/IODevices/SwitchMatrixPIO/ActiveLow4Columns.pio b/src/IODevices/SwitchMatrixPIO/ActiveLow4Columns.pio new file mode 100644 index 0000000..ae3fa59 --- /dev/null +++ b/src/IODevices/SwitchMatrixPIO/ActiveLow4Columns.pio @@ -0,0 +1,16 @@ +.program active_low_4_columns_pio +.wrap_target + set y, 1 + mov isr, ~y ; initialize ISR with 0xFFFFFFFE + set y, 0 ; Y = 0 + mov x, ~y ; X = 0xFFFFFFFF + set y, 3 ; 4 columns (0-3) + nop [16] ; short delay to let other state machines perform debouncing + +loop: + mov osr, isr ; copy ISR to OSR for output + out pins, 4 ; set 4 pins for columns, one is LOW, others HIGH + in x, 1 ; shift left ISR by 1 bit + nop [16] ; short delay to let other state machines read rows + jmp y-- loop ; decrement Y, loop until Y < 0 +.wrap diff --git a/src/IODevices/SwitchMatrixPIO/ActiveLow4Rows.pio b/src/IODevices/SwitchMatrixPIO/ActiveLow4Rows.pio new file mode 100644 index 0000000..cdcc6b8 --- /dev/null +++ b/src/IODevices/SwitchMatrixPIO/ActiveLow4Rows.pio @@ -0,0 +1,37 @@ +.program active_low_4_rows_pio + ; Initialize X to all pins HIGH + set x, 0 ; X = 0x0 + mov y, ~x ; Y = 0xFFFFFFFF + mov x, y ; X = 0xFFFFFFFF + mov osr, y ; OSR = 0xFFFFFFFF + +loop: + set y, 0 ; X = 0x0 + mov isr, ~y ; ISR = 0xFFFFFFFF + wait 0 PIN 4 ; wait for column 1 + in pins, 4 ; read 4 rows to ISR (shifting into lower 4 bits of the 32bit ISR) + wait 0 PIN 5 ; wait for column 2 + in pins, 4 ; read 4 rows to ISR (shifting into lower 4 bits of the 32bit ISR) + wait 0 PIN 6 ; wait for odd column 3 + in pins, 4 ; read 4 rows to ISR (shifting into lower 4 bits of the 32bit ISR) + wait 0 PIN 7 ; wait for odd column 4 + in pins, 4 ; read 4 rows to ISR (shifting into lower 4 bits of the 32bit ISR) + + mov y, isr ; copy ISR to X for comparison + jmp x!=y changed + + ; two consecutive identical reads required for debouncing + mov y, osr ; copy OSR to Y for comparison + jmp x!=y new_stable_state + + jmp loop + +changed: + mov x, isr ; update X to the new state + jmp loop + +new_stable_state: + mov osr, isr ; update OSR to the new state, used for debouncing + push block ; push ISR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it, ISR is empty after that! + irq 0 ; trigger interrupt 0 to notify the main CPU that matrix changed + jmp loop diff --git a/src/IODevices/SwitchMatrixPIO/ActiveLow8Rows.pio b/src/IODevices/SwitchMatrixPIO/ActiveLow8Rows.pio new file mode 100644 index 0000000..a0b05bf --- /dev/null +++ b/src/IODevices/SwitchMatrixPIO/ActiveLow8Rows.pio @@ -0,0 +1,37 @@ +.program active_low_8_rows_pio + ; Initialize X to all pins HIGH + set x, 0 ; X = 0x0 + mov y, ~x ; Y = 0xFFFFFFFF + mov x, y ; X = 0xFFFFFFFF + mov osr, y ; OSR = 0xFFFFFFFF + +loop: + set y, 0 ; X = 0x0 + mov isr, ~y ; ISR = 0xFFFFFFFF + wait 0 PIN 4 ; wait for column 1 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 5 ; wait for column 2 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 6 ; wait for odd column 3 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + wait 0 PIN 7 ; wait for odd column 4 + in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) + + mov y, isr ; copy ISR to X for comparison + jmp x!=y changed + + ; two consecutive identical reads required for debouncing + mov y, osr ; copy OSR to Y for comparison + jmp x!=y new_stable_state + + jmp loop + +changed: + mov x, isr ; update X to the new state + jmp loop + +new_stable_state: + mov osr, isr ; update OSR to the new state, used for debouncing + push block ; push ISR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it, ISR is empty after that! + irq 0 ; trigger interrupt 0 to notify the main CPU that matrix changed + jmp loop diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index cefebe1..a2a462f 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -1,11 +1,13 @@ #include "Switches.h" -#include "Switches.pio.h" +#include "SwitchesPIO/ActiveLow4Switches.pio.h" +#include "SwitchesPIO/ActiveLow8Switches.pio.h" +#include "SwitchesPIO/ActiveLow16Switches.pio.h" Switches* Switches::instance = nullptr; void Switches::registerSwitch(byte p, byte n) { - if (last < (MAX_SWITCHES - 1)) { + if (last < (numSwitches - 1) && p < numSwitches) { port[++last] = p; number[last] = n; active = true; @@ -16,33 +18,30 @@ void Switches::handleSwitchChanges(uint16_t raw) { absolute_time_t now = get_absolute_time(); uint16_t changed = raw ^ lastStable; // raw to raw comparison - for (int i = 0; i < MAX_SWITCHES; i++) { + for (int i = 0; i < numSwitches; i++) { if (number[i] == 0) continue; // Not registered - uint16_t mask = 1u << i; + uint16_t mask = 1u << (numSwitches - 1 - i); // the switches are in inverted order if (changed & mask) { + bool rawBit = (raw & mask) != 0; + bool switchState = !rawBit; // active-low: 0 = pressed + // Debounce - if (absolute_time_diff_us(debounceTime[i], now) >= + if (absolute_time_diff_us(debounceTime[i][switchState], now) >= SWITCH_DEBOUNCE * 1000) { - debounceTime[i] = now; - - bool rawBit = (raw & mask) != 0; - - // logical pressed state for active-low - bool newState = !rawBit; - - // store raw stable bit (not logical) - if (rawBit) - lastStable |= mask; // raw = 1 - else - lastStable &= ~mask; // raw = 0 + debounceTime[i][switchState] = now; + // Store the *raw* stable state + if (rawBit) + lastStable |= mask; // raw=1 + else + lastStable &= ~mask; // raw=0 // Dispatch all switch events as "local fast". // If a PWM output registered to it, we have "fast flip". Useful for // flippers, kick backs, jets and sling shots. _eventDispatcher->dispatch( - new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), newState, true)); + new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), switchState, true)); } } } @@ -67,30 +66,48 @@ void Switches::handleEvent(Event* event) { instance = this; running = true; - extern const pio_program_t switches_pio_program; - uint offset = pio_add_program(pio, &switches_pio_program); - pio_sm_config c = switches_pio_program_get_default_config(offset); + uint offset; + pio_sm_config c; + + switch (numSwitches) + { + case 4: + extern const pio_program_t active_low_4_switches_pio_program; + offset = pio_add_program(pio, &active_low_4_switches_pio_program); + c = active_low_4_switches_pio_program_get_default_config(offset); + break; + + case 8: + extern const pio_program_t active_low_8_switches_pio_program; + offset = pio_add_program(pio, &active_low_8_switches_pio_program); + c = active_low_8_switches_pio_program_get_default_config(offset); + break; + + case MAX_SWITCHES: + default: + extern const pio_program_t active_low_16_switches_pio_program; + offset = pio_add_program(pio, &active_low_16_switches_pio_program); + c = active_low_16_switches_pio_program_get_default_config(offset); + break; + } sm_config_set_in_pins(&c, SWITCHES_BASE_PIN); - sm_config_set_sideset_pins(&c, 15); // Side-set begins at GPIO 15 - sm_config_set_set_pins(&c, 15, 4); // Set begins at GPIO 15 - - // Connect 16 GPIOs to this PIO block - for (uint i = 0; i < 16; i++) { + if (MAX_SWITCHES == numSwitches) { + // Using GPIO 12-15 as switch inputs on IO_16_8_1 board requires resetting the sateful input after reading. + sm_config_set_sideset_pins(&c, 13); // Side-set begins at GPIO 13 + sm_config_set_set_pins(&c, 13, 4); // Set begins at GPIO 13 + } + // Connect GPIOs to this PIO block + for (uint i = 0; i < numSwitches; i++) { pio_gpio_init(pio, SWITCHES_BASE_PIN + i); } - // Set the pin direction at the PIO - pio_sm_set_consecutive_pindirs(pio, sm, SWITCHES_BASE_PIN, 16, false); - - sm_config_set_in_shift(&c, true, false, 16); - + pio_sm_set_consecutive_pindirs(pio, sm, SWITCHES_BASE_PIN, numSwitches, false); + sm_config_set_in_shift(&c, false, false, 0); pio_sm_init(pio, sm, offset, &c); - - irq_set_exclusive_handler(PIO0_IRQ_0, onSwitchChanges); - irq_set_enabled(PIO0_IRQ_0, true); - pio_set_irq0_source_enabled(pio, pis_interrupt0, true); - + irq_set_exclusive_handler(PIO0_IRQ_1, onSwitchChanges); + irq_set_enabled(PIO0_IRQ_1, true); + pio_set_irq0_source_enabled(pio, pis_interrupt1, true); pio_sm_set_enabled(pio, sm, true); } } diff --git a/src/IODevices/Switches.h b/src/IODevices/Switches.h index 982c0e0..1a8e1e8 100644 --- a/src/IODevices/Switches.h +++ b/src/IODevices/Switches.h @@ -15,7 +15,7 @@ #include "hardware/gpio.h" #include "hardware/pio.h" -#define SWITCHES_BASE_PIN 3 +#define SWITCHES_BASE_PIN 0 #define MAX_SWITCHES 16 #define SWITCH_DEBOUNCE 2 @@ -26,11 +26,9 @@ class Switches : public EventListener { _eventDispatcher = eD; _eventDispatcher->addListener(this, EVENT_POLL_EVENTS); _eventDispatcher->addListener(this, EVENT_READ_SWITCHES); - - pio = pio0; - sm = 0; } + void setNumSwitches(uint8_t n) { numSwitches = n; } void registerSwitch(byte p, byte n); void handleEvent(Event* event); @@ -39,11 +37,12 @@ class Switches : public EventListener { void handleSwitchChanges(uint16_t raw); - PIO pio; - int sm; + PIO pio = pio0; + int sm = 2; // State machine 0 and 1 are used by SwitchMatrix private: byte boardId; + uint8_t numSwitches = MAX_SWITCHES; bool running = false; bool active = false; @@ -52,15 +51,15 @@ class Switches : public EventListener { int last = -1; uint16_t lastStable = 0; - absolute_time_t debounceTime[MAX_SWITCHES] = {0}; + absolute_time_t debounceTime[MAX_SWITCHES][2] = {0}; EventDispatcher* _eventDispatcher; static Switches* instance; static void __not_in_flash_func(onSwitchChanges)() { - // IRQ0 clear - pio0_hw->irq = 1u << 0; + // IRQ1 clear + pio0_hw->irq = 1u << 1; // Get 16 bit from FIFO uint32_t raw = pio_sm_get_blocking(instance->pio, instance->sm); diff --git a/src/IODevices/Switches.pio b/src/IODevices/Switches.pio deleted file mode 100644 index 6dfe53b..0000000 --- a/src/IODevices/Switches.pio +++ /dev/null @@ -1,37 +0,0 @@ -.program switches_pio -.side_set 4 opt - - ; Initialize X to all pins HIGH. Max. 16 switches, so 16 bit, so 0xFFFF: - ; But "set" can only set 5 bits, so a max value of 31 (0x1F). - set x, 31 ; X = 0x1F - in x, 5 ; shift 5 bits from X into ISR, now ISR = 0x1F - in x, 5 ; shift 5 bits from X into ISR, now ISR = 0x3FF - in x, 5 ; shift 5 bits from X into ISR, now ISR = 0x7FFF - in x, 1 ; shift 1 bit from X into ISR, now ISR = 0xFFFF - mov x, isr ; copy ISR to X, now X = 0xFFFF - set y, 0 ; Y = 0x0 - -loop: - mov isr, y ; ISR = 0x0 - in pins, 16 ; read 16 switches to ISR (filling lower 16 bits of the 32bit ISR) - mov y, isr ; copy ISR to Y for comparison - jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) - jmp loop - -changed: - mov osr, y - push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it - irq 0 ; trigger interrupt 0 to notify the main CPU that a switch state has changed - mov x, y ; update X to the new switch states - set y, 0 ; Y = 0x0 - - ; Reset stateful pins (GPIO 15-18) - set pindirs, 0b1111 side 0 ; change direction of 4 pins (15-18) to output, set LOW - nop side 0b1111 ; set 4 pins to HIGH - nop side 0b1111 ; short delay - nop side 0b1111 ; short delay - nop side 0b1111 ; short delay - nop side 0 ; set LOW - set pindirs, 0 side 0 ; change direction all pins back to input - - jmp loop diff --git a/src/IODevices/SwitchesPIO/ActiveLow16Switches.pio b/src/IODevices/SwitchesPIO/ActiveLow16Switches.pio new file mode 100644 index 0000000..c2da94e --- /dev/null +++ b/src/IODevices/SwitchesPIO/ActiveLow16Switches.pio @@ -0,0 +1,48 @@ +.program active_low_16_switches_pio +.side_set 4 opt + ; Initialize X to all pins HIGH + set x, 0 ; X = 0x0 + mov y, ~x ; Y = 0xFFFFFFFF + mov x, y ; X = 0xFFFFFFFF + mov osr, y ; OSR = 0xFFFFFFFF + +loop: + set y, 0 ; X = 0x0 + mov isr, ~y ; ISR = 0xFFFFFFFF + in pins, 16 ; read 16 switches to ISR (filling lower 16 bits of the 32bit ISR) + + mov y, isr ; copy ISR to Y for comparison + jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) + + ; two consecutive identical reads required for debouncing + mov y, osr ; copy OSR to Y for comparison + jmp x!=y new_stable_state + + jmp loop + +changed: + mov x, isr ; update X to the new state + nop ; short delay for debouncing + nop ; short delay for debouncing + nop ; short delay for debouncing + nop ; short delay for debouncing + nop ; short delay for debouncing + nop ; short delay for debouncing + nop ; short delay for debouncing + jmp loop + +new_stable_state: + mov osr, isr ; update OSR to the new state, used for debouncing + push block ; push ISR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it, ISR is empty after that! + irq 1 ; trigger interrupt 1 to notify the main CPU that switches changed + + ; Reset stateful pins (GPIO 15-18) + set pindirs, 0b1111 side 0 ; change direction of 4 pins (15-18) to output, set LOW + nop side 0b1111 ; set 4 pins to HIGH + nop side 0b1111 ; short delay + nop side 0b1111 ; short delay + nop side 0b1111 ; short delay + nop side 0 ; set LOW + set pindirs, 0 side 0 ; change direction all pins back to input + + jmp loop diff --git a/src/IODevices/SwitchesPIO/ActiveLow4Switches.pio b/src/IODevices/SwitchesPIO/ActiveLow4Switches.pio new file mode 100644 index 0000000..371b6c6 --- /dev/null +++ b/src/IODevices/SwitchesPIO/ActiveLow4Switches.pio @@ -0,0 +1,31 @@ +.program active_low_4_switches_pio + ; Initialize X to all pins HIGH + set x, 0 ; X = 0x0 + mov y, ~x ; Y = 0xFFFFFFFF + mov x, y ; X = 0xFFFFFFFF + mov osr, y ; OSR = 0xFFFFFFFF + +loop: + set y, 0 ; X = 0x0 + mov isr, ~y ; ISR = 0xFFFFFFFF + in pins, 4 ; read 4 switches to ISR (filling lower 4 bits of the 32bit ISR) + + mov y, isr ; copy ISR to Y for comparison + jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) + + ; two consecutive identical reads required for debouncing + mov y, osr ; copy OSR to Y for comparison + jmp x!=y new_stable_state + + jmp loop + +changed: + mov x, isr ; update X to the new state + nop [16] ; short delay for debouncing + jmp loop + +new_stable_state: + mov osr, isr ; update OSR to the new state, used for debouncing + push block ; push ISR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it, ISR is empty after that! + irq 1 ; trigger interrupt 1 to notify the main CPU that switches changed + jmp loop diff --git a/src/IODevices/SwitchesPIO/ActiveLow8Switches.pio b/src/IODevices/SwitchesPIO/ActiveLow8Switches.pio new file mode 100644 index 0000000..245b535 --- /dev/null +++ b/src/IODevices/SwitchesPIO/ActiveLow8Switches.pio @@ -0,0 +1,31 @@ +.program active_low_8_switches_pio + ; Initialize X to all pins HIGH + set x, 0 ; X = 0x0 + mov y, ~x ; Y = 0xFFFFFFFF + mov x, y ; X = 0xFFFFFFFF + mov osr, y ; OSR = 0xFFFFFFFF + +loop: + set y, 0 ; X = 0x0 + mov isr, ~y ; ISR = 0xFFFFFFFF + in pins, 8 ; read 8 switches to ISR (filling lower 8 bits of the 32bit ISR) + + mov y, isr ; copy ISR to Y for comparison + jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) + + ; two consecutive identical reads required for debouncing + mov y, osr ; copy OSR to Y for comparison + jmp x!=y new_stable_state + + jmp loop + +changed: + mov x, isr ; update X to the new state + nop [16] ; short delay for debouncing + jmp loop + +new_stable_state: + mov osr, isr ; update OSR to the new state, used for debouncing + push block ; push ISR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it, ISR is empty after that! + irq 1 ; trigger interrupt 1 to notify the main CPU that switches changed + jmp loop From 34a81b6db19b87cabb570656dcfe73643c02f7dd Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 19 Nov 2025 20:28:34 +0100 Subject: [PATCH 089/102] added flicker on config transmission --- src/EffectsController.cpp | 28 ++++++---------------------- src/EffectsController.h | 5 +---- 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src/EffectsController.cpp b/src/EffectsController.cpp index 169deb0..218e029 100644 --- a/src/EffectsController.cpp +++ b/src/EffectsController.cpp @@ -83,10 +83,6 @@ void EffectsController::addEffect(EffectContainer *container) { stackEffectContainers[++stackCounter] = container; } -void EffectsController::attachBrightnessControl(byte port, byte poti) { - brightnessControl[--port] = poti; -} - void EffectsController::setBrightness(byte port, byte brightness) { ws2812FXDevices[--port][0]->setBrightness(brightness); ws2812FXbrightness[port] = brightness; @@ -142,6 +138,12 @@ void EffectsController::handleEvent(Event *event) { void EffectsController::handleEvent(ConfigEvent *event) { if (event->boardId == boardId) { + if (flickerState) + _ledBuiltInDevice->on(); + else + _ledBuiltInDevice->off(); + flickerState = !flickerState; + switch (event->topic) { case CONFIG_TOPIC_PLATFORM: platform = event->value; @@ -517,24 +519,6 @@ void EffectsController::update() { } } } - - if (brightnessControlBasePin > 0) { - if (millis() - brightnessUpdateInterval > - UPDATE_INTERVAL_WS2812FX_BRIGHTNESS) { - // Don't update the brightness too often. - brightnessUpdateInterval = millis(); - for (byte i = 0; i < PPUC_MAX_BRIGHTNESS_CONTROLS; i++) { - brightnessControlReads[i] = - analogRead(brightnessControlBasePin + i) / 4; - } - for (byte i = 0; i < PPUC_MAX_WS2812FX_DEVICES; i++) { - if (brightnessControl[i] > 0) { - setBrightness(i + 1, - brightnessControlReads[brightnessControl[i - 1]]); - } - } - } - } } void EffectsController::start() { diff --git a/src/EffectsController.h b/src/EffectsController.h index 280997b..410bd43 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -133,10 +133,7 @@ class EffectsController : public EventListener { byte ws2812FXbrightness[PPUC_MAX_WS2812FX_DEVICES] = {0}; EffectContainer* stackEffectContainers[EFFECT_STACK_SIZE]; int stackCounter = -1; - byte brightnessControl[PPUC_MAX_WS2812FX_DEVICES] = {0}; - byte brightnessControlReads[PPUC_MAX_BRIGHTNESS_CONTROLS] = {0}; - byte brightnessControlBasePin = 0; - + bool flickerState = false; int mode = 0; byte platform; From c213354c1d57959db729fe8b9b76c50d2c722572 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 20 Nov 2025 10:27:02 +0100 Subject: [PATCH 090/102] fixed switches base pins --- src/IODevices/SwitchMatrix.h | 2 +- src/IODevices/SwitchMatrixPIO/ActiveHigh8Rows.pio | 8 ++++---- src/IODevices/SwitchMatrixPIO/ActiveLow8Rows.pio | 8 ++++---- src/IODevices/Switches.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/IODevices/SwitchMatrix.h b/src/IODevices/SwitchMatrix.h index 8739b52..3aa0005 100644 --- a/src/IODevices/SwitchMatrix.h +++ b/src/IODevices/SwitchMatrix.h @@ -11,7 +11,7 @@ #include "hardware/gpio.h" #include "hardware/pio.h" -#define COLUMNS_BASE_PIN 13 // GPIO 13-16 for columns, the only pins with required hardware on IO_16_8_1 board +#define COLUMNS_BASE_PIN 15 // GPIO 15-18 for columns, the only pins with required hardware on IO_16_8_1 board #define NUM_COLUMNS 4 #define MAX_ROWS 8 #define MATRIX_SWITCH_DEBOUNCE 2 diff --git a/src/IODevices/SwitchMatrixPIO/ActiveHigh8Rows.pio b/src/IODevices/SwitchMatrixPIO/ActiveHigh8Rows.pio index 2bd87cb..160ac0e 100644 --- a/src/IODevices/SwitchMatrixPIO/ActiveHigh8Rows.pio +++ b/src/IODevices/SwitchMatrixPIO/ActiveHigh8Rows.pio @@ -6,13 +6,13 @@ mov osr, y ; ISR = 0x0 loop: - wait 0 PIN 4 ; wait for column 1 + wait 0 PIN 8 ; wait for column 1 in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 5 ; wait for column 2 + wait 0 PIN 9 ; wait for column 2 in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 6 ; wait for odd column 3 + wait 0 PIN 10 ; wait for odd column 3 in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 7 ; wait for odd column 4 + wait 0 PIN 11 ; wait for odd column 4 in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) mov y, isr ; copy ISR to X for comparison diff --git a/src/IODevices/SwitchMatrixPIO/ActiveLow8Rows.pio b/src/IODevices/SwitchMatrixPIO/ActiveLow8Rows.pio index a0b05bf..607d270 100644 --- a/src/IODevices/SwitchMatrixPIO/ActiveLow8Rows.pio +++ b/src/IODevices/SwitchMatrixPIO/ActiveLow8Rows.pio @@ -8,13 +8,13 @@ loop: set y, 0 ; X = 0x0 mov isr, ~y ; ISR = 0xFFFFFFFF - wait 0 PIN 4 ; wait for column 1 + wait 0 PIN 8 ; wait for column 1 in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 5 ; wait for column 2 + wait 0 PIN 9 ; wait for column 2 in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 6 ; wait for odd column 3 + wait 0 PIN 10 ; wait for odd column 3 in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) - wait 0 PIN 7 ; wait for odd column 4 + wait 0 PIN 11 ; wait for odd column 4 in pins, 8 ; read 8 rows to ISR (shifting into lower 8 bits of the 32bit ISR) mov y, isr ; copy ISR to X for comparison diff --git a/src/IODevices/Switches.h b/src/IODevices/Switches.h index 1a8e1e8..ac90349 100644 --- a/src/IODevices/Switches.h +++ b/src/IODevices/Switches.h @@ -15,7 +15,7 @@ #include "hardware/gpio.h" #include "hardware/pio.h" -#define SWITCHES_BASE_PIN 0 +#define SWITCHES_BASE_PIN 3 #define MAX_SWITCHES 16 #define SWITCH_DEBOUNCE 2 From 0f62b16f39aa329369f430d86d518d846d063ffe Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 20 Nov 2025 18:57:39 +0100 Subject: [PATCH 091/102] fixed interrupt 1, made interrupt handler public --- src/IODevices/SwitchMatrix.h | 22 +++++++++++----------- src/IODevices/Switches.cpp | 2 +- src/IODevices/Switches.h | 22 +++++++++++----------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/IODevices/SwitchMatrix.h b/src/IODevices/SwitchMatrix.h index 3aa0005..8465def 100644 --- a/src/IODevices/SwitchMatrix.h +++ b/src/IODevices/SwitchMatrix.h @@ -39,7 +39,17 @@ class SwitchMatrix : public EventListener { int sm_columns = 0; int sm_rows = 1; - private: + static SwitchMatrix* instance; + + static void __not_in_flash_func(onRowChanges)() { + // IRQ0 clear + pio0_hw->irq = 1u << 0; + + uint32_t raw = pio_sm_get_blocking(instance->pio, instance->sm_rows); + instance->handleRowChanges(raw); + } + + private: byte boardId; bool activeLow = false; uint8_t numRows = 4; @@ -50,16 +60,6 @@ class SwitchMatrix : public EventListener { uint32_t lastStable = 0; absolute_time_t debounceTime[NUM_COLUMNS * MAX_ROWS][2] = {0}; EventDispatcher* _eventDispatcher; - - static SwitchMatrix* instance; - - static void __not_in_flash_func(onRowChanges)() { - // IRQ0 clear - pio0_hw->irq = 1u << 0; - - uint32_t raw = pio_sm_get_blocking(instance->pio, instance->sm_rows); - instance->handleRowChanges(raw); - } }; #endif diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index a2a462f..b824577 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -107,7 +107,7 @@ void Switches::handleEvent(Event* event) { pio_sm_init(pio, sm, offset, &c); irq_set_exclusive_handler(PIO0_IRQ_1, onSwitchChanges); irq_set_enabled(PIO0_IRQ_1, true); - pio_set_irq0_source_enabled(pio, pis_interrupt1, true); + pio_set_irq1_source_enabled(pio, pis_interrupt1, true); pio_sm_set_enabled(pio, sm, true); } } diff --git a/src/IODevices/Switches.h b/src/IODevices/Switches.h index ac90349..6bbabc8 100644 --- a/src/IODevices/Switches.h +++ b/src/IODevices/Switches.h @@ -40,6 +40,17 @@ class Switches : public EventListener { PIO pio = pio0; int sm = 2; // State machine 0 and 1 are used by SwitchMatrix + static Switches* instance; + + static void __not_in_flash_func(onSwitchChanges)() { + // IRQ1 clear + pio0_hw->irq = 1u << 1; + + // Get 16 bit from FIFO + uint32_t raw = pio_sm_get_blocking(instance->pio, instance->sm); + instance->handleSwitchChanges(raw & 0xFFFF); + } + private: byte boardId; uint8_t numSwitches = MAX_SWITCHES; @@ -54,17 +65,6 @@ class Switches : public EventListener { absolute_time_t debounceTime[MAX_SWITCHES][2] = {0}; EventDispatcher* _eventDispatcher; - - static Switches* instance; - - static void __not_in_flash_func(onSwitchChanges)() { - // IRQ1 clear - pio0_hw->irq = 1u << 1; - - // Get 16 bit from FIFO - uint32_t raw = pio_sm_get_blocking(instance->pio, instance->sm); - instance->handleSwitchChanges(raw & 0xFFFF); - } }; #endif From 6ffe07530f3e710f742972339ee1699b9a2f412f Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 20 Nov 2025 20:15:45 +0100 Subject: [PATCH 092/102] fixed GPIO positions --- src/IODevices/Switches.cpp | 10 +++++----- src/IODevices/Switches.h | 2 +- src/IODevices/SwitchesPIO/ActiveLow16Switches.pio | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index b824577..59028e9 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -18,10 +18,10 @@ void Switches::handleSwitchChanges(uint16_t raw) { absolute_time_t now = get_absolute_time(); uint16_t changed = raw ^ lastStable; // raw to raw comparison - for (int i = 0; i < numSwitches; i++) { + for (int i = 0; i <= last; i++) { if (number[i] == 0) continue; // Not registered - uint16_t mask = 1u << (numSwitches - 1 - i); // the switches are in inverted order + uint16_t mask = 1u << (port[i] - SWITCHES_BASE_PIN); if (changed & mask) { bool rawBit = (raw & mask) != 0; @@ -93,9 +93,9 @@ void Switches::handleEvent(Event* event) { sm_config_set_in_pins(&c, SWITCHES_BASE_PIN); if (MAX_SWITCHES == numSwitches) { - // Using GPIO 12-15 as switch inputs on IO_16_8_1 board requires resetting the sateful input after reading. - sm_config_set_sideset_pins(&c, 13); // Side-set begins at GPIO 13 - sm_config_set_set_pins(&c, 13, 4); // Set begins at GPIO 13 + // Using GPIO 15-18 as switch inputs on IO_16_8_1 board requires resetting the sateful input after reading. + sm_config_set_set_pins(&c, 15, 4); // Set begins at GPIO 15 for 4 pins + sm_config_set_sideset_pins(&c, 15); // Side-set begins at GPIO 15 } // Connect GPIOs to this PIO block for (uint i = 0; i < numSwitches; i++) { diff --git a/src/IODevices/Switches.h b/src/IODevices/Switches.h index 6bbabc8..da51581 100644 --- a/src/IODevices/Switches.h +++ b/src/IODevices/Switches.h @@ -17,7 +17,7 @@ #define SWITCHES_BASE_PIN 3 #define MAX_SWITCHES 16 -#define SWITCH_DEBOUNCE 2 +#define SWITCH_DEBOUNCE 20 class Switches : public EventListener { public: diff --git a/src/IODevices/SwitchesPIO/ActiveLow16Switches.pio b/src/IODevices/SwitchesPIO/ActiveLow16Switches.pio index c2da94e..4aaf7b9 100644 --- a/src/IODevices/SwitchesPIO/ActiveLow16Switches.pio +++ b/src/IODevices/SwitchesPIO/ActiveLow16Switches.pio @@ -28,7 +28,6 @@ changed: nop ; short delay for debouncing nop ; short delay for debouncing nop ; short delay for debouncing - nop ; short delay for debouncing jmp loop new_stable_state: @@ -37,12 +36,13 @@ new_stable_state: irq 1 ; trigger interrupt 1 to notify the main CPU that switches changed ; Reset stateful pins (GPIO 15-18) - set pindirs, 0b1111 side 0 ; change direction of 4 pins (15-18) to output, set LOW + set pindirs, 0b1111 ; change direction of 4 pins (15-18) to output + nop side 0 ; set LOW nop side 0b1111 ; set 4 pins to HIGH nop side 0b1111 ; short delay nop side 0b1111 ; short delay nop side 0b1111 ; short delay nop side 0 ; set LOW - set pindirs, 0 side 0 ; change direction all pins back to input + set pindirs, 0 ; change direction all pins back to input jmp loop From bf5ea614e82910fbc7d8673de1aab0b63bdb5bb7 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 23 Nov 2025 19:38:13 +0100 Subject: [PATCH 093/102] removed support for multiple serial connections as we don't have that on recent IO boards, actively empty FIFOs after reboot --- src/EventDispatcher/EventDispatcher.cpp | 180 ++++++++---------------- src/EventDispatcher/EventDispatcher.h | 15 +- src/IOBoardController.cpp | 2 +- src/PPUC.h | 4 +- src/main.cpp | 18 +-- 5 files changed, 74 insertions(+), 145 deletions(-) diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index 334fab3..f2a6b03 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -5,8 +5,6 @@ EventDispatcher::EventDispatcher() {} void EventDispatcher::setRS485ModePin(int pin) { rs485 = true; rs485Pin = pin; - pinMode(rs485Pin, OUTPUT); - digitalWrite(rs485Pin, LOW); // Read. } void EventDispatcher::setBoard(byte b) { board = b; } @@ -21,15 +19,7 @@ MultiCoreCrossLink *EventDispatcher::getMultiCoreCrossLink() { } void EventDispatcher::setCrossLinkSerial(HardwareSerial &reference) { - hwSerial[0] = (HardwareSerial *)&reference; - crossLink = 0; -} - -void EventDispatcher::addCrossLinkSerial(HardwareSerial &reference) { - hwSerial[++crossLink] = (HardwareSerial *)&reference; - hwSerial[crossLink]->begin(115200); - while (!hwSerial[crossLink]) { - } + hwSerial = (HardwareSerial *)&reference; } void EventDispatcher::addListener(EventListener *eventListener) { @@ -71,7 +61,8 @@ void EventDispatcher::dispatch(Event *event) { } } -void EventDispatcher::callListeners(Event *event, int sender, bool flush) { +void EventDispatcher::callListeners(Event *event, bool sendToOtherCore, + bool sendToRS485) { if (!event->localFast) { for (byte i = 0; i <= numListeners; i++) { if (event->sourceId == eventListenerFilters[i] || @@ -81,42 +72,19 @@ void EventDispatcher::callListeners(Event *event, int sender, bool flush) { } } - if (!rs485 || flush) { - // Send to other micro controller. But only if there's room left in write - // buffer. Otherwise the program will be blocked. The buffer gets full if - // the data is not fetched by the other controller for any reason. - // @todo Possible optimization to check hwSerial->availableForWrite() >= 6 - // failed on Arduino for unknown reason. - - if (crossLink != -1 /* && hwSerial->availableForWrite() >= 6 */) { - msg[0] = 0b11111111; - msg[1] = event->sourceId; - msg[2] = highByte(event->eventId); - msg[3] = lowByte(event->eventId); - msg[4] = event->value; - msg[5] = 0b10101010; - msg[6] = 0b01010101; - - for (int i = 0; i <= crossLink; i++) { - if (i != sender) { - hwSerial[i]->write(msg, 7); - } - } + if (rs485 && sendToRS485) { + msg[0] = 0b11111111; + msg[1] = event->sourceId; + msg[2] = highByte(event->eventId); + msg[3] = lowByte(event->eventId); + msg[4] = event->value; + msg[5] = 0b10101010; + msg[6] = 0b01010101; - if (false && Serial) { - rp2040.idleOtherCore(); - Serial.print("Sent event: sourceId "); - Serial.print(event->sourceId); - Serial.print(", eventId "); - Serial.print(event->eventId, DEC); - Serial.print(", value "); - Serial.println(event->value, DEC); - rp2040.resumeOtherCore(); - } - } + hwSerial->write(msg, 7); } - if (multiCore && sender != -1 && event->sourceId != EVENT_NULL) { + if (multiCore && sendToOtherCore && event->sourceId != EVENT_NULL) { multiCoreCrossLink->pushEvent(event); } @@ -124,7 +92,7 @@ void EventDispatcher::callListeners(Event *event, int sender, bool flush) { delete event; } -void EventDispatcher::callListeners(ConfigEvent *event, int sender) { +void EventDispatcher::callListeners(ConfigEvent *event, bool sendToOtherCore) { for (byte i = 0; i <= numListeners; i++) { if (EVENT_CONFIGURATION == eventListenerFilters[i] || EVENT_SOURCE_ANY == eventListenerFilters[i]) { @@ -132,31 +100,8 @@ void EventDispatcher::callListeners(ConfigEvent *event, int sender) { } } - if (sender != -1) { - if (crossLink != -1 /* && hwSerial->availableForWrite() >= 6 */) { - msg[0] = 0b11111111; - msg[1] = event->sourceId; - msg[2] = event->boardId; - msg[3] = event->topic; - msg[4] = event->index; - msg[5] = event->key; - msg[6] = (event->value >> 24) & 0xff; - msg[7] = (event->value >> 16) & 0xff; - msg[8] = (event->value >> 8) & 0xff; - msg[9] = event->value & 0xff; - msg[10] = 0b10101010; - msg[11] = 0b01010101; - - for (int i = 0; i <= crossLink; i++) { - if (i != sender) { - hwSerial[i]->write(msg, 12); - } - } - } - - if (multiCoreCrossLink && event->boardId == board) { - multiCoreCrossLink->pushConfigEvent(event); - } + if (multiCoreCrossLink && sendToOtherCore && event->boardId == board) { + multiCoreCrossLink->pushConfigEvent(event); } // delete the event and free the memory @@ -164,92 +109,81 @@ void EventDispatcher::callListeners(ConfigEvent *event, int sender) { } void EventDispatcher::update() { - if (!rs485) { + if (!rs485) { // We're on Core1, the EffectController. Transmit stacked + // events to Core0. for (int i = 0; i <= stackCounter; i++) { Event *event = stackEvents[i]; - // Integer MAX_CROSS_LINKS is always higher than crossLinks, so this - // parameters means "no sender, send to all". - callListeners(event, MAX_CROSS_LINKS, false); + callListeners(event, true, false); } // -1 means empty. stackCounter = -1; - } - - for (int i = 0; i <= crossLink; i++) { - if (hwSerial[i]->available() >= 7) { + } else { + if (hwSerial->available() >= 7) { bool success = false; - byte startByte = hwSerial[i]->read(); + byte startByte = hwSerial->read(); if (startByte == 255) { - byte sourceId = hwSerial[i]->read(); + byte sourceId = hwSerial->read(); if (sourceId != 0) { if (sourceId == EVENT_CONFIGURATION) { // Config Event has 12 bytes, 2 bytes are already parsed above. - while (hwSerial[i]->available() < 10) { + while (hwSerial->available() < 10) { } // We have a ConfigEvent. - byte boardId = hwSerial[i]->read(); - byte topic = hwSerial[i]->read(); - byte index = hwSerial[i]->read(); - byte key = hwSerial[i]->read(); - uint32_t value = (((uint32_t)hwSerial[i]->read()) << 24) + - (((uint32_t)hwSerial[i]->read()) << 16) + - (((uint32_t)hwSerial[i]->read()) << 8) + - hwSerial[i]->read(); - byte stopByte = hwSerial[i]->read(); + byte boardId = hwSerial->read(); + byte topic = hwSerial->read(); + byte index = hwSerial->read(); + byte key = hwSerial->read(); + uint32_t value = (((uint32_t)hwSerial->read()) << 24) + + (((uint32_t)hwSerial->read()) << 16) + + (((uint32_t)hwSerial->read()) << 8) + + hwSerial->read(); + byte stopByte = hwSerial->read(); if (stopByte == 0b10101010) { - stopByte = hwSerial[i]->read(); + stopByte = hwSerial->read(); if (stopByte == 0b01010101) { success = true; callListeners( - new ConfigEvent(boardId, topic, index, key, value), i); + new ConfigEvent(boardId, topic, index, key, value), true); } } } else { - word eventId = word(hwSerial[i]->read(), hwSerial[i]->read()); + word eventId = word(hwSerial->read(), hwSerial->read()); if (eventId != 0) { - byte value = hwSerial[i]->read(); - byte stopByte = hwSerial[i]->read(); + byte value = hwSerial->read(); + byte stopByte = hwSerial->read(); if (stopByte == 0b10101010) { - stopByte = hwSerial[i]->read(); + stopByte = hwSerial->read(); if (stopByte == 0b01010101) { success = true; - callListeners(new Event((char)sourceId, eventId, value), i, + callListeners(new Event((char)sourceId, eventId, value), true, false); if (sourceId == EVENT_POLL_EVENTS && board == value) { - if (rs485) { - digitalWrite(rs485Pin, HIGH); // Write. - // Wait until the RS485 converter switched to write mode. - delayMicroseconds(RS485_MODE_SWITCH_DELAY); - } + digitalWrite(rs485Pin, HIGH); // Write. + // Wait until the RS485 converter switched to write mode. + delayMicroseconds(RS485_MODE_SWITCH_DELAY); for (int k = 0; k <= stackCounter; k++) { Event *event = stackEvents[k]; - // Integer MAX_CROSS_LINKS is always higher than - // crossLinks, so this parameters means "no sender, send - // to all". - callListeners(event, MAX_CROSS_LINKS, true); + callListeners(event, true, true); } // -1 means empty. stackCounter = -1; // Send NULL event to indicate that transmission is // complete. - callListeners(new Event(EVENT_NULL, 1, board), - MAX_CROSS_LINKS, true); + callListeners(new Event(EVENT_NULL, 1, board), false, true); lastPoll = millis(); - if (rs485) { - // Flush the serial buffer and wait until done. - hwSerial[i]->flush(); - digitalWrite(rs485Pin, LOW); // Read. - // Wait until the RS485 converter switched back to read - // mode. - delayMicroseconds(RS485_MODE_SWITCH_DELAY); - } + // Flush the serial buffer and wait until done. + hwSerial->flush(); + digitalWrite(rs485Pin, LOW); // Read. + // Wait until the RS485 converter switched back to read + // mode. + delayMicroseconds(RS485_MODE_SWITCH_DELAY); } else if (sourceId == EVENT_RUN) { running = true; } @@ -308,10 +242,10 @@ void EventDispatcher::update() { error = true; dispatch(new Event(EVENT_ERROR, 1, board)); - while (hwSerial[i]->available()) { - byte bits = hwSerial[i]->read(); - if (bits == 0b10101010 && hwSerial[i]->available()) { - bits = hwSerial[i]->read(); + while (hwSerial->available()) { + byte bits = hwSerial->read(); + if (bits == 0b10101010 && hwSerial->available()) { + bits = hwSerial->read(); if (bits == 0b01010101) { // Now we should be back in sync. break; @@ -325,12 +259,12 @@ void EventDispatcher::update() { if (multiCoreCrossLink) { if (multiCoreCrossLink->eventAvailable()) { Event *event = multiCoreCrossLink->popEvent(); - callListeners(event, -1, false); + callListeners(event, false, false); } if (multiCoreCrossLink->configEventAvailable()) { ConfigEvent *configEvent = multiCoreCrossLink->popConfigEvent(); - callListeners(configEvent, -1); + callListeners(configEvent, false); } } } diff --git a/src/EventDispatcher/EventDispatcher.h b/src/EventDispatcher/EventDispatcher.h index 9f58da5..5abd4b1 100644 --- a/src/EventDispatcher/EventDispatcher.h +++ b/src/EventDispatcher/EventDispatcher.h @@ -18,10 +18,6 @@ #define MAX_EVENT_LISTENERS 32 #endif -#ifndef MAX_CROSS_LINKS -#define MAX_CROSS_LINKS 8 -#endif - #ifndef EVENT_STACK_SIZE #define EVENT_STACK_SIZE 100 #endif @@ -40,8 +36,6 @@ class EventDispatcher { void setCrossLinkSerial(HardwareSerial& reference); - void addCrossLinkSerial(HardwareSerial& reference); - void addListener(EventListener* eventListener, char sourceId); void addListener(EventListener* eventListener); @@ -53,9 +47,9 @@ class EventDispatcher { uint32_t getLastPoll(); private: - void callListeners(Event* event, int sender, bool flush); + void callListeners(Event* event, bool sendToOtherCore, bool sendToRS485); - void callListeners(ConfigEvent* event, int sender); + void callListeners(ConfigEvent* event, bool sendToOtherCore); Event* stackEvents[EVENT_STACK_SIZE]; int stackCounter = -1; @@ -67,15 +61,14 @@ class EventDispatcher { byte msg[12]; bool rs485 = false; - int rs485Pin = 0; + uint8_t rs485Pin = 0; byte board = 255; bool error = false; uint32_t lastPoll; bool running = false; bool multiCore = false; - int crossLink = -1; - HardwareSerial* hwSerial[MAX_CROSS_LINKS]; + HardwareSerial* hwSerial; MultiCoreCrossLink* multiCoreCrossLink; }; diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 858bff1..8e8f0a0 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -15,8 +15,8 @@ IOBoardController::IOBoardController(int cT) { // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 -> 58.46 // to 935.3 boardId = 16 - ((int)((analogRead(28) + 29.23) / 58.46)); - _eventDispatcher->setRS485ModePin(2); _eventDispatcher->setBoard(boardId); + _eventDispatcher->setRS485ModePin(RS485_MODE_PIN); _eventDispatcher->setCrossLinkSerial(Serial1); _multiCoreCrossLink = new MultiCoreCrossLink(); _eventDispatcher->setMultiCoreCrossLink(_multiCoreCrossLink); diff --git a/src/PPUC.h b/src/PPUC.h index be26b4e..27b065d 100644 --- a/src/PPUC.h +++ b/src/PPUC.h @@ -12,11 +12,13 @@ #include -#include "PPUCTimings.h" #include "PPUCPlatforms.h" +#include "PPUCTimings.h" #define CONTROLLER_16_8_1 1 +#define RS485_MODE_PIN 2 + #include #endif diff --git a/src/main.cpp b/src/main.cpp index df14b31..efaf71e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,7 +47,7 @@ void setup() { uint32_t timeout = millis() + WAIT_FOR_SERIAL_DEBUGGER_TIMEOUT; Serial.begin(115200); - // Wait for a serial connection of a debugger via USB. + // Wait for a serial connection of a debugger via USB. Serial us USB CDC // The Pico implements USB itself so special care must be taken. Use // while(!Serial){} in the setup() code before printing anything so that it // waits for the USB connection to be established. @@ -68,15 +68,15 @@ void setup() { rp2040.restartCore1(); // RS485 connection. - Serial1.setTX(0); - Serial1.setRX(1); - Serial1.setFIFOSize(1024); // @todo find the right size. + Serial1.end(); // Deactivete UART to empty TX FIFO after reboot + delay(5); + pinMode(RS485_MODE_PIN, OUTPUT); + digitalWrite(RS485_MODE_PIN, LOW); // Read mode + delay(5); Serial1.begin(115200); - // The Pico implements USB itself so special care must be taken. Use - // while(!Serial){} in the setup() code before printing anything so that it - // waits for the USB connection to be established. - // https://community.platformio.org/t/serial-monitor-not-working/1512/25 - while (!Serial1) { + // Empty RX FIFO after reboot + while (Serial1.available()) { + Serial1.read(); } // The watchdog interferes with the USB debuging. From 1cd44001da11ecbe1537e0ce417cbef4b515b76b Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 27 Nov 2025 12:13:52 +0100 Subject: [PATCH 094/102] fixed swiztch reading, use std quque for events, remove event stack limit, limit IO boards to 8, use DIP switch 4 for debug on/off --- src/EffectsController.h | 2 +- src/EventDispatcher/CrossLinkDebugger.cpp | 2 +- src/EventDispatcher/Event.h | 1 + src/EventDispatcher/EventDispatcher.cpp | 44 +++---- src/EventDispatcher/EventDispatcher.h | 5 +- src/IOBoardController.cpp | 20 ++- src/IOBoardController.h | 4 +- src/IODevices/SwitchMatrix8x16.pio | 114 +++++++++++++++++ src/IODevices/Switches.cpp | 121 ++++++++++-------- src/IODevices/Switches.h | 30 +++-- .../SwitchesPIO/ActiveLow16Switches.pio | 24 ++-- .../SwitchesPIO/ActiveLow4Switches.pio | 23 ++-- .../SwitchesPIO/ActiveLow8Switches.pio | 23 ++-- src/PPUCTimings.h | 6 +- src/main.cpp | 55 ++++---- 15 files changed, 308 insertions(+), 166 deletions(-) create mode 100644 src/IODevices/SwitchMatrix8x16.pio diff --git a/src/EffectsController.h b/src/EffectsController.h index 410bd43..f27b579 100644 --- a/src/EffectsController.h +++ b/src/EffectsController.h @@ -59,7 +59,7 @@ class EffectsController : public EventListener { if (controllerType == CONTROLLER_16_8_1) { // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 // -> 58.46 to 935.3 - boardId = 16 - ((int)((analogRead(28) + 29.23) / 58.46)); + boardId = (16 - ((int)((analogRead(28) + 29.23) / 58.46))) & 0b0111; _ledBuiltInDevice = new LedBuiltInDevice(); _ledBuiltInDevice->on(); diff --git a/src/EventDispatcher/CrossLinkDebugger.cpp b/src/EventDispatcher/CrossLinkDebugger.cpp index b731403..6a7c287 100644 --- a/src/EventDispatcher/CrossLinkDebugger.cpp +++ b/src/EventDispatcher/CrossLinkDebugger.cpp @@ -9,7 +9,7 @@ CrossLinkDebugger::CrossLinkDebugger() { Serial.print("PPUC board #"); // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 -> 58.46 // to 935.3 - Serial.println(16 - ((int)((analogRead(28) + 29.23) / 58.46))); + Serial.println((16 - ((int)((analogRead(28) + 29.23) / 58.46))) & 0b0111); Serial.println("PPUC core #0 started"); Serial.println("PPUC CrossLinkDebugger"); Serial.println("----------------------"); diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 9850437..87d1dbb 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -63,6 +63,7 @@ #define CONFIG_TOPIC_MIN_PULSE_TIME 77 // "M" #define CONFIG_TOPIC_FROM 77 // "M" #define CONFIG_TOPIC_MIN_INTENSITY 77 // "M" +#define CONFIG_TOPIC_DEBOUNCE_TIME 77 // "M" #define CONFIG_TOPIC_NUMBER 78 // "N" #define CONFIG_TOPIC_AMOUNT_LEDS 79 // "O" #define CONFIG_TOPIC_NUM_ROWS 79 // "O" diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index f2a6b03..9b6434e 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -36,28 +36,22 @@ void EventDispatcher::addListener(EventListener *eventListener, char sourceId) { void EventDispatcher::dispatch(Event *event) { if (EVENT_RESET == event->sourceId) { // Force immediate handling of the reset event. Forget about the others. - for (int i = 0; i <= stackCounter; i++) { - if (stackEvents[i]) { - delete stackEvents[i]; - } + while (!eventQueue.empty()) { + Event *e = eventQueue.front(); + eventQueue.pop(); + delete e; } - stackCounter = -1; } - if (stackCounter < (EVENT_STACK_SIZE - 1)) { - stackEvents[++stackCounter] = event; + eventQueue.push(event); - if (event->localFast) { - for (byte i = 0; i <= numListeners; i++) { - if (event->sourceId == eventListenerFilters[i] || - EVENT_SOURCE_ANY == eventListenerFilters[i]) { - eventListeners[i]->handleEvent(event); - } + if (event->localFast) { + for (byte i = 0; i <= numListeners; i++) { + if (event->sourceId == eventListenerFilters[i] || + EVENT_SOURCE_ANY == eventListenerFilters[i]) { + eventListeners[i]->handleEvent(event); } } - } else { - // Too many events stacked, delete the event and free the memory. - delete event; } } @@ -111,12 +105,11 @@ void EventDispatcher::callListeners(ConfigEvent *event, bool sendToOtherCore) { void EventDispatcher::update() { if (!rs485) { // We're on Core1, the EffectController. Transmit stacked // events to Core0. - for (int i = 0; i <= stackCounter; i++) { - Event *event = stackEvents[i]; - callListeners(event, true, false); + while (!eventQueue.empty()) { + Event *e = eventQueue.front(); + eventQueue.pop(); + callListeners(e, true, false); } - // -1 means empty. - stackCounter = -1; } else { if (hwSerial->available() >= 7) { bool success = false; @@ -165,12 +158,11 @@ void EventDispatcher::update() { // Wait until the RS485 converter switched to write mode. delayMicroseconds(RS485_MODE_SWITCH_DELAY); - for (int k = 0; k <= stackCounter; k++) { - Event *event = stackEvents[k]; - callListeners(event, true, true); + while (!eventQueue.empty()) { + Event *e = eventQueue.front(); + eventQueue.pop(); + callListeners(e, true, true); } - // -1 means empty. - stackCounter = -1; // Send NULL event to indicate that transmission is // complete. diff --git a/src/EventDispatcher/EventDispatcher.h b/src/EventDispatcher/EventDispatcher.h index 5abd4b1..bcdabb7 100644 --- a/src/EventDispatcher/EventDispatcher.h +++ b/src/EventDispatcher/EventDispatcher.h @@ -10,6 +10,8 @@ #include +#include + #include "Event.h" #include "EventListener.h" #include "MultiCoreCrossLink.h" @@ -51,8 +53,7 @@ class EventDispatcher { void callListeners(ConfigEvent* event, bool sendToOtherCore); - Event* stackEvents[EVENT_STACK_SIZE]; - int stackCounter = -1; + std::queue eventQueue; EventListener* eventListeners[MAX_EVENT_LISTENERS]; char eventListenerFilters[MAX_EVENT_LISTENERS]; diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 40906ff..abe4724 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -2,6 +2,8 @@ #include "EventDispatcher/CrossLinkDebugger.h" +#define SWITCH_DEBOUNCE 10 + IOBoardController::IOBoardController(int cT) { _eventDispatcher = new EventDispatcher(); _eventDispatcher->addListener(this, EVENT_CONFIGURATION); @@ -15,6 +17,11 @@ IOBoardController::IOBoardController(int cT) { // Read bordID. Ideal value at 10bit resolution: (DIP+1)*1023*2/35 -> 58.46 // to 935.3 boardId = 16 - ((int)((analogRead(28) + 29.23) / 58.46)); + m_debug = (boardId & 0b1000) != 0; + if (m_debug) { + boardId -= 8; + } + _eventDispatcher->setBoard(boardId); _eventDispatcher->setRS485ModePin(RS485_MODE_PIN); _eventDispatcher->setCrossLinkSerial(Serial1); @@ -31,6 +38,12 @@ IOBoardController::IOBoardController(int cT) { void IOBoardController::update() { if (running) { + if (activeSwitches) { + // nop + } + if (activeSwitchMatrix) { + //switchMatrix()->update(); + } if (activePwmDevices) { pwmDevices()->update(); } @@ -98,6 +111,7 @@ void IOBoardController::handleEvent(ConfigEvent *event) { break; case CONFIG_TOPIC_NUMBER: _switchMatrix->registerSwitch((byte)port, event->value); + activeSwitchMatrix = true; break; } break; @@ -108,7 +122,11 @@ void IOBoardController::handleEvent(ConfigEvent *event) { port = event->value; break; case CONFIG_TOPIC_NUMBER: - _switches->registerSwitch((byte)port, event->value); + number = event->value; + break; + case CONFIG_TOPIC_DEBOUNCE_TIME: + _switches->registerSwitch((byte)port, number, event->value); + activeSwitches = true; break; } break; diff --git a/src/IOBoardController.h b/src/IOBoardController.h index 1dcfc24..b7414c5 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -40,7 +40,7 @@ class IOBoardController : public EventListener { void update(); - void debug() { m_debug = true; } + bool isDebug() { return m_debug; } private: PwmDevices *_pwmDevices; @@ -49,6 +49,8 @@ class IOBoardController : public EventListener { bool running = false; bool activePwmDevices = false; + bool activeSwitches = false; + bool activeSwitchMatrix = false; bool m_debug = false; int controllerType; diff --git a/src/IODevices/SwitchMatrix8x16.pio b/src/IODevices/SwitchMatrix8x16.pio new file mode 100644 index 0000000..9bd416c --- /dev/null +++ b/src/IODevices/SwitchMatrix8x16.pio @@ -0,0 +1,114 @@ +.program columns8x16_pio +.wrap_target + set y, 7 ; 8 columns (0-7) + +loop: + mov osr, y ; copy Y to OSR for output + out pins, 8 ; set 8 pins for columns, one is active LOW, others HIGH + nop [16] ; short delay to let other state machines read rows + jmp y-- loop ; decrement Y, loop until Y < 0 +.wrap + + +.program even_rows_high_pio + ; Initialize X to all pins HIGH. + set x, 0 ; X = 0x0 + mov y, ~x ; Y = 0xFFFFFFFF + mov x, y ; X = 0xFFFFFFFF + mov isr, y ; ISR = 0xFFFFFFFF + +loop: + wait 0 GPIO 10 ; wait for even column 8 + in pins, 16 ; read 16 rows to ISR (shifting into lower 16 bits of the 32bit ISR) + wait 0 GPIO 8 ; wait for even column 6 + in pins, 16 ; read 16 rows to ISR (shifting into lower 16 bits of the 32bit ISR) + + mov y, isr ; copy ISR to Y for comparison + jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) + jmp loop + +changed: + mov osr, y + push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it + irq 1 ; trigger interrupt 1 to notify the main CPU that a even columns state has changed + mov x, y ; update X to the new switch states + jmp loop + + +.program odd_rows_high_pio + ; Initialize X to all pins HIGH. + set x, 0 ; X = 0x0 + mov y, ~x ; Y = 0xFFFFFFFF + mov x, y ; X = 0xFFFFFFFF + mov isr, y ; ISR = 0xFFFFFFFF + +loop: + wait 0 GPIO 9 ; wait for odd column 7 + in pins, 16 ; read 16 rows to ISR (shifting into lower 16 bits of the 32bit ISR) + wait 0 GPIO 7 ; wait for odd column 5 + in pins, 16 ; read 16 rows to ISR (shifting into lower 16 bits of the 32bit ISR) + + mov y, isr ; copy ISR to Y for comparison + jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) + jmp loop + +changed: + mov osr, y + push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it + irq 0 ; trigger interrupt 0 to notify the main CPU that a odd columns state has changed + mov x, y ; update X to the new odd columns state + jmp loop + + +; IMPORTANT: +; The "low" PIO programs must run on a separate PIO instance from the "high" PIO programs, +; because of the limitation of interrupts per PIO instance (only 2). + +.program even_rows_low_pio + ; Initialize X to all pins HIGH. + set x, 0 ; X = 0x0 + mov y, ~x ; Y = 0xFFFFFFFF + mov x, y ; X = 0xFFFFFFFF + mov isr, y ; ISR = 0xFFFFFFFF + +loop: + wait 0 GPIO 6 ; wait for even column 4 + in pins, 16 ; read 16 rows to ISR (shifting into lower 16 bits of the 32bit ISR) + wait 0 GPIO 4 ; wait for even column 2 + in pins, 16 ; read 16 rows to ISR (shifting into lower 16 bits of the 32bit ISR) + + mov y, isr ; copy ISR to Y for comparison + jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) + jmp loop + +changed: + mov osr, y + push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it + irq 1 ; trigger interrupt 1 to notify the main CPU that a even columns state has changed + mov x, y ; update X to the new switch states + jmp loop + + +.program odd_rows_low_pio + ; Initialize X to all pins HIGH. + set x, 0 ; X = 0x0 + mov y, ~x ; Y = 0xFFFFFFFF + mov x, y ; X = 0xFFFFFFFF + mov isr, y ; ISR = 0xFFFFFFFF + +loop: + wait 0 GPIO 5 ; wait for odd column 3 + in pins, 16 ; read 16 rows to ISR (shifting into lower 16 bits of the 32bit ISR) + wait 0 GPIO 3 ; wait for odd column 1 + in pins, 16 ; read 16 rows to ISR (shifting into lower 16 bits of the 32bit ISR) + + mov y, isr ; copy ISR to Y for comparison + jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) + jmp loop + +changed: + mov osr, y + push block ; push OSR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it + irq 0 ; trigger interrupt 0 to notify the main CPU that a odd columns state has changed + mov x, y ; update X to the new odd columns state + jmp loop diff --git a/src/IODevices/Switches.cpp b/src/IODevices/Switches.cpp index 59028e9..4e30711 100644 --- a/src/IODevices/Switches.cpp +++ b/src/IODevices/Switches.cpp @@ -1,50 +1,57 @@ #include "Switches.h" +#include "SwitchesPIO/ActiveLow16Switches.pio.h" #include "SwitchesPIO/ActiveLow4Switches.pio.h" #include "SwitchesPIO/ActiveLow8Switches.pio.h" -#include "SwitchesPIO/ActiveLow16Switches.pio.h" Switches* Switches::instance = nullptr; -void Switches::registerSwitch(byte p, byte n) { +void Switches::registerSwitch(byte p, byte n, uint8_t debounceTimeMs) { if (last < (numSwitches - 1) && p < numSwitches) { port[++last] = p; number[last] = n; + debounceSetting[last] = debounceTimeMs; active = true; } } -void Switches::handleSwitchChanges(uint16_t raw) { - absolute_time_t now = get_absolute_time(); - uint16_t changed = raw ^ lastStable; // raw to raw comparison - - for (int i = 0; i <= last; i++) { - if (number[i] == 0) continue; // Not registered - - uint16_t mask = 1u << (port[i] - SWITCHES_BASE_PIN); - - if (changed & mask) { - bool rawBit = (raw & mask) != 0; - bool switchState = !rawBit; // active-low: 0 = pressed - - // Debounce - if (absolute_time_diff_us(debounceTime[i][switchState], now) >= - SWITCH_DEBOUNCE * 1000) { - debounceTime[i][switchState] = now; - // Store the *raw* stable state - if (rawBit) - lastStable |= mask; // raw=1 +void Switches::handleSwitchChanges(uint32_t raw) { + uint32_t now = millis(); + uint32_t changed = raw ^ currentStable; + if (changed > 0) { + uint32_t allSwitchesMask = 0; + + for (int i = 0; i <= last; i++) { + uint32_t mask = 1u << (port[i] - SWITCHES_BASE_PIN); + allSwitchesMask |= mask; + + if (changed & mask) { + // Debounce + if ((debounceTime[i] + debounceSetting[i]) < now) { + debounceTime[i] = now; + bool switchState = ((raw & mask) != 0); + if (switchState) + currentStable |= mask; // set bit in lastStable to 1 else - lastStable &= ~mask; // raw=0 - - // Dispatch all switch events as "local fast". - // If a PWM output registered to it, we have "fast flip". Useful for - // flippers, kick backs, jets and sling shots. - _eventDispatcher->dispatch( - new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), switchState, true)); + currentStable &= ~mask; // set bit in lastStable to 0 + // Dispatch all switch events as "local fast". + // If a PWM output registered to it, we have "fast flip". Useful for + // flippers, kick backs, jets and sling shots. + _eventDispatcher->dispatch(new Event(EVENT_SOURCE_SWITCH, + word(0, number[i]), + switchState ? 1 : 0, true)); + // digitalWrite(LED_BUILTIN, switchState); + } } } + + // Set unregistered switches to raw value to for next comparison + currentStable = + (currentStable & allSwitchesMask) + (raw & ~allSwitchesMask); } + + // Push debounced state to PIO for next detection + pio_sm_put(pio, sm, ~currentStable); } void Switches::handleEvent(Event* event) { @@ -57,8 +64,10 @@ void Switches::handleEvent(Event* event) { // the IRQ handler. for (int i = 0; i <= last; i++) { if (number[i] != 0) { + uint16_t mask = 1u << (port[i] - SWITCHES_BASE_PIN); _eventDispatcher->dispatch( - new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), 0)); + new Event(EVENT_SOURCE_SWITCH, word(0, number[i]), + ((currentStable & mask) > 0) ? 1 : 0)); } } @@ -69,40 +78,44 @@ void Switches::handleEvent(Event* event) { uint offset; pio_sm_config c; - switch (numSwitches) - { - case 4: - extern const pio_program_t active_low_4_switches_pio_program; - offset = pio_add_program(pio, &active_low_4_switches_pio_program); - c = active_low_4_switches_pio_program_get_default_config(offset); - break; - - case 8: - extern const pio_program_t active_low_8_switches_pio_program; - offset = pio_add_program(pio, &active_low_8_switches_pio_program); - c = active_low_8_switches_pio_program_get_default_config(offset); - break; - - case MAX_SWITCHES: - default: - extern const pio_program_t active_low_16_switches_pio_program; - offset = pio_add_program(pio, &active_low_16_switches_pio_program); - c = active_low_16_switches_pio_program_get_default_config(offset); - break; + switch (numSwitches) { + case 4: + extern const pio_program_t active_low_4_switches_pio_program; + offset = pio_add_program(pio, &active_low_4_switches_pio_program); + c = active_low_4_switches_pio_program_get_default_config(offset); + break; + + case 8: + extern const pio_program_t active_low_8_switches_pio_program; + offset = pio_add_program(pio, &active_low_8_switches_pio_program); + c = active_low_8_switches_pio_program_get_default_config(offset); + break; + + case MAX_SWITCHES: + default: + extern const pio_program_t active_low_16_switches_pio_program; + offset = + pio_add_program(pio, &active_low_16_switches_pio_program); + c = active_low_16_switches_pio_program_get_default_config(offset); + break; } sm_config_set_in_pins(&c, SWITCHES_BASE_PIN); if (MAX_SWITCHES == numSwitches) { - // Using GPIO 15-18 as switch inputs on IO_16_8_1 board requires resetting the sateful input after reading. - sm_config_set_set_pins(&c, 15, 4); // Set begins at GPIO 15 for 4 pins - sm_config_set_sideset_pins(&c, 15); // Side-set begins at GPIO 15 + // Using GPIO 15-18 as switch inputs on IO_16_8_1 board requires + // resetting the sateful input after reading. + // Set begins at GPIO 15 for 4 pins. + sm_config_set_set_pins(&c, 15, 4); + // Side-set begins at GPIO 15. + sm_config_set_sideset_pins(&c, 15); } // Connect GPIOs to this PIO block for (uint i = 0; i < numSwitches; i++) { pio_gpio_init(pio, SWITCHES_BASE_PIN + i); } // Set the pin direction at the PIO - pio_sm_set_consecutive_pindirs(pio, sm, SWITCHES_BASE_PIN, numSwitches, false); + pio_sm_set_consecutive_pindirs(pio, sm, SWITCHES_BASE_PIN, + numSwitches, false); sm_config_set_in_shift(&c, false, false, 0); pio_sm_init(pio, sm, offset, &c); irq_set_exclusive_handler(PIO0_IRQ_1, onSwitchChanges); diff --git a/src/IODevices/Switches.h b/src/IODevices/Switches.h index da51581..e79e98d 100644 --- a/src/IODevices/Switches.h +++ b/src/IODevices/Switches.h @@ -17,7 +17,6 @@ #define SWITCHES_BASE_PIN 3 #define MAX_SWITCHES 16 -#define SWITCH_DEBOUNCE 20 class Switches : public EventListener { public: @@ -28,41 +27,46 @@ class Switches : public EventListener { _eventDispatcher->addListener(this, EVENT_READ_SWITCHES); } - void setNumSwitches(uint8_t n) { numSwitches = n; } - void registerSwitch(byte p, byte n); + void setNumSwitches(uint8_t n) { + numSwitches = n; + validSwitchMask = (1u << numSwitches) - 1; + } + void registerSwitch(byte p, byte n, uint8_t debounceTimeMs); void handleEvent(Event* event); void handleEvent(ConfigEvent* event) {} - void handleSwitchChanges(uint16_t raw); + void handleSwitchChanges(uint32_t raw); PIO pio = pio0; - int sm = 2; // State machine 0 and 1 are used by SwitchMatrix - + int sm = 2; // State machine 0 and 1 are used by SwitchMatrix + uint16_t validSwitchMask = (1u << MAX_SWITCHES) - 1; static Switches* instance; + uint8_t numSwitches = MAX_SWITCHES; static void __not_in_flash_func(onSwitchChanges)() { - // IRQ1 clear + // re-enable IRQ1 for next switch change (clear IRQ 1) pio0_hw->irq = 1u << 1; - // Get 16 bit from FIFO - uint32_t raw = pio_sm_get_blocking(instance->pio, instance->sm); - instance->handleSwitchChanges(raw & 0xFFFF); + // Get 32 bit from FIFO + uint32_t raw = pio_sm_get(instance->pio, instance->sm); + instance->handleSwitchChanges((~raw) & instance->validSwitchMask); } private: byte boardId; - uint8_t numSwitches = MAX_SWITCHES; + bool running = false; bool active = false; byte port[MAX_SWITCHES] = {0}; byte number[MAX_SWITCHES] = {0}; + uint8_t debounceSetting[MAX_SWITCHES] = {0}; + uint32_t debounceTime[MAX_SWITCHES] = {0}; int last = -1; - uint16_t lastStable = 0; - absolute_time_t debounceTime[MAX_SWITCHES][2] = {0}; + uint16_t currentStable = 0; EventDispatcher* _eventDispatcher; }; diff --git a/src/IODevices/SwitchesPIO/ActiveLow16Switches.pio b/src/IODevices/SwitchesPIO/ActiveLow16Switches.pio index 4aaf7b9..3f4bdbe 100644 --- a/src/IODevices/SwitchesPIO/ActiveLow16Switches.pio +++ b/src/IODevices/SwitchesPIO/ActiveLow16Switches.pio @@ -1,40 +1,39 @@ .program active_low_16_switches_pio .side_set 4 opt - ; Initialize X to all pins HIGH set x, 0 ; X = 0x0 - mov y, ~x ; Y = 0xFFFFFFFF - mov x, y ; X = 0xFFFFFFFF - mov osr, y ; OSR = 0xFFFFFFFF + mov osr, ~x + jmp reset_stateful_pins loop: - set y, 0 ; X = 0x0 - mov isr, ~y ; ISR = 0xFFFFFFFF - in pins, 16 ; read 16 switches to ISR (filling lower 16 bits of the 32bit ISR) - + mov isr, null ; ISR is 0x0 + in pins, 16 ; read 16 switches to ISR mov y, isr ; copy ISR to Y for comparison jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) - ; two consecutive identical reads required for debouncing + ; two consecutive identical reads required for first level of debouncing mov y, osr ; copy OSR to Y for comparison jmp x!=y new_stable_state jmp loop changed: - mov x, isr ; update X to the new state + mov x, y ; update X to the new state nop ; short delay for debouncing nop ; short delay for debouncing nop ; short delay for debouncing nop ; short delay for debouncing nop ; short delay for debouncing nop ; short delay for debouncing + jmp loop new_stable_state: - mov osr, isr ; update OSR to the new state, used for debouncing - push block ; push ISR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it, ISR is empty after that! + push ; push ISR to RX FIFO irq 1 ; trigger interrupt 1 to notify the main CPU that switches changed + pull ; pull debounced state from TX FIFO to OSR + mov x, osr ; update X to the new state from OSR +reset_stateful_pins: ; Reset stateful pins (GPIO 15-18) set pindirs, 0b1111 ; change direction of 4 pins (15-18) to output nop side 0 ; set LOW @@ -44,5 +43,4 @@ new_stable_state: nop side 0b1111 ; short delay nop side 0 ; set LOW set pindirs, 0 ; change direction all pins back to input - jmp loop diff --git a/src/IODevices/SwitchesPIO/ActiveLow4Switches.pio b/src/IODevices/SwitchesPIO/ActiveLow4Switches.pio index 371b6c6..de3aa17 100644 --- a/src/IODevices/SwitchesPIO/ActiveLow4Switches.pio +++ b/src/IODevices/SwitchesPIO/ActiveLow4Switches.pio @@ -1,31 +1,28 @@ .program active_low_4_switches_pio - ; Initialize X to all pins HIGH set x, 0 ; X = 0x0 - mov y, ~x ; Y = 0xFFFFFFFF - mov x, y ; X = 0xFFFFFFFF - mov osr, y ; OSR = 0xFFFFFFFF + mov osr, ~x loop: - set y, 0 ; X = 0x0 - mov isr, ~y ; ISR = 0xFFFFFFFF - in pins, 4 ; read 4 switches to ISR (filling lower 4 bits of the 32bit ISR) - + mov isr, null ; ISR is 0x0 + in pins, 8 ; read 4 switches to ISR mov y, isr ; copy ISR to Y for comparison jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) - ; two consecutive identical reads required for debouncing + ; two consecutive identical reads required for first level of debouncing mov y, osr ; copy OSR to Y for comparison jmp x!=y new_stable_state jmp loop changed: - mov x, isr ; update X to the new state - nop [16] ; short delay for debouncing + mov x, y ; update X to the new state + jmp loop new_stable_state: - mov osr, isr ; update OSR to the new state, used for debouncing - push block ; push ISR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it, ISR is empty after that! + push ; push ISR to RX FIFO irq 1 ; trigger interrupt 1 to notify the main CPU that switches changed + pull ; pull debounced state from TX FIFO to OSR + mov x, osr ; update X to the new state from OSR + jmp loop diff --git a/src/IODevices/SwitchesPIO/ActiveLow8Switches.pio b/src/IODevices/SwitchesPIO/ActiveLow8Switches.pio index 245b535..19c140a 100644 --- a/src/IODevices/SwitchesPIO/ActiveLow8Switches.pio +++ b/src/IODevices/SwitchesPIO/ActiveLow8Switches.pio @@ -1,31 +1,28 @@ .program active_low_8_switches_pio - ; Initialize X to all pins HIGH set x, 0 ; X = 0x0 - mov y, ~x ; Y = 0xFFFFFFFF - mov x, y ; X = 0xFFFFFFFF - mov osr, y ; OSR = 0xFFFFFFFF + mov osr, ~x loop: - set y, 0 ; X = 0x0 - mov isr, ~y ; ISR = 0xFFFFFFFF - in pins, 8 ; read 8 switches to ISR (filling lower 8 bits of the 32bit ISR) - + mov isr, null ; ISR is 0x0 + in pins, 8 ; read 8 switches to ISR mov y, isr ; copy ISR to Y for comparison jmp x!=y changed ; jump to "changed" if X (old state) != Y (new state) - ; two consecutive identical reads required for debouncing + ; two consecutive identical reads required for first level of debouncing mov y, osr ; copy OSR to Y for comparison jmp x!=y new_stable_state jmp loop changed: - mov x, isr ; update X to the new state - nop [16] ; short delay for debouncing + mov x, y ; update X to the new state + jmp loop new_stable_state: - mov osr, isr ; update OSR to the new state, used for debouncing - push block ; push ISR to FIFO, "block" waits until the CPU handled enough data in the FIFO, so we don't overflow it, ISR is empty after that! + push ; push ISR to RX FIFO irq 1 ; trigger interrupt 1 to notify the main CPU that switches changed + pull ; pull debounced state from TX FIFO to OSR + mov x, osr ; update X to the new state from OSR + jmp loop diff --git a/src/PPUCTimings.h b/src/PPUCTimings.h index 91b5929..821bc01 100644 --- a/src/PPUCTimings.h +++ b/src/PPUCTimings.h @@ -6,9 +6,9 @@ #ifndef PPUC_TIMINGS_h #define PPUC_TIMINGS_h -#define WAIT_FOR_EFFECT_CONTROLLER_RESET 3000 // 3 seconds -#define WAIT_FOR_SERIAL_DEBUGGER_TIMEOUT 1000 // 1 second -#define WAIT_FOR_IO_BOARD_BOOT 1000 // 1 second +#define WAIT_FOR_EFFECT_CONTROLLER_RESET 3000 // 3 seconds +#define WAIT_FOR_SERIAL_DEBUGGER_TIMEOUT 1000 // 1 second +#define WAIT_FOR_IO_BOARD_BOOT 1000 // 1 second #define WAIT_FOR_IO_BOARD_RESET \ (WAIT_FOR_SERIAL_DEBUGGER_TIMEOUT + WAIT_FOR_EFFECT_CONTROLLER_RESET + \ diff --git a/src/main.cpp b/src/main.cpp index efaf71e..ab2ba51 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -44,29 +44,6 @@ void setup() { // Overclock according to Raspberry Pi Pico SDK recommendations. set_sys_clock_khz(SYS_CLK_KHZ, true); - uint32_t timeout = millis() + WAIT_FOR_SERIAL_DEBUGGER_TIMEOUT; - - Serial.begin(115200); - // Wait for a serial connection of a debugger via USB. Serial us USB CDC - // The Pico implements USB itself so special care must be taken. Use - // while(!Serial){} in the setup() code before printing anything so that it - // waits for the USB connection to be established. - // https://community.platformio.org/t/serial-monitor-not-working/1512/25 - while (!Serial && millis() < timeout) { - } - - if (Serial) { - usb_debugging = true; - ioBoardController.debug(); - delay(10); - ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); - } else { - Serial.end(); - } - - core_0_initilized = true; - rp2040.restartCore1(); - // RS485 connection. Serial1.end(); // Deactivete UART to empty TX FIFO after reboot delay(5); @@ -79,12 +56,40 @@ void setup() { Serial1.read(); } - // The watchdog interferes with the USB debuging. - if (!usb_debugging) { + usb_debugging = ioBoardController.isDebug(); + + if (usb_debugging) { + pinMode(LED_BUILTIN, OUTPUT); + Serial.begin(115200); + delay(100); + // Wait for a serial connection of a debugger via USB CDC. + // The Pico implements USB itself so special care must be taken. Use + // while(!Serial){} in the setup() code before printing anything so that + // it waits for the USB connection to be established. + // https://community.platformio.org/t/serial-monitor-not-working/1512/25 + while (!Serial) { + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); + delay(100); + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); + delay(1000); + } + + Serial.println("USB Serial debugging active."); + // ioBoardController.eventDispatcher()->addListener(new CrossLinkDebugger()); + } else { + // The watchdog interferes with the USB debuging, so only start it + // if USB debugging is not active. if (!ITimer.attachInterruptInterval(1000000, watchdog)) { // @todo } } + + core_0_initilized = true; + rp2040.restartCore1(); } void setup1() { From 3980436beb7b2bdf6acd1323c3aea0e99c039c28 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 28 Jan 2026 22:07:00 +0100 Subject: [PATCH 095/102] fixed typos --- .github/workflows/io-bords.yml | 111 --------------------------------- src/IOBoardController.h | 8 --- src/main.cpp | 6 +- 3 files changed, 3 insertions(+), 122 deletions(-) delete mode 100644 .github/workflows/io-bords.yml diff --git a/.github/workflows/io-bords.yml b/.github/workflows/io-bords.yml deleted file mode 100644 index d1a42d3..0000000 --- a/.github/workflows/io-bords.yml +++ /dev/null @@ -1,111 +0,0 @@ -name: PPUC IO Boards - -on: - push: - pull_request: - schedule: - - cron: '0 9 * * *' # run at 08:00 UTC - -jobs: - version: - name: Detect version - runs-on: ubuntu-latest - outputs: - tag: ${{ steps.version.outputs.tag }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - id: version - run: | - VERSION_MAJOR=$(grep -Eo "FIRMWARE_VERSION_MAJOR\s+[0-9]+" src/PPUC.h | grep -Eo "[0-9]+") - VERSION_MINOR=$(grep -Eo "FIRMWARE_VERSION_MINOR\s+[0-9]+" src/PPUC.h | grep -Eo "[0-9]+") - VERSION_PATCH=$(grep -Eo "FIRMWARE_VERSION_PATCH\s+[0-9]+" src/PPUC.h | grep -Eo "[0-9]+") - TAG="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" - echo "${TAG}" - echo "tag=${TAG}" >> $GITHUB_OUTPUT - - name: Check git tag - if: startsWith(github.ref, 'refs/tags/v') - run: | - GIT_TAG="${GITHUB_REF#refs/tags/}" - EXPECTED_TAG="v${{ steps.version.outputs.tag }}" - if [[ "${GIT_TAG}" != "${EXPECTED_TAG}" ]]; then - echo "Error: Git tag (${GIT_TAG}) does not match version from PPUC.h (v${{ steps.version.outputs.tag }})" - exit 1 - fi - - pio-run: - name: Build and upload firmware - runs-on: ubuntu-latest - needs: [ version ] - - strategy: - fail-fast: false - matrix: - controller: ['IO_16_8_1'] - - steps: - - name: PPUC ${{ matrix.controller }} - uses: actions/checkout@v4 - - - name: Cache pip - uses: actions/cache@v4 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - - - name: Cache PlatformIO - uses: actions/cache@v4 - with: - path: ~/.platformio - key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - - - name: Set up Python - uses: actions/setup-python@v5 - - - name: Install PlatformIO - run: | - python -m pip install --upgrade pip - pip install --upgrade platformio - - - name: Build elf2uf2 from source - run: | - sudo apt update && sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi - git clone https://github.com/ckormanyos/elf2uf2.git - cd elf2uf2 - make all - sudo cp bin/elf2uf2 /usr/local/bin/ - cd .. - - - name: Run PlatformIO - run: | - pio run - - - name: Create UF2 file (using elf2uf2) - run: | - ELF_FILE=$(find .pio/build/ -name "*.elf" | head -n 1) - echo "Found ELF file: $ELF_FILE" - elf2uf2 "$ELF_FILE" "${ELF_FILE%.elf}.uf2" - cp ${ELF_FILE%.elf}.uf2 ${{ matrix.controller }}-${{ needs.version.outputs.tag }}.uf2 - - name: Upload UF2 artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ matrix.controller }}-firmware - path: | - ${{ matrix.controller }}-${{ needs.version.outputs.tag }}.uf2 - - post-build: - runs-on: ubuntu-latest - needs: [ version, pio-run ] - name: Release - steps: - - uses: actions/download-artifact@v4 - - name: Release - uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/v') - with: - draft: true - files: | - */*.uf2 diff --git a/src/IOBoardController.h b/src/IOBoardController.h index b7414c5..9e7240b 100644 --- a/src/IOBoardController.h +++ b/src/IOBoardController.h @@ -1,14 +1,6 @@ /* IOBoardController.h Created by Markus Kalkbrenner. - - GPIO0-7: Input (Switches) or low power output - GPIO8-15: Input (Switches) - GPIO16,17,18: UART TX, UART RX, RS485 Direction - GPIO19-24, 26, 27: Power Out (PWM) - GPIO25: Status-LED - GPIO28: ADC for Board ID - GPIO29: Reserve (z.B. für einen LED-Strip oder zweite Status-LED) */ #ifndef IOBOARDCONTROLLER_h diff --git a/src/main.cpp b/src/main.cpp index ab2ba51..a8381cf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,7 +32,7 @@ bool watchdog(struct repeating_timer *t) { } bool usb_debugging = false; -bool core_0_initilized = false; +bool core_0_initialized = false; // Each controller will be bound to its own core and has it's own // EventDispatcher. Only the EventDispatcher of IOBoardController @@ -88,12 +88,12 @@ void setup() { } } - core_0_initilized = true; + core_0_initialized = true; rp2040.restartCore1(); } void setup1() { - while (!core_0_initilized) { + while (!core_0_initialized) { } if (usb_debugging) { From 608951e6a5075440facaf4e48ed245eb1e65a7da Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 28 Jan 2026 23:12:49 +0100 Subject: [PATCH 096/102] pios --- .github/workflows/io-boards.yml | 111 ++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 .github/workflows/io-boards.yml diff --git a/.github/workflows/io-boards.yml b/.github/workflows/io-boards.yml new file mode 100644 index 0000000..d1a42d3 --- /dev/null +++ b/.github/workflows/io-boards.yml @@ -0,0 +1,111 @@ +name: PPUC IO Boards + +on: + push: + pull_request: + schedule: + - cron: '0 9 * * *' # run at 08:00 UTC + +jobs: + version: + name: Detect version + runs-on: ubuntu-latest + outputs: + tag: ${{ steps.version.outputs.tag }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - id: version + run: | + VERSION_MAJOR=$(grep -Eo "FIRMWARE_VERSION_MAJOR\s+[0-9]+" src/PPUC.h | grep -Eo "[0-9]+") + VERSION_MINOR=$(grep -Eo "FIRMWARE_VERSION_MINOR\s+[0-9]+" src/PPUC.h | grep -Eo "[0-9]+") + VERSION_PATCH=$(grep -Eo "FIRMWARE_VERSION_PATCH\s+[0-9]+" src/PPUC.h | grep -Eo "[0-9]+") + TAG="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" + echo "${TAG}" + echo "tag=${TAG}" >> $GITHUB_OUTPUT + - name: Check git tag + if: startsWith(github.ref, 'refs/tags/v') + run: | + GIT_TAG="${GITHUB_REF#refs/tags/}" + EXPECTED_TAG="v${{ steps.version.outputs.tag }}" + if [[ "${GIT_TAG}" != "${EXPECTED_TAG}" ]]; then + echo "Error: Git tag (${GIT_TAG}) does not match version from PPUC.h (v${{ steps.version.outputs.tag }})" + exit 1 + fi + + pio-run: + name: Build and upload firmware + runs-on: ubuntu-latest + needs: [ version ] + + strategy: + fail-fast: false + matrix: + controller: ['IO_16_8_1'] + + steps: + - name: PPUC ${{ matrix.controller }} + uses: actions/checkout@v4 + + - name: Cache pip + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Cache PlatformIO + uses: actions/cache@v4 + with: + path: ~/.platformio + key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + + - name: Set up Python + uses: actions/setup-python@v5 + + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + + - name: Build elf2uf2 from source + run: | + sudo apt update && sudo apt install -y cmake gcc-arm-none-eabi libnewlib-arm-none-eabi + git clone https://github.com/ckormanyos/elf2uf2.git + cd elf2uf2 + make all + sudo cp bin/elf2uf2 /usr/local/bin/ + cd .. + + - name: Run PlatformIO + run: | + pio run + + - name: Create UF2 file (using elf2uf2) + run: | + ELF_FILE=$(find .pio/build/ -name "*.elf" | head -n 1) + echo "Found ELF file: $ELF_FILE" + elf2uf2 "$ELF_FILE" "${ELF_FILE%.elf}.uf2" + cp ${ELF_FILE%.elf}.uf2 ${{ matrix.controller }}-${{ needs.version.outputs.tag }}.uf2 + - name: Upload UF2 artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.controller }}-firmware + path: | + ${{ matrix.controller }}-${{ needs.version.outputs.tag }}.uf2 + + post-build: + runs-on: ubuntu-latest + needs: [ version, pio-run ] + name: Release + steps: + - uses: actions/download-artifact@v4 + - name: Release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/v') + with: + draft: true + files: | + */*.uf2 From 6abb7902171d27510de42477d874e7555cbc80d3 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 15 Feb 2026 13:23:49 +0100 Subject: [PATCH 097/102] prepared v2 --- src/EventDispatcher/EventDispatcher.cpp | 481 ++++++++++++++++++------ src/EventDispatcher/EventDispatcher.h | 21 ++ src/PPUCProtocolV2.h | 198 ++++++++++ 3 files changed, 579 insertions(+), 121 deletions(-) create mode 100644 src/PPUCProtocolV2.h diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index 9b6434e..4659d0d 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -1,6 +1,18 @@ #include "EventDispatcher.h" -EventDispatcher::EventDispatcher() {} +#include + +EventDispatcher::EventDispatcher() { + for (uint16_t i = 0; i < ppuc::v2::kMaxCoilBits; ++i) { + coilIndexToNumber[i] = i; + } + for (uint16_t i = 0; i < ppuc::v2::kMaxLampBits; ++i) { + lampIndexToNumber[i] = i; + } + for (uint16_t i = 0; i < ppuc::v2::kMaxSwitchBits; ++i) { + switchIndexToNumber[i] = i; + } +} void EventDispatcher::setRS485ModePin(int pin) { rs485 = true; @@ -82,6 +94,10 @@ void EventDispatcher::callListeners(Event *event, bool sendToOtherCore, multiCoreCrossLink->pushEvent(event); } + if (event->sourceId == EVENT_SOURCE_SWITCH) { + updateSwitchBitmap(event); + } + // delete the event and free the memory delete event; } @@ -102,148 +118,371 @@ void EventDispatcher::callListeners(ConfigEvent *event, bool sendToOtherCore) { delete event; } -void EventDispatcher::update() { - if (!rs485) { // We're on Core1, the EffectController. Transmit stacked - // events to Core0. - while (!eventQueue.empty()) { - Event *e = eventQueue.front(); - eventQueue.pop(); - callListeners(e, true, false); +bool EventDispatcher::readBytes(byte *buffer, size_t len) { + size_t offset = 0; + uint32_t start = micros(); + while (offset < len) { + if (hwSerial->available() > 0) { + buffer[offset++] = hwSerial->read(); + continue; } - } else { - if (hwSerial->available() >= 7) { - bool success = false; - - byte startByte = hwSerial->read(); - if (startByte == 255) { - byte sourceId = hwSerial->read(); - if (sourceId != 0) { - if (sourceId == EVENT_CONFIGURATION) { - // Config Event has 12 bytes, 2 bytes are already parsed above. - while (hwSerial->available() < 10) { - } - // We have a ConfigEvent. - byte boardId = hwSerial->read(); - byte topic = hwSerial->read(); - byte index = hwSerial->read(); - byte key = hwSerial->read(); - uint32_t value = (((uint32_t)hwSerial->read()) << 24) + - (((uint32_t)hwSerial->read()) << 16) + - (((uint32_t)hwSerial->read()) << 8) + - hwSerial->read(); - byte stopByte = hwSerial->read(); - if (stopByte == 0b10101010) { - stopByte = hwSerial->read(); - if (stopByte == 0b01010101) { - success = true; - callListeners( - new ConfigEvent(boardId, topic, index, key, value), true); - } - } - } else { - word eventId = word(hwSerial->read(), hwSerial->read()); - if (eventId != 0) { - byte value = hwSerial->read(); - byte stopByte = hwSerial->read(); - if (stopByte == 0b10101010) { - stopByte = hwSerial->read(); - if (stopByte == 0b01010101) { - success = true; - callListeners(new Event((char)sourceId, eventId, value), true, - false); - - if (sourceId == EVENT_POLL_EVENTS && board == value) { - digitalWrite(rs485Pin, HIGH); // Write. - // Wait until the RS485 converter switched to write mode. - delayMicroseconds(RS485_MODE_SWITCH_DELAY); - - while (!eventQueue.empty()) { - Event *e = eventQueue.front(); - eventQueue.pop(); - callListeners(e, true, true); - } - - // Send NULL event to indicate that transmission is - // complete. - callListeners(new Event(EVENT_NULL, 1, board), false, true); - - lastPoll = millis(); - - // Flush the serial buffer and wait until done. - hwSerial->flush(); - digitalWrite(rs485Pin, LOW); // Read. - // Wait until the RS485 converter switched back to read - // mode. - delayMicroseconds(RS485_MODE_SWITCH_DELAY); - } else if (sourceId == EVENT_RUN) { - running = true; - } - - } else { - if (Serial) { - rp2040.idleOtherCore(); - Serial.print("Received wrong second stop byte "); - Serial.println(stopByte, DEC); - rp2040.resumeOtherCore(); - } - } - } else { - if (Serial) { - rp2040.idleOtherCore(); - Serial.print("Received wrong first stop byte "); - Serial.println(stopByte, DEC); - rp2040.resumeOtherCore(); + if ((micros() - start) > 8000) { + return false; + } + } + + return true; +} + +int16_t EventDispatcher::findMappedIndex(const uint16_t* table, uint16_t count, + uint16_t number) { + for (uint16_t i = 0; i < count; ++i) { + if (table[i] == number) { + return (int16_t)i; + } + } + return -1; +} + +void EventDispatcher::updateSwitchBitmap(Event *event) { + int16_t mappedIndex = + findMappedIndex(switchIndexToNumber, runtimeConfig.switchBits, + event->eventId); + if (mappedIndex < 0) { + return; + } + + ppuc::v2::SetBitmapBit(switchStates, (uint16_t)mappedIndex, + event->value != 0); +} + +void EventDispatcher::applyOutputStates(const byte *coils, size_t coilBytes, + const byte *lamps, size_t lampBytes) { + for (uint16_t n = 0; n < runtimeConfig.coilBits; ++n) { + bool oldState = ppuc::v2::GetBitmapBit(outputCoils, n); + bool newState = ppuc::v2::GetBitmapBit(coils, n); + if (oldState != newState) { + callListeners( + new Event(EVENT_SOURCE_SOLENOID, coilIndexToNumber[n], + newState ? 1 : 0), + true, false); + } + } + memcpy(outputCoils, coils, coilBytes); + + for (uint16_t n = 0; n < runtimeConfig.lampBits; ++n) { + bool oldState = ppuc::v2::GetBitmapBit(outputLamps, n); + bool newState = ppuc::v2::GetBitmapBit(lamps, n); + if (oldState != newState) { + callListeners( + new Event(EVENT_SOURCE_LIGHT, lampIndexToNumber[n], newState ? 1 : 0), + true, false); + } + } + memcpy(outputLamps, lamps, lampBytes); +} + +void EventDispatcher::sendSwitchStateFrame(byte nextBoard) { + const size_t switchBytes = ppuc::v2::BitsToBytes(runtimeConfig.switchBits); + const size_t frameBytes = + ppuc::v2::kHeaderBytes + switchBytes + ppuc::v2::kCrcBytes; + + byte frame[ppuc::v2::kHeaderBytes + ppuc::v2::kMaxSwitchBytes + + ppuc::v2::kCrcBytes]; + frame[0] = ppuc::v2::kSyncByte; + frame[1] = ppuc::v2::ComposeTypeAndFlags(ppuc::v2::kFrameSwitchState, + ppuc::v2::kFlagKeyframe); + frame[2] = nextBoard; + frame[3] = txSequence++; + memcpy(&frame[4], switchStates, switchBytes); + + uint16_t crc = + ppuc::v2::Crc16Ccitt(frame, ppuc::v2::kHeaderBytes + switchBytes); + frame[4 + switchBytes] = highByte(crc); + frame[5 + switchBytes] = lowByte(crc); + + digitalWrite(rs485Pin, HIGH); // Write. + delayMicroseconds(RS485_MODE_SWITCH_DELAY); + hwSerial->write(frame, frameBytes); + hwSerial->flush(); + digitalWrite(rs485Pin, LOW); // Read. + delayMicroseconds(RS485_MODE_SWITCH_DELAY); + lastPoll = millis(); +} + +bool EventDispatcher::handleV2Frame() { + if (hwSerial->available() < (int)ppuc::v2::kHeaderBytes) { + return false; + } + + if (hwSerial->peek() != ppuc::v2::kSyncByte) { + return false; + } + + if (!readBytes(v2Buffer, ppuc::v2::kHeaderBytes)) { + return false; + } + + ppuc::v2::FrameType frameType = ppuc::v2::ExtractType(v2Buffer[1]); + size_t payloadBytes = 0; + switch (frameType) { + case ppuc::v2::kFrameSetup: + payloadBytes = ppuc::v2::kSetupPayloadBytes; + break; + case ppuc::v2::kFrameMapping: + payloadBytes = ppuc::v2::kMappingPayloadBytes; + break; + case ppuc::v2::kFrameOutputState: + payloadBytes = ppuc::v2::BitsToBytes(runtimeConfig.coilBits) + + ppuc::v2::BitsToBytes(runtimeConfig.lampBits); + break; + case ppuc::v2::kFrameHeartbeat: + case ppuc::v2::kFrameError: + payloadBytes = 0; + break; + default: + return false; + } + + if (!readBytes(&v2Buffer[ppuc::v2::kHeaderBytes], + payloadBytes + ppuc::v2::kCrcBytes)) { + return false; + } + + const size_t crcOffset = ppuc::v2::kHeaderBytes + payloadBytes; + uint16_t receivedCrc = + word(v2Buffer[crcOffset], v2Buffer[crcOffset + 1]); + uint16_t expectedCrc = + ppuc::v2::Crc16Ccitt(v2Buffer, ppuc::v2::kHeaderBytes + payloadBytes); + if (receivedCrc != expectedCrc) { + return true; + } + + if (frameType == ppuc::v2::kFrameSetup) { + ppuc::v2::RuntimeConfig newConfig; + newConfig.coilBits = word(v2Buffer[4], v2Buffer[5]); + newConfig.lampBits = word(v2Buffer[6], v2Buffer[7]); + newConfig.switchBits = word(v2Buffer[8], v2Buffer[9]); + if (ppuc::v2::IsValidRuntimeConfig(newConfig)) { + runtimeConfig = newConfig; + memset(outputCoils, 0, sizeof(outputCoils)); + memset(outputLamps, 0, sizeof(outputLamps)); + memset(switchStates, 0, sizeof(switchStates)); + for (uint16_t i = 0; i < runtimeConfig.coilBits; ++i) { + coilIndexToNumber[i] = i; + } + for (uint16_t i = 0; i < runtimeConfig.lampBits; ++i) { + lampIndexToNumber[i] = i; + } + for (uint16_t i = 0; i < runtimeConfig.switchBits; ++i) { + switchIndexToNumber[i] = i; + } + } + return true; + } + + if (frameType == ppuc::v2::kFrameMapping) { + const uint8_t domain = v2Buffer[4]; + const uint16_t index = word(v2Buffer[6], v2Buffer[7]); + const uint16_t number = word(v2Buffer[8], v2Buffer[9]); + + if (domain == ppuc::v2::kDomainCoil && index < runtimeConfig.coilBits) { + coilIndexToNumber[index] = number; + } else if (domain == ppuc::v2::kDomainLamp && + index < runtimeConfig.lampBits) { + lampIndexToNumber[index] = number; + } else if (domain == ppuc::v2::kDomainSwitch && + index < runtimeConfig.switchBits) { + switchIndexToNumber[index] = number; + } + + return true; + } + + if (frameType == ppuc::v2::kFrameOutputState) { + const size_t coilBytes = ppuc::v2::BitsToBytes(runtimeConfig.coilBits); + const size_t lampBytes = ppuc::v2::BitsToBytes(runtimeConfig.lampBits); + applyOutputStates(&v2Buffer[4], coilBytes, &v2Buffer[4 + coilBytes], + lampBytes); + + if (v2Buffer[2] == board) { + sendSwitchStateFrame((byte)((board + 1) % ppuc::v2::kMaxBoards)); + } + return true; + } + + return true; +} + +bool EventDispatcher::handleLegacyFrame() { + if (hwSerial->available() < 7) { + return false; + } + + bool success = false; + + byte startByte = hwSerial->read(); + if (startByte == 255) { + byte sourceId = hwSerial->read(); + if (sourceId != 0) { + if (sourceId == EVENT_CONFIGURATION) { + // Config Event has 12 bytes, 2 bytes are already parsed above. + while (hwSerial->available() < 10) { + } + + // We have a ConfigEvent. + byte boardId = hwSerial->read(); + byte topic = hwSerial->read(); + byte index = hwSerial->read(); + byte key = hwSerial->read(); + uint32_t value = (((uint32_t)hwSerial->read()) << 24) + + (((uint32_t)hwSerial->read()) << 16) + + (((uint32_t)hwSerial->read()) << 8) + + hwSerial->read(); + byte stopByte = hwSerial->read(); + if (stopByte == 0b10101010) { + stopByte = hwSerial->read(); + if (stopByte == 0b01010101) { + success = true; + callListeners(new ConfigEvent(boardId, topic, index, key, value), + true); + } + } + } else { + word eventId = word(hwSerial->read(), hwSerial->read()); + if (eventId != 0) { + byte value = hwSerial->read(); + byte stopByte = hwSerial->read(); + if (stopByte == 0b10101010) { + stopByte = hwSerial->read(); + if (stopByte == 0b01010101) { + success = true; + callListeners(new Event((char)sourceId, eventId, value), true, + false); + + if (sourceId == EVENT_POLL_EVENTS && board == value) { + digitalWrite(rs485Pin, HIGH); // Write. + // Wait until the RS485 converter switched to write mode. + delayMicroseconds(RS485_MODE_SWITCH_DELAY); + + while (!eventQueue.empty()) { + Event *e = eventQueue.front(); + eventQueue.pop(); + callListeners(e, true, true); } + + // Send NULL event to indicate that transmission is complete. + callListeners(new Event(EVENT_NULL, 1, board), false, true); + + lastPoll = millis(); + + // Flush the serial buffer and wait until done. + hwSerial->flush(); + digitalWrite(rs485Pin, LOW); // Read. + // Wait until the RS485 converter switched back to read mode. + delayMicroseconds(RS485_MODE_SWITCH_DELAY); + } else if (sourceId == EVENT_RUN) { + running = true; } + } else { if (Serial) { rp2040.idleOtherCore(); - Serial.print("Received invalid event id "); - Serial.println(eventId, DEC); + Serial.print("Received wrong second stop byte "); + Serial.println(stopByte, DEC); rp2040.resumeOtherCore(); } } + } else { + if (Serial) { + rp2040.idleOtherCore(); + Serial.print("Received wrong first stop byte "); + Serial.println(stopByte, DEC); + rp2040.resumeOtherCore(); + } } } else { if (Serial) { rp2040.idleOtherCore(); - Serial.print("Received invalid source id "); - Serial.println(sourceId, DEC); + Serial.print("Received invalid event id "); + Serial.println(eventId, DEC); rp2040.resumeOtherCore(); } } - } else { - if (Serial) { - rp2040.idleOtherCore(); - Serial.print("Received wrong start byte "); - Serial.println(startByte, DEC); - rp2040.resumeOtherCore(); + } + } else { + if (Serial) { + rp2040.idleOtherCore(); + Serial.print("Received invalid source id "); + Serial.println(sourceId, DEC); + rp2040.resumeOtherCore(); + } + } + } else { + if (Serial) { + rp2040.idleOtherCore(); + Serial.print("Received wrong start byte "); + Serial.println(startByte, DEC); + rp2040.resumeOtherCore(); + } + // We didn't receive a start byte. Fake "success" to start over with the + // next byte. + success = true; + } + + if (success) { + if (error) { + error = false; + dispatch(new Event(EVENT_NO_ERROR, 1, board)); + } + } else { + error = true; + dispatch(new Event(EVENT_ERROR, 1, board)); + + while (hwSerial->available()) { + byte bits = hwSerial->read(); + if (bits == 0b10101010 && hwSerial->available()) { + bits = hwSerial->read(); + if (bits == 0b01010101) { + // Now we should be back in sync. + break; } - // We didn't receive a start byte. Fake "success" to start over with the - // next byte. - success = true; } + } + } - if (success) { - if (error) { - error = false; - dispatch(new Event(EVENT_NO_ERROR, 1, board)); + return success; +} + +void EventDispatcher::update() { + if (!rs485) { // We're on Core1, the EffectController. Transmit stacked + // events to Core0. + while (!eventQueue.empty()) { + Event *e = eventQueue.front(); + eventQueue.pop(); + callListeners(e, true, false); + } + } else { + while (!eventQueue.empty()) { + Event *e = eventQueue.front(); + eventQueue.pop(); + callListeners(e, true, false); + } + + while (hwSerial->available() > 0) { + int firstByte = hwSerial->peek(); + if (firstByte == ppuc::v2::kSyncByte) { + if (!handleV2Frame()) { + break; } - } else { - error = true; - dispatch(new Event(EVENT_ERROR, 1, board)); - - while (hwSerial->available()) { - byte bits = hwSerial->read(); - if (bits == 0b10101010 && hwSerial->available()) { - bits = hwSerial->read(); - if (bits == 0b01010101) { - // Now we should be back in sync. - break; - } - } + } else if (firstByte == 255) { + if (!handleLegacyFrame()) { + break; } + } else { + // Desync/noise, consume one byte and continue. + hwSerial->read(); } } } diff --git a/src/EventDispatcher/EventDispatcher.h b/src/EventDispatcher/EventDispatcher.h index bcdabb7..33ee12f 100644 --- a/src/EventDispatcher/EventDispatcher.h +++ b/src/EventDispatcher/EventDispatcher.h @@ -15,6 +15,7 @@ #include "Event.h" #include "EventListener.h" #include "MultiCoreCrossLink.h" +#include "../PPUCProtocolV2.h" #ifndef MAX_EVENT_LISTENERS #define MAX_EVENT_LISTENERS 32 @@ -49,6 +50,16 @@ class EventDispatcher { uint32_t getLastPoll(); private: + bool readBytes(byte* buffer, size_t len); + bool handleLegacyFrame(); + bool handleV2Frame(); + void sendSwitchStateFrame(byte nextBoard); + void applyOutputStates(const byte* coils, size_t coilBytes, const byte* lamps, + size_t lampBytes); + void updateSwitchBitmap(Event* event); + int16_t findMappedIndex(const uint16_t* table, uint16_t count, + uint16_t number); + void callListeners(Event* event, bool sendToOtherCore, bool sendToRS485); void callListeners(ConfigEvent* event, bool sendToOtherCore); @@ -60,6 +71,16 @@ class EventDispatcher { int numListeners = -1; byte msg[12]; + byte v2Buffer[ppuc::v2::kHeaderBytes + ppuc::v2::kMaxCoilBytes + + ppuc::v2::kMaxLampBytes + ppuc::v2::kCrcBytes]; + byte outputCoils[ppuc::v2::kMaxCoilBytes] = {0}; + byte outputLamps[ppuc::v2::kMaxLampBytes] = {0}; + byte switchStates[ppuc::v2::kMaxSwitchBytes] = {0}; + uint16_t coilIndexToNumber[ppuc::v2::kMaxCoilBits]; + uint16_t lampIndexToNumber[ppuc::v2::kMaxLampBits]; + uint16_t switchIndexToNumber[ppuc::v2::kMaxSwitchBits]; + byte txSequence = 0; + ppuc::v2::RuntimeConfig runtimeConfig; bool rs485 = false; uint8_t rs485Pin = 0; diff --git a/src/PPUCProtocolV2.h b/src/PPUCProtocolV2.h new file mode 100644 index 0000000..2fc2db8 --- /dev/null +++ b/src/PPUCProtocolV2.h @@ -0,0 +1,198 @@ +#pragma once + +#include +#include + +namespace ppuc { +namespace v2 { + +constexpr uint32_t kBaudRate = 250000; + +constexpr uint8_t kSyncByte = 0xA5; +constexpr uint8_t kNoBoard = 0xFF; +constexpr uint8_t kMaxBoards = 8; + +// Bitmaps are indexed by global device number: bit N => device number N. +// Runtime counts are configured per game and announced with SetupFrame. +constexpr uint16_t kDefaultCoilBits = 24; +constexpr uint16_t kDefaultLampBits = 64; +constexpr uint16_t kDefaultSwitchBits = 64; +constexpr uint16_t kMaxCoilBits = 256; +constexpr uint16_t kMaxLampBits = 256; +constexpr uint16_t kMaxSwitchBits = 256; + +constexpr size_t BitsToBytes(uint16_t bits) { return (bits + 7u) / 8u; } + +constexpr size_t kDefaultCoilBytes = BitsToBytes(kDefaultCoilBits); +constexpr size_t kDefaultLampBytes = BitsToBytes(kDefaultLampBits); +constexpr size_t kDefaultSwitchBytes = BitsToBytes(kDefaultSwitchBits); +constexpr size_t kMaxCoilBytes = BitsToBytes(kMaxCoilBits); +constexpr size_t kMaxLampBytes = BitsToBytes(kMaxLampBits); +constexpr size_t kMaxSwitchBytes = BitsToBytes(kMaxSwitchBits); + +constexpr size_t kHeaderBytes = 4; +constexpr size_t kCrcBytes = 2; + +enum FrameType : uint8_t { + kFrameOutputState = 0x01, + kFrameSwitchState = 0x02, + kFrameHeartbeat = 0x03, + kFrameError = 0x04, + kFrameSetup = 0x05, + kFrameMapping = 0x06, +}; + +enum MappingDomain : uint8_t { + kDomainCoil = 0x01, + kDomainLamp = 0x02, + kDomainSwitch = 0x03, +}; + +enum FrameFlag : uint8_t { + kFlagNone = 0x00, + kFlagKeyframe = 0x10, + kFlagDelta = 0x20, + kFlagError = 0x80, +}; + +struct FrameHeader { + uint8_t sync; + uint8_t typeAndFlags; + uint8_t nextBoard; + uint8_t sequence; +}; + +struct SetupPayload { + uint16_t coilBits; + uint16_t lampBits; + uint16_t switchBits; +}; + +struct MappingPayload { + uint8_t domain; + uint8_t reserved; + uint16_t index; + uint16_t number; +}; + +struct OutputPayload { + // Only first BitsToBytes(coilBits/lampBits) bytes are used at runtime. + uint8_t coils[kMaxCoilBytes]; + uint8_t lamps[kMaxLampBytes]; +}; + +struct SwitchPayload { + // Only first BitsToBytes(switchBits) bytes are used at runtime. + uint8_t switches[kMaxSwitchBytes]; +}; + +struct SetupFrame { + FrameHeader header; + SetupPayload payload; + uint16_t crc; +}; + +struct MappingFrame { + FrameHeader header; + MappingPayload payload; + uint16_t crc; +}; + +struct OutputStateFrame { + FrameHeader header; + OutputPayload payload; + uint16_t crc; +}; + +struct SwitchStateFrame { + FrameHeader header; + SwitchPayload payload; + uint16_t crc; +}; + +constexpr size_t kSetupPayloadBytes = sizeof(SetupPayload); +constexpr size_t kMappingPayloadBytes = sizeof(MappingPayload); +constexpr size_t kOutputPayloadBytes = sizeof(OutputPayload); +constexpr size_t kSwitchPayloadBytes = sizeof(SwitchPayload); +constexpr size_t kSetupFrameBytes = sizeof(SetupFrame); +constexpr size_t kMappingFrameBytes = sizeof(MappingFrame); +constexpr size_t kOutputFrameBytes = sizeof(OutputStateFrame); +constexpr size_t kSwitchFrameBytes = sizeof(SwitchStateFrame); + +struct RuntimeConfig { + uint16_t coilBits = kDefaultCoilBits; + uint16_t lampBits = kDefaultLampBits; + uint16_t switchBits = kDefaultSwitchBits; +}; + +inline bool IsValidRuntimeConfig(const RuntimeConfig& cfg) { + return cfg.coilBits > 0 && cfg.coilBits <= kMaxCoilBits && cfg.lampBits > 0 && + cfg.lampBits <= kMaxLampBits && cfg.switchBits > 0 && + cfg.switchBits <= kMaxSwitchBits; +} + +inline size_t OutputPayloadBytes(const RuntimeConfig& cfg) { + return BitsToBytes(cfg.coilBits) + BitsToBytes(cfg.lampBits); +} + +inline size_t SwitchPayloadBytes(const RuntimeConfig& cfg) { + return BitsToBytes(cfg.switchBits); +} + +inline size_t OutputFrameBytes(const RuntimeConfig& cfg) { + return kHeaderBytes + OutputPayloadBytes(cfg) + kCrcBytes; +} + +inline size_t SwitchFrameBytes(const RuntimeConfig& cfg) { + return kHeaderBytes + SwitchPayloadBytes(cfg) + kCrcBytes; +} + +inline uint16_t Crc16Ccitt(const uint8_t* data, size_t len) { + uint16_t crc = 0xFFFF; + for (size_t i = 0; i < len; ++i) { + crc ^= static_cast(data[i]) << 8; + for (uint8_t bit = 0; bit < 8; ++bit) { + if (crc & 0x8000) { + crc = static_cast((crc << 1) ^ 0x1021); + } else { + crc <<= 1; + } + } + } + return crc; +} + +inline uint8_t ComposeTypeAndFlags(FrameType type, uint8_t flags) { + return static_cast(static_cast(type) | flags); +} + +inline FrameType ExtractType(uint8_t typeAndFlags) { + return static_cast(typeAndFlags & 0x0F); +} + +inline uint8_t ExtractFlags(uint8_t typeAndFlags) { + return static_cast(typeAndFlags & 0xF0); +} + +inline bool IsValidBoard(uint8_t board) { + return board == kNoBoard || board < kMaxBoards; +} + +inline void SetBitmapBit(uint8_t* bitmap, uint16_t number, bool on) { + const uint16_t byteIndex = number / 8u; + const uint8_t bitMask = static_cast(1u << (number % 8u)); + if (on) { + bitmap[byteIndex] |= bitMask; + } else { + bitmap[byteIndex] &= static_cast(~bitMask); + } +} + +inline bool GetBitmapBit(const uint8_t* bitmap, uint16_t number) { + const uint16_t byteIndex = number / 8u; + const uint8_t bitMask = static_cast(1u << (number % 8u)); + return (bitmap[byteIndex] & bitMask) != 0; +} + +} // namespace v2 +} // namespace ppuc From a79b044f773a5acd68808a4720fc04a9f8ef66bd Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 15 Feb 2026 13:46:44 +0100 Subject: [PATCH 098/102] adjusted baudrate --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index a8381cf..ae525ed 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,7 @@ #include "EventDispatcher/CrossLinkDebugger.h" #include "IOBoardController.h" #include "PPUC.h" +#include "PPUCProtocolV2.h" #include "RPi_Pico_TimerInterrupt.h" IOBoardController ioBoardController(CONTROLLER_16_8_1); @@ -50,7 +51,7 @@ void setup() { pinMode(RS485_MODE_PIN, OUTPUT); digitalWrite(RS485_MODE_PIN, LOW); // Read mode delay(5); - Serial1.begin(115200); + Serial1.begin(ppuc::v2::kBaudRate); // Empty RX FIFO after reboot while (Serial1.available()) { Serial1.read(); From 36e197b71b6de0784044090b218e77699fefc705 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 16 Feb 2026 18:21:24 +0100 Subject: [PATCH 099/102] migrated config events to v2 --- src/EventDispatcher/EventDispatcher.cpp | 421 ++++++++++++++++++------ src/EventDispatcher/EventDispatcher.h | 30 ++ src/IOBoardController.cpp | 1 + src/PPUCProtocolV2.h | 19 ++ 4 files changed, 370 insertions(+), 101 deletions(-) diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index 4659d0d..f803ef6 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -1,7 +1,12 @@ #include "EventDispatcher.h" +#include "hardware/uart.h" #include +namespace { +constexpr uint32_t kV2RxTimeoutUs = 8000; +} + EventDispatcher::EventDispatcher() { for (uint16_t i = 0; i < ppuc::v2::kMaxCoilBits; ++i) { coilIndexToNumber[i] = i; @@ -34,6 +39,8 @@ void EventDispatcher::setCrossLinkSerial(HardwareSerial &reference) { hwSerial = (HardwareSerial *)&reference; } +void EventDispatcher::setDebug(bool enabled) { debugEnabled = enabled; } + void EventDispatcher::addListener(EventListener *eventListener) { addListener(eventListener, EVENT_SOURCE_ANY); } @@ -135,6 +142,245 @@ bool EventDispatcher::readBytes(byte *buffer, size_t len) { return true; } +size_t EventDispatcher::getV2PayloadBytes(ppuc::v2::FrameType frameType) { + switch (frameType) { + case ppuc::v2::kFrameSetup: + return ppuc::v2::kSetupPayloadBytes; + case ppuc::v2::kFrameMapping: + return ppuc::v2::kMappingPayloadBytes; + case ppuc::v2::kFrameConfig: + return ppuc::v2::kConfigPayloadBytes; + case ppuc::v2::kFrameOutputState: + return ppuc::v2::BitsToBytes(runtimeConfig.coilBits) + + ppuc::v2::BitsToBytes(runtimeConfig.lampBits); + case ppuc::v2::kFrameHeartbeat: + case ppuc::v2::kFrameError: + case ppuc::v2::kFrameReset: + return 0; + default: + return 0; + } +} + +bool EventDispatcher::processV2Frame(const byte* frame, size_t payloadBytes) { + const ppuc::v2::FrameType frameType = ppuc::v2::ExtractType(frame[1]); + const size_t crcOffset = ppuc::v2::kHeaderBytes + payloadBytes; + uint16_t receivedCrc = word(frame[crcOffset], frame[crcOffset + 1]); + uint16_t expectedCrc = + ppuc::v2::Crc16Ccitt(frame, ppuc::v2::kHeaderBytes + payloadBytes); + if (receivedCrc != expectedCrc) { + v2RxCrcFail++; + return false; + } + v2RxFrames++; + + if (frameType == ppuc::v2::kFrameSetup) { + ppuc::v2::RuntimeConfig newConfig; + newConfig.coilBits = word(frame[4], frame[5]); + newConfig.lampBits = word(frame[6], frame[7]); + newConfig.switchBits = word(frame[8], frame[9]); + if (ppuc::v2::IsValidRuntimeConfig(newConfig)) { + runtimeConfig = newConfig; + memset(outputCoils, 0, sizeof(outputCoils)); + memset(outputLamps, 0, sizeof(outputLamps)); + memset(switchStates, 0, sizeof(switchStates)); + for (uint16_t i = 0; i < runtimeConfig.coilBits; ++i) { + coilIndexToNumber[i] = i; + } + for (uint16_t i = 0; i < runtimeConfig.lampBits; ++i) { + lampIndexToNumber[i] = i; + } + for (uint16_t i = 0; i < runtimeConfig.switchBits; ++i) { + switchIndexToNumber[i] = i; + } + if (!v2UartDmaActive) { + if (startV2UartDmaTransport()) { + v2CutoverOk++; + } else { + v2CutoverFail++; + } + } + } + return true; + } + + if (frameType == ppuc::v2::kFrameMapping) { + const uint8_t domain = frame[4]; + const uint16_t index = word(frame[6], frame[7]); + const uint16_t number = word(frame[8], frame[9]); + + if (domain == ppuc::v2::kDomainCoil && index < runtimeConfig.coilBits) { + coilIndexToNumber[index] = number; + } else if (domain == ppuc::v2::kDomainLamp && + index < runtimeConfig.lampBits) { + lampIndexToNumber[index] = number; + } else if (domain == ppuc::v2::kDomainSwitch && + index < runtimeConfig.switchBits) { + switchIndexToNumber[index] = number; + } + return true; + } + + if (frameType == ppuc::v2::kFrameOutputState) { + const size_t coilBytes = ppuc::v2::BitsToBytes(runtimeConfig.coilBits); + const size_t lampBytes = ppuc::v2::BitsToBytes(runtimeConfig.lampBits); + applyOutputStates(&frame[4], coilBytes, &frame[4 + coilBytes], lampBytes); + if (frame[2] == board) { + sendSwitchStateFrame((byte)((board + 1) % ppuc::v2::kMaxBoards)); + } + return true; + } + + if (frameType == ppuc::v2::kFrameReset) { + dispatch(new Event(EVENT_RESET)); + return true; + } + + if (frameType == ppuc::v2::kFrameConfig) { + callListeners( + new ConfigEvent(frame[4], frame[5], frame[6], frame[7], + (((uint32_t)frame[8]) << 24) | + (((uint32_t)frame[9]) << 16) | + (((uint32_t)frame[10]) << 8) | + ((uint32_t)frame[11])), + true); + return true; + } + + return true; +} + +bool EventDispatcher::startV2UartDmaTransport() { + if (v2UartDmaActive) { + return true; + } + + int rxDma = dma_claim_unused_channel(false); + if (rxDma < 0) { + return false; + } + + int txDma = dma_claim_unused_channel(false); + if (txDma < 0) { + dma_channel_unclaim(rxDma); + return false; + } + v2RxDmaChannel = rxDma; + v2TxDmaChannel = txDma; + v2UartDmaActive = true; + v2RxState = V2_RX_IDLE; + v2RxPayloadBytes = 0; + v2RxStateStartUs = micros(); + + return true; +} + +void EventDispatcher::stopV2UartDmaTransport() { + if (!v2UartDmaActive) { + return; + } + + dma_channel_abort(v2RxDmaChannel); + dma_channel_abort(v2TxDmaChannel); + dma_channel_unclaim(v2RxDmaChannel); + dma_channel_unclaim(v2TxDmaChannel); + + v2UartDmaActive = false; + v2RxState = V2_RX_IDLE; + v2RxDmaChannel = -1; + v2TxDmaChannel = -1; +} + +bool EventDispatcher::sendV2FrameUartDma(const byte* frame, size_t frameBytes) { + if (!v2UartDmaActive || !frame || frameBytes == 0) { + return false; + } + + memcpy(v2DmaTxBuffer, frame, frameBytes); + dma_channel_config txConfig = dma_channel_get_default_config(v2TxDmaChannel); + channel_config_set_transfer_data_size(&txConfig, DMA_SIZE_8); + channel_config_set_dreq(&txConfig, uart_get_dreq(uart1, true)); + channel_config_set_read_increment(&txConfig, true); + channel_config_set_write_increment(&txConfig, false); + + digitalWrite(rs485Pin, HIGH); // Write. + delayMicroseconds(RS485_MODE_SWITCH_DELAY); + dma_channel_configure(v2TxDmaChannel, &txConfig, &uart1_hw->dr, + v2DmaTxBuffer, frameBytes, true); + dma_channel_wait_for_finish_blocking(v2TxDmaChannel); + uart_tx_wait_blocking(uart1); + digitalWrite(rs485Pin, LOW); // Read. + delayMicroseconds(RS485_MODE_SWITCH_DELAY); + v2TxFrames++; + return true; +} + +void EventDispatcher::serviceV2UartDmaRx() { + if (!v2UartDmaActive) { + return; + } + + if (v2RxState == V2_RX_IDLE) { + dma_channel_config rxConfig = dma_channel_get_default_config(v2RxDmaChannel); + channel_config_set_transfer_data_size(&rxConfig, DMA_SIZE_8); + channel_config_set_dreq(&rxConfig, uart_get_dreq(uart1, false)); + channel_config_set_read_increment(&rxConfig, false); + channel_config_set_write_increment(&rxConfig, true); + dma_channel_configure(v2RxDmaChannel, &rxConfig, v2DmaRxBuffer, + &uart1_hw->dr, ppuc::v2::kHeaderBytes, true); + v2RxState = V2_RX_HEADER; + v2RxStateStartUs = micros(); + v2RxDmaRestarts++; + return; + } + + if (v2RxState == V2_RX_HEADER && dma_channel_is_busy(v2RxDmaChannel)) { + if ((micros() - v2RxStateStartUs) > kV2RxTimeoutUs) { + dma_channel_abort(v2RxDmaChannel); + v2RxState = V2_RX_IDLE; + v2RxDmaTimeouts++; + } + return; + } + + if (v2RxState == V2_RX_HEADER) { + if (v2DmaRxBuffer[0] != ppuc::v2::kSyncByte) { + v2RxSyncFail++; + v2RxState = V2_RX_IDLE; + return; + } + ppuc::v2::FrameType frameType = ppuc::v2::ExtractType(v2DmaRxBuffer[1]); + v2RxPayloadBytes = getV2PayloadBytes(frameType); + + dma_channel_config rxConfig = dma_channel_get_default_config(v2RxDmaChannel); + channel_config_set_transfer_data_size(&rxConfig, DMA_SIZE_8); + channel_config_set_dreq(&rxConfig, uart_get_dreq(uart1, false)); + channel_config_set_read_increment(&rxConfig, false); + channel_config_set_write_increment(&rxConfig, true); + dma_channel_configure(v2RxDmaChannel, &rxConfig, + &v2DmaRxBuffer[ppuc::v2::kHeaderBytes], + &uart1_hw->dr, + v2RxPayloadBytes + ppuc::v2::kCrcBytes, true); + v2RxState = V2_RX_BODY; + v2RxStateStartUs = micros(); + return; + } + + if (v2RxState == V2_RX_BODY && dma_channel_is_busy(v2RxDmaChannel)) { + if ((micros() - v2RxStateStartUs) > kV2RxTimeoutUs) { + dma_channel_abort(v2RxDmaChannel); + v2RxState = V2_RX_IDLE; + v2RxDmaTimeouts++; + } + return; + } + + if (v2RxState == V2_RX_BODY) { + processV2Frame(v2DmaRxBuffer, v2RxPayloadBytes); + v2RxState = V2_RX_IDLE; + } +} + int16_t EventDispatcher::findMappedIndex(const uint16_t* table, uint16_t count, uint16_t number) { for (uint16_t i = 0; i < count; ++i) { @@ -146,6 +392,10 @@ int16_t EventDispatcher::findMappedIndex(const uint16_t* table, uint16_t count, } void EventDispatcher::updateSwitchBitmap(Event *event) { + // V2 switch reporting is bitmap-based. Legacy switch events still originate + // from the existing switch devices/listeners; this method mirrors those + // events into the dense V2 switch-state RAM bitmap. On token/poll, the board + // sends this bitmap back to the CPU in one V2 switch frame. int16_t mappedIndex = findMappedIndex(switchIndexToNumber, runtimeConfig.switchBits, event->eventId); @@ -159,6 +409,10 @@ void EventDispatcher::updateSwitchBitmap(Event *event) { void EventDispatcher::applyOutputStates(const byte *coils, size_t coilBytes, const byte *lamps, size_t lampBytes) { + // V2 output frames carry full RAM snapshots. To preserve existing + // EventListener behavior, we synthesize legacy events only for changed bits + // (edge detection old snapshot -> new snapshot). This keeps the rest of the + // firmware event-driven without requiring listener rewrites. for (uint16_t n = 0; n < runtimeConfig.coilBits; ++n) { bool oldState = ppuc::v2::GetBitmapBit(outputCoils, n); bool newState = ppuc::v2::GetBitmapBit(coils, n); @@ -184,12 +438,15 @@ void EventDispatcher::applyOutputStates(const byte *coils, size_t coilBytes, } void EventDispatcher::sendSwitchStateFrame(byte nextBoard) { + // Switch updates are transmitted as a compact V2 frame containing the full + // dense switch bitmap. The CPU selects the responding board via token + // (header.nextBoard in output frame). This board answers once and then + // returns RS485 direction to RX mode. const size_t switchBytes = ppuc::v2::BitsToBytes(runtimeConfig.switchBits); const size_t frameBytes = ppuc::v2::kHeaderBytes + switchBytes + ppuc::v2::kCrcBytes; - byte frame[ppuc::v2::kHeaderBytes + ppuc::v2::kMaxSwitchBytes + - ppuc::v2::kCrcBytes]; + byte* frame = v2DmaTxBuffer; frame[0] = ppuc::v2::kSyncByte; frame[1] = ppuc::v2::ComposeTypeAndFlags(ppuc::v2::kFrameSwitchState, ppuc::v2::kFlagKeyframe); @@ -202,12 +459,16 @@ void EventDispatcher::sendSwitchStateFrame(byte nextBoard) { frame[4 + switchBytes] = highByte(crc); frame[5 + switchBytes] = lowByte(crc); - digitalWrite(rs485Pin, HIGH); // Write. - delayMicroseconds(RS485_MODE_SWITCH_DELAY); - hwSerial->write(frame, frameBytes); - hwSerial->flush(); - digitalWrite(rs485Pin, LOW); // Read. - delayMicroseconds(RS485_MODE_SWITCH_DELAY); + if (!v2UartDmaActive || !sendV2FrameUartDma(frame, frameBytes)) { + v2TxFallback++; + digitalWrite(rs485Pin, HIGH); // Write. + delayMicroseconds(RS485_MODE_SWITCH_DELAY); + hwSerial->write(frame, frameBytes); + hwSerial->flush(); + digitalWrite(rs485Pin, LOW); // Read. + delayMicroseconds(RS485_MODE_SWITCH_DELAY); + } + lastPoll = millis(); } @@ -225,24 +486,12 @@ bool EventDispatcher::handleV2Frame() { } ppuc::v2::FrameType frameType = ppuc::v2::ExtractType(v2Buffer[1]); - size_t payloadBytes = 0; - switch (frameType) { - case ppuc::v2::kFrameSetup: - payloadBytes = ppuc::v2::kSetupPayloadBytes; - break; - case ppuc::v2::kFrameMapping: - payloadBytes = ppuc::v2::kMappingPayloadBytes; - break; - case ppuc::v2::kFrameOutputState: - payloadBytes = ppuc::v2::BitsToBytes(runtimeConfig.coilBits) + - ppuc::v2::BitsToBytes(runtimeConfig.lampBits); - break; - case ppuc::v2::kFrameHeartbeat: - case ppuc::v2::kFrameError: - payloadBytes = 0; - break; - default: - return false; + size_t payloadBytes = getV2PayloadBytes(frameType); + if (frameType != ppuc::v2::kFrameHeartbeat && + frameType != ppuc::v2::kFrameError && + frameType != ppuc::v2::kFrameReset && payloadBytes == 0 && + frameType != ppuc::v2::kFrameOutputState) { + return false; } if (!readBytes(&v2Buffer[ppuc::v2::kHeaderBytes], @@ -250,69 +499,7 @@ bool EventDispatcher::handleV2Frame() { return false; } - const size_t crcOffset = ppuc::v2::kHeaderBytes + payloadBytes; - uint16_t receivedCrc = - word(v2Buffer[crcOffset], v2Buffer[crcOffset + 1]); - uint16_t expectedCrc = - ppuc::v2::Crc16Ccitt(v2Buffer, ppuc::v2::kHeaderBytes + payloadBytes); - if (receivedCrc != expectedCrc) { - return true; - } - - if (frameType == ppuc::v2::kFrameSetup) { - ppuc::v2::RuntimeConfig newConfig; - newConfig.coilBits = word(v2Buffer[4], v2Buffer[5]); - newConfig.lampBits = word(v2Buffer[6], v2Buffer[7]); - newConfig.switchBits = word(v2Buffer[8], v2Buffer[9]); - if (ppuc::v2::IsValidRuntimeConfig(newConfig)) { - runtimeConfig = newConfig; - memset(outputCoils, 0, sizeof(outputCoils)); - memset(outputLamps, 0, sizeof(outputLamps)); - memset(switchStates, 0, sizeof(switchStates)); - for (uint16_t i = 0; i < runtimeConfig.coilBits; ++i) { - coilIndexToNumber[i] = i; - } - for (uint16_t i = 0; i < runtimeConfig.lampBits; ++i) { - lampIndexToNumber[i] = i; - } - for (uint16_t i = 0; i < runtimeConfig.switchBits; ++i) { - switchIndexToNumber[i] = i; - } - } - return true; - } - - if (frameType == ppuc::v2::kFrameMapping) { - const uint8_t domain = v2Buffer[4]; - const uint16_t index = word(v2Buffer[6], v2Buffer[7]); - const uint16_t number = word(v2Buffer[8], v2Buffer[9]); - - if (domain == ppuc::v2::kDomainCoil && index < runtimeConfig.coilBits) { - coilIndexToNumber[index] = number; - } else if (domain == ppuc::v2::kDomainLamp && - index < runtimeConfig.lampBits) { - lampIndexToNumber[index] = number; - } else if (domain == ppuc::v2::kDomainSwitch && - index < runtimeConfig.switchBits) { - switchIndexToNumber[index] = number; - } - - return true; - } - - if (frameType == ppuc::v2::kFrameOutputState) { - const size_t coilBytes = ppuc::v2::BitsToBytes(runtimeConfig.coilBits); - const size_t lampBytes = ppuc::v2::BitsToBytes(runtimeConfig.lampBits); - applyOutputStates(&v2Buffer[4], coilBytes, &v2Buffer[4 + coilBytes], - lampBytes); - - if (v2Buffer[2] == board) { - sendSwitchStateFrame((byte)((board + 1) % ppuc::v2::kMaxBoards)); - } - return true; - } - - return true; + return processV2Frame(v2Buffer, payloadBytes); } bool EventDispatcher::handleLegacyFrame() { @@ -470,19 +657,23 @@ void EventDispatcher::update() { callListeners(e, true, false); } - while (hwSerial->available() > 0) { - int firstByte = hwSerial->peek(); - if (firstByte == ppuc::v2::kSyncByte) { - if (!handleV2Frame()) { - break; - } - } else if (firstByte == 255) { - if (!handleLegacyFrame()) { - break; + if (v2UartDmaActive) { + serviceV2UartDmaRx(); + } else { + while (hwSerial->available() > 0) { + int firstByte = hwSerial->peek(); + if (firstByte == ppuc::v2::kSyncByte) { + if (!handleV2Frame()) { + break; + } + } else if (firstByte == 255) { + if (!handleLegacyFrame()) { + break; + } + } else { + // Desync/noise, consume one byte and continue. + hwSerial->read(); } - } else { - // Desync/noise, consume one byte and continue. - hwSerial->read(); } } } @@ -498,6 +689,34 @@ void EventDispatcher::update() { callListeners(configEvent, false); } } + + if (debugEnabled && Serial && (millis() - debugLastPrintMs) >= 1000) { + debugLastPrintMs = millis(); + rp2040.idleOtherCore(); + Serial.print("V2DBG board="); + Serial.print(board); + Serial.print(" active="); + Serial.print(v2UartDmaActive ? 1 : 0); + Serial.print(" cutover_ok="); + Serial.print(v2CutoverOk); + Serial.print(" cutover_fail="); + Serial.print(v2CutoverFail); + Serial.print(" rx="); + Serial.print(v2RxFrames); + Serial.print(" rx_crc_fail="); + Serial.print(v2RxCrcFail); + Serial.print(" rx_sync_fail="); + Serial.print(v2RxSyncFail); + Serial.print(" rx_dma_restart="); + Serial.print(v2RxDmaRestarts); + Serial.print(" rx_dma_timeout="); + Serial.print(v2RxDmaTimeouts); + Serial.print(" tx="); + Serial.print(v2TxFrames); + Serial.print(" tx_fallback="); + Serial.println(v2TxFallback); + rp2040.resumeOtherCore(); + } } uint32_t EventDispatcher::getLastPoll() { diff --git a/src/EventDispatcher/EventDispatcher.h b/src/EventDispatcher/EventDispatcher.h index 33ee12f..46d6522 100644 --- a/src/EventDispatcher/EventDispatcher.h +++ b/src/EventDispatcher/EventDispatcher.h @@ -12,6 +12,7 @@ #include +#include "hardware/dma.h" #include "Event.h" #include "EventListener.h" #include "MultiCoreCrossLink.h" @@ -38,6 +39,7 @@ class EventDispatcher { MultiCoreCrossLink* getMultiCoreCrossLink(); void setCrossLinkSerial(HardwareSerial& reference); + void setDebug(bool enabled); void addListener(EventListener* eventListener, char sourceId); @@ -53,6 +55,12 @@ class EventDispatcher { bool readBytes(byte* buffer, size_t len); bool handleLegacyFrame(); bool handleV2Frame(); + bool startV2UartDmaTransport(); + void stopV2UartDmaTransport(); + void serviceV2UartDmaRx(); + bool sendV2FrameUartDma(const byte* frame, size_t frameBytes); + size_t getV2PayloadBytes(ppuc::v2::FrameType frameType); + bool processV2Frame(const byte* frame, size_t payloadBytes); void sendSwitchStateFrame(byte nextBoard); void applyOutputStates(const byte* coils, size_t coilBytes, const byte* lamps, size_t lampBytes); @@ -73,6 +81,10 @@ class EventDispatcher { byte msg[12]; byte v2Buffer[ppuc::v2::kHeaderBytes + ppuc::v2::kMaxCoilBytes + ppuc::v2::kMaxLampBytes + ppuc::v2::kCrcBytes]; + byte v2DmaRxBuffer[ppuc::v2::kHeaderBytes + ppuc::v2::kMaxCoilBytes + + ppuc::v2::kMaxLampBytes + ppuc::v2::kCrcBytes]; + byte v2DmaTxBuffer[ppuc::v2::kHeaderBytes + ppuc::v2::kMaxSwitchBytes + + ppuc::v2::kCrcBytes]; byte outputCoils[ppuc::v2::kMaxCoilBytes] = {0}; byte outputLamps[ppuc::v2::kMaxLampBytes] = {0}; byte switchStates[ppuc::v2::kMaxSwitchBytes] = {0}; @@ -81,6 +93,24 @@ class EventDispatcher { uint16_t switchIndexToNumber[ppuc::v2::kMaxSwitchBits]; byte txSequence = 0; ppuc::v2::RuntimeConfig runtimeConfig; + bool v2UartDmaActive = false; + enum V2RxState { V2_RX_IDLE = 0, V2_RX_HEADER, V2_RX_BODY }; + V2RxState v2RxState = V2_RX_IDLE; + size_t v2RxPayloadBytes = 0; + uint32_t v2RxStateStartUs = 0; + int v2RxDmaChannel = -1; + int v2TxDmaChannel = -1; + bool debugEnabled = false; + uint32_t debugLastPrintMs = 0; + uint32_t v2CutoverOk = 0; + uint32_t v2CutoverFail = 0; + uint32_t v2RxFrames = 0; + uint32_t v2RxCrcFail = 0; + uint32_t v2RxSyncFail = 0; + uint32_t v2RxDmaRestarts = 0; + uint32_t v2RxDmaTimeouts = 0; + uint32_t v2TxFrames = 0; + uint32_t v2TxFallback = 0; bool rs485 = false; uint8_t rs485Pin = 0; diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index abe4724..7c604a9 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -23,6 +23,7 @@ IOBoardController::IOBoardController(int cT) { } _eventDispatcher->setBoard(boardId); + _eventDispatcher->setDebug(m_debug); _eventDispatcher->setRS485ModePin(RS485_MODE_PIN); _eventDispatcher->setCrossLinkSerial(Serial1); _multiCoreCrossLink = new MultiCoreCrossLink(); diff --git a/src/PPUCProtocolV2.h b/src/PPUCProtocolV2.h index 2fc2db8..d795e31 100644 --- a/src/PPUCProtocolV2.h +++ b/src/PPUCProtocolV2.h @@ -40,6 +40,8 @@ enum FrameType : uint8_t { kFrameError = 0x04, kFrameSetup = 0x05, kFrameMapping = 0x06, + kFrameReset = 0x07, + kFrameConfig = 0x08, }; enum MappingDomain : uint8_t { @@ -75,6 +77,14 @@ struct MappingPayload { uint16_t number; }; +struct ConfigPayload { + uint8_t boardId; + uint8_t topic; + uint8_t index; + uint8_t key; + uint32_t value; +}; + struct OutputPayload { // Only first BitsToBytes(coilBits/lampBits) bytes are used at runtime. uint8_t coils[kMaxCoilBytes]; @@ -98,6 +108,12 @@ struct MappingFrame { uint16_t crc; }; +struct ConfigFrame { + FrameHeader header; + ConfigPayload payload; + uint16_t crc; +}; + struct OutputStateFrame { FrameHeader header; OutputPayload payload; @@ -112,10 +128,13 @@ struct SwitchStateFrame { constexpr size_t kSetupPayloadBytes = sizeof(SetupPayload); constexpr size_t kMappingPayloadBytes = sizeof(MappingPayload); +constexpr size_t kConfigPayloadBytes = sizeof(ConfigPayload); constexpr size_t kOutputPayloadBytes = sizeof(OutputPayload); constexpr size_t kSwitchPayloadBytes = sizeof(SwitchPayload); +constexpr size_t kResetFrameBytes = kHeaderBytes + kCrcBytes; constexpr size_t kSetupFrameBytes = sizeof(SetupFrame); constexpr size_t kMappingFrameBytes = sizeof(MappingFrame); +constexpr size_t kConfigFrameBytes = sizeof(ConfigFrame); constexpr size_t kOutputFrameBytes = sizeof(OutputStateFrame); constexpr size_t kSwitchFrameBytes = sizeof(SwitchStateFrame); From 6898dd9ce38e670001df14589e12f0c37e73f606 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 16 Feb 2026 19:23:25 +0100 Subject: [PATCH 100/102] removed vscode --- .gitignore | 1 + .vscode/c_cpp_properties.json | 463 ---------------------------------- 2 files changed, 1 insertion(+), 463 deletions(-) delete mode 100644 .vscode/c_cpp_properties.json diff --git a/.gitignore b/.gitignore index 5286d05..155326f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea +.vscode .pio .DS_Store *.pio.h diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json deleted file mode 100644 index 106f88c..0000000 --- a/.vscode/c_cpp_properties.json +++ /dev/null @@ -1,463 +0,0 @@ -// -// !!! WARNING !!! AUTO-GENERATED FILE! -// PLEASE DO NOT MODIFY IT AND USE "platformio.ini": -// https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags -// -{ - "configurations": [ - { - "name": "PlatformIO", - "includePath": [ - "/Volumes/data/workspace/PPUC/io-boards/src", - "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/RPI_PICO_TimerInterrupt/src", - "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/Bounce2/src", - "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/WS2812FX/src", - "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/Adafruit NeoPixel", - "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/WavePWM/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040/api/deprecated", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040/api/deprecated-avr-comp", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/include/rp2040", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/include/rp2040/pico_base", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2040/hardware_regs/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2040/hardware_structs/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2040/pico_platform/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_btstack/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_cyw43_arch/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_cyw43_driver/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/cyw43-driver/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/3rd-party/bluedroid/decoder/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/3rd-party/bluedroid/encoder/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/3rd-party/yxml", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/platform/embedded", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Device/RP2040/Include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/tinyusb/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/boards/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/hardware_claim/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_base_headers/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_binary_info/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_sync/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_time/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_util/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_stdlib_headers/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_usb_reset_interface_headers/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/boot_bootrom_headers/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/cmsis/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Core/Include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_adc/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_base/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_boot_lock/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_clocks/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_divider/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_dma/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_exception/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_flash/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_gpio/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_i2c/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_interp/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_irq/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_rtc/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_pio/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_pll/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_pwm/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_resets/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_spi/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_sync/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_sync_spin_lock/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_timer/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_uart/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_vreg/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_watchdog/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_xosc/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_aon_timer/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_async_context/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_bootrom/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_double/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_flash/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_float/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_int64_ops/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_lwip/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_multicore/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_common/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_compiler/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_sections/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_panic/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_printf/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_runtime/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_runtime_init/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_rand/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_stdio/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_stdio_uart/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_unique_id/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/lwip/src/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040/freertos", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/variants/rpipico", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/ADCInput/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/ArduinoOTA/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/AsyncUDP/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/AudioBufferManager/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BTstackLib/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BluetoothAudio/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BluetoothHCI/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BluetoothHIDMaster/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/DNSServer/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/EEPROM/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/ESPHost/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/FatFS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/FatFSUSB/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Bluetooth/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Joystick/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Keyboard/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Mouse/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HTTPClient/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HTTPUpdate/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HTTPUpdateServer/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Hash/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/I2S/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Joystick/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/JoystickBLE/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/JoystickBT/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Keyboard/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/KeyboardBLE/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/KeyboardBT/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/LEAmDNS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/LittleFS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MD5Builder/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MIDIUSB/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Mouse/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MouseAbsolute/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MouseBLE/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MouseBT/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/NetBIOS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/PDM/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/PWMAudio/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/PicoOTA/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SD/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SDFS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SPI/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SPISlave/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SdFat/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SerialBT/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Servo/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SimpleMDNS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SingleFileDrive/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SoftwareSPI/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Ticker/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Updater/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/VFS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/WebServer/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/WiFi/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Wire/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/http-parser/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_CYW43/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_ESPHost/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_Ethernet/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_WINC1500/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_enc28j60/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w5100/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w5500/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w55rp20/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w6100/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w6300/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/rp2040", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/rp2350", - "" - ], - "browse": { - "limitSymbolsToIncludedHeaders": true, - "path": [ - "/Volumes/data/workspace/PPUC/io-boards/src", - "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/RPI_PICO_TimerInterrupt/src", - "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/Bounce2/src", - "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/WS2812FX/src", - "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/Adafruit NeoPixel", - "/Volumes/data/workspace/PPUC/io-boards/.pio/libdeps/IO_16_8_1/WavePWM/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040/api/deprecated", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040/api/deprecated-avr-comp", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/include/rp2040", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/include/rp2040/pico_base", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2040/hardware_regs/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2040/hardware_structs/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2040/pico_platform/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_btstack/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_cyw43_arch/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_cyw43_driver/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/cyw43-driver/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/3rd-party/bluedroid/decoder/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/3rd-party/bluedroid/encoder/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/3rd-party/yxml", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/btstack/platform/embedded", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Device/RP2040/Include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/tinyusb/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/boards/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/hardware_claim/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_base_headers/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_binary_info/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_sync/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_time/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_util/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_stdlib_headers/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/common/pico_usb_reset_interface_headers/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/boot_bootrom_headers/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/cmsis/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/cmsis/stub/CMSIS/Core/Include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_adc/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_base/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_boot_lock/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_clocks/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_divider/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_dma/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_exception/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_flash/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_gpio/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_i2c/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_interp/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_irq/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_rtc/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_pio/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_pll/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_pwm/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_resets/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_spi/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_sync/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_sync_spin_lock/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_timer/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_uart/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_vreg/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_watchdog/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/hardware_xosc/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_aon_timer/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_async_context/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_bootrom/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_double/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_flash/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_float/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_int64_ops/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_lwip/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_multicore/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_common/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_compiler/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_sections/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_platform_panic/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_printf/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_runtime/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_runtime_init/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_rand/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_stdio/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_stdio_uart/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/src/rp2_common/pico_unique_id/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/pico-sdk/lib/lwip/src/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/cores/rp2040/freertos", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/include", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/variants/rpipico", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/ADCInput/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/ArduinoOTA/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/AsyncUDP/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/AudioBufferManager/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BTstackLib/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BluetoothAudio/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BluetoothHCI/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/BluetoothHIDMaster/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/DNSServer/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/EEPROM/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/ESPHost/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/FatFS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/FatFSUSB/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Bluetooth/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Joystick/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Keyboard/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HID_Mouse/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HTTPClient/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HTTPUpdate/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/HTTPUpdateServer/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Hash/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/I2S/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Joystick/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/JoystickBLE/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/JoystickBT/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Keyboard/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/KeyboardBLE/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/KeyboardBT/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/LEAmDNS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/LittleFS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MD5Builder/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MIDIUSB/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Mouse/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MouseAbsolute/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MouseBLE/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/MouseBT/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/NetBIOS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/PDM/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/PWMAudio/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/PicoOTA/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SD/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SDFS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SPI/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SPISlave/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SdFat/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SerialBT/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Servo/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SimpleMDNS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SingleFileDrive/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/SoftwareSPI/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Ticker/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Updater/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/VFS/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/WebServer/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/WiFi/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/Wire/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/http-parser/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_CYW43/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_ESPHost/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_Ethernet/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_WINC1500/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_enc28j60/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w5100/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w5500/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w55rp20/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w6100/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/lwIP_w6300/src", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/rp2040", - "/Users/markus.kalkbrenner/.platformio/packages/framework-arduinopico/libraries/rp2350", - "" - ] - }, - "defines": [ - "PLATFORMIO=60118", - "ARDUINO_RASPBERRY_PI_PICO", - "ARDUINO_ARCH_RP2040", - "USBD_MAX_POWER_MA=500", - "PICO_STDIO_USB", - "CFG_TUSB_MCU=OPT_MCU_RP2040", - "CFG_TUSB_OS=OPT_OS_PICO", - "CYW43_DEFAULT_PIN_WL_CLOCK=29u", - "CYW43_DEFAULT_PIN_WL_CS=25u", - "CYW43_DEFAULT_PIN_WL_DATA_IN=24u", - "CYW43_DEFAULT_PIN_WL_DATA_OUT=24u", - "CYW43_DEFAULT_PIN_WL_HOST_WAKE=24u", - "CYW43_DEFAULT_PIN_WL_REG_ON=23u", - "CYW43_PIN_WL_DYNAMIC=1", - "CYW43_PIO_CLOCK_DIV_DYNAMIC=1", - "CYW43_WARN=//", - "LIB_BOOT_STAGE2_HEADERS=1", - "LIB_PICO_AON_TIMER=1", - "LIB_PICO_ATOMIC=1", - "LIB_PICO_BIT_OPS=1", - "LIB_PICO_BIT_OPS_PICO=1", - "LIB_PICO_BOOTSEL_VIA_DOUBLE_RESET=1", - "LIB_PICO_CLIB_INTERFACE=1", - "LIB_PICO_CRT0=1", - "LIB_PICO_CXX_OPTIONS=1", - "LIB_PICO_DIVIDER=1", - "LIB_PICO_DIVIDER_COMPILER=1", - "LIB_PICO_DOUBLE=1", - "LIB_PICO_FIX_RP2040_USB_DEVICE_ENUMERATION=1", - "LIB_PICO_FLASH=1", - "LIB_PICO_FLOAT=1", - "LIB_PICO_FLOAT_PICO=1", - "LIB_PICO_INT64_OPS=1", - "LIB_PICO_INT64_OPS_COMPILER=1", - "LIB_PICO_MALLOC=1", - "LIB_PICO_MEM_OPS=1", - "LIB_PICO_MEM_OPS_COMPILER=1", - "LIB_PICO_MULTICORE=1", - "LIB_PICO_NEWLIB_INTERFACE=1", - "LIB_PICO_PLATFORM=1", - "LIB_PICO_PLATFORM_COMMON=1", - "LIB_PICO_PLATFORM_COMPILER=1", - "LIB_PICO_PLATFORM_PANIC=1", - "LIB_PICO_PLATFORM_SECTIONS=1", - "LIB_PICO_PRINTF=1", - "LIB_PICO_PRINTF_PICO=1", - "LIB_PICO_RAND=1", - "LIB_PICO_RUNTIME=1", - "LIB_PICO_RUNTIME_INIT=1", - "LIB_PICO_STANDARD_BINARY_INFO=1", - "LIB_PICO_STANDARD_LINK=1", - "LIB_PICO_STDIO=0", - "LIB_PICO_STDIO_UART=0", - "LIB_PICO_STDLIB=1", - "LIB_PICO_SYNC=1", - "LIB_PICO_SYNC_CRITICAL_SECTION=1", - "LIB_PICO_SYNC_MUTEX=1", - "LIB_PICO_SYNC_SEM=1", - "LIB_PICO_TIME=1", - "LIB_PICO_TIME_ADAPTER=1", - "LIB_PICO_UNIQUE_ID=1", - "LIB_PICO_UTIL=1", - "LIB_TINYUSB_BOARD=1", - "LIB_TINYUSB_DEVICE=1", - "PICO_32BIT=1", - "PICO_BUILD=1", - "PICO_COPY_TO_RAM=0", - "PICO_NO_BINARY_INFO=1", - "PICO_NO_FLASH=0", - "PICO_NO_HARDWARE=0", - "PICO_ON_DEVICE=1", - "PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1", - "PICO_RP2040_USB_DEVICE_UFRAME_FIX=1", - "PICO_USE_BLOCKED_RAM=0", - "PICO_XOSC_STARTUP_DELAY_MULTIPLIER=64", - "PICO_MAX_SHARED_IRQ_HANDLERS=6", - "PICO_CYW43_ARCH_HEADER=stdint.h", - "CYW43_TASK_STACK_SIZE=1024", - "LIB_PICO_DIVIDER_HARDWARE=1", - "LIB_PICO_DOUBLE_PICO=1", - "LIB_PICO_INT64_OPS_PICO=1", - "LIB_PICO_MEM_OPS_PICO=1", - "PICO_DOUBLE_SUPPORT_ROM_V1=1", - "PICO_FLOAT_SUPPORT_ROM_V1=1", - "PICO_PLATFORM=rp2040", - "PICO_RP2040=1", - "PICO_RP2040_B0_SUPPORTED=1", - "PICO_RP2040_B1_SUPPORTED=1", - "PICO_RP2040_B2_SUPPORTED=1", - "ARM_MATH_CM0_FAMILY", - "ARM_MATH_CM0_PLUS", - "TARGET_RP2040", - "ARDUINO=10810", - "ARDUINO_ARCH_RP2040", - "F_CPU=133000000L", - "BOARD_NAME=\"pico\"", - "PICO_FLASH_SIZE_BYTES=2097152", - "FILE_COPY_CONSTRUCTOR_SELECT=FILE_COPY_CONSTRUCTOR_PUBLIC", - "USE_UTF8_LONG_NAMES=1", - "DISABLE_FS_H_WARNING=1", - "CFG_TUSB_MCU=OPT_MCU_RP2040", - "USB_VID=0x2e8a", - "USB_PID=0x000a", - "USBD_VID=0x2e8a", - "USBD_PID=0x000a", - "USB_MANUFACTURER=\"Raspberry Pi\"", - "USB_PRODUCT=\"Pico\"", - "PICO_CYW43_ARCH_THREADSAFE_BACKGROUND=1", - "CYW43_LWIP=1", - "CYW43_PIO_CLOCK_DIV_DYNAMIC=1", - "LWIP_IPV4=1", - "LWIP_IGMP=1", - "LWIP_CHECKSUM_CTRL_PER_NETIF=1", - "LWIP_IPV6=0", - "ARDUINO_VARIANT=\"rpipico\"", - "" - ], - "cStandard": "gnu17", - "cppStandard": "gnu++17", - "compilerPath": "/Users/markus.kalkbrenner/.platformio/packages/toolchain-rp2040-earlephilhower/bin/arm-none-eabi-gcc", - "compilerArgs": [ - "-march=armv6-m", - "-mcpu=cortex-m0plus", - "-mthumb", - "" - ] - } - ], - "version": 4 -} From 88e85145b64133d0c5f6ec713a08b993cb21154d Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 16 Feb 2026 19:40:17 +0100 Subject: [PATCH 101/102] removed v1 support --- src/EventDispatcher/EventDispatcher.cpp | 147 +----------------------- src/EventDispatcher/EventDispatcher.h | 2 - 2 files changed, 3 insertions(+), 146 deletions(-) diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index f803ef6..0d4223e 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -502,146 +502,6 @@ bool EventDispatcher::handleV2Frame() { return processV2Frame(v2Buffer, payloadBytes); } -bool EventDispatcher::handleLegacyFrame() { - if (hwSerial->available() < 7) { - return false; - } - - bool success = false; - - byte startByte = hwSerial->read(); - if (startByte == 255) { - byte sourceId = hwSerial->read(); - if (sourceId != 0) { - if (sourceId == EVENT_CONFIGURATION) { - // Config Event has 12 bytes, 2 bytes are already parsed above. - while (hwSerial->available() < 10) { - } - - // We have a ConfigEvent. - byte boardId = hwSerial->read(); - byte topic = hwSerial->read(); - byte index = hwSerial->read(); - byte key = hwSerial->read(); - uint32_t value = (((uint32_t)hwSerial->read()) << 24) + - (((uint32_t)hwSerial->read()) << 16) + - (((uint32_t)hwSerial->read()) << 8) + - hwSerial->read(); - byte stopByte = hwSerial->read(); - if (stopByte == 0b10101010) { - stopByte = hwSerial->read(); - if (stopByte == 0b01010101) { - success = true; - callListeners(new ConfigEvent(boardId, topic, index, key, value), - true); - } - } - } else { - word eventId = word(hwSerial->read(), hwSerial->read()); - if (eventId != 0) { - byte value = hwSerial->read(); - byte stopByte = hwSerial->read(); - if (stopByte == 0b10101010) { - stopByte = hwSerial->read(); - if (stopByte == 0b01010101) { - success = true; - callListeners(new Event((char)sourceId, eventId, value), true, - false); - - if (sourceId == EVENT_POLL_EVENTS && board == value) { - digitalWrite(rs485Pin, HIGH); // Write. - // Wait until the RS485 converter switched to write mode. - delayMicroseconds(RS485_MODE_SWITCH_DELAY); - - while (!eventQueue.empty()) { - Event *e = eventQueue.front(); - eventQueue.pop(); - callListeners(e, true, true); - } - - // Send NULL event to indicate that transmission is complete. - callListeners(new Event(EVENT_NULL, 1, board), false, true); - - lastPoll = millis(); - - // Flush the serial buffer and wait until done. - hwSerial->flush(); - digitalWrite(rs485Pin, LOW); // Read. - // Wait until the RS485 converter switched back to read mode. - delayMicroseconds(RS485_MODE_SWITCH_DELAY); - } else if (sourceId == EVENT_RUN) { - running = true; - } - - } else { - if (Serial) { - rp2040.idleOtherCore(); - Serial.print("Received wrong second stop byte "); - Serial.println(stopByte, DEC); - rp2040.resumeOtherCore(); - } - } - } else { - if (Serial) { - rp2040.idleOtherCore(); - Serial.print("Received wrong first stop byte "); - Serial.println(stopByte, DEC); - rp2040.resumeOtherCore(); - } - } - } else { - if (Serial) { - rp2040.idleOtherCore(); - Serial.print("Received invalid event id "); - Serial.println(eventId, DEC); - rp2040.resumeOtherCore(); - } - } - } - } else { - if (Serial) { - rp2040.idleOtherCore(); - Serial.print("Received invalid source id "); - Serial.println(sourceId, DEC); - rp2040.resumeOtherCore(); - } - } - } else { - if (Serial) { - rp2040.idleOtherCore(); - Serial.print("Received wrong start byte "); - Serial.println(startByte, DEC); - rp2040.resumeOtherCore(); - } - // We didn't receive a start byte. Fake "success" to start over with the - // next byte. - success = true; - } - - if (success) { - if (error) { - error = false; - dispatch(new Event(EVENT_NO_ERROR, 1, board)); - } - } else { - error = true; - dispatch(new Event(EVENT_ERROR, 1, board)); - - while (hwSerial->available()) { - byte bits = hwSerial->read(); - if (bits == 0b10101010 && hwSerial->available()) { - bits = hwSerial->read(); - if (bits == 0b01010101) { - // Now we should be back in sync. - break; - } - } - } - } - - return success; -} - void EventDispatcher::update() { if (!rs485) { // We're on Core1, the EffectController. Transmit stacked // events to Core0. @@ -660,16 +520,15 @@ void EventDispatcher::update() { if (v2UartDmaActive) { serviceV2UartDmaRx(); } else { + // Fallback parser is still needed for V2 bootstrap and fault handling: + // - bootstrap: receive initial V2 setup frame before DMA cutover + // - fault path: continue operating if UART DMA transport cannot start while (hwSerial->available() > 0) { int firstByte = hwSerial->peek(); if (firstByte == ppuc::v2::kSyncByte) { if (!handleV2Frame()) { break; } - } else if (firstByte == 255) { - if (!handleLegacyFrame()) { - break; - } } else { // Desync/noise, consume one byte and continue. hwSerial->read(); diff --git a/src/EventDispatcher/EventDispatcher.h b/src/EventDispatcher/EventDispatcher.h index 46d6522..1e788bb 100644 --- a/src/EventDispatcher/EventDispatcher.h +++ b/src/EventDispatcher/EventDispatcher.h @@ -53,7 +53,6 @@ class EventDispatcher { private: bool readBytes(byte* buffer, size_t len); - bool handleLegacyFrame(); bool handleV2Frame(); bool startV2UartDmaTransport(); void stopV2UartDmaTransport(); @@ -115,7 +114,6 @@ class EventDispatcher { bool rs485 = false; uint8_t rs485Pin = 0; byte board = 255; - bool error = false; uint32_t lastPoll; bool running = false; From 6b36be6300a58454c66b19f8ed78168e44105934 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 16 Feb 2026 23:19:08 +0100 Subject: [PATCH 102/102] optimized --- src/EventDispatcher/Event.h | 2 + src/EventDispatcher/EventDispatcher.cpp | 76 ++++++++++++++++++++++++- src/EventDispatcher/EventDispatcher.h | 7 +++ src/IOBoardController.cpp | 6 ++ src/PPUCProtocolV2.h | 1 + 5 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/EventDispatcher/Event.h b/src/EventDispatcher/Event.h index 87d1dbb..b024f1d 100644 --- a/src/EventDispatcher/Event.h +++ b/src/EventDispatcher/Event.h @@ -48,6 +48,7 @@ #define CONFIG_TOPIC_SWITCHES 115 // "s" #define CONFIG_TOPIC_TRIGGER 116 // "t" #define CONFIG_TOPIC_SWITCH_MATRIX 120 // "x" +#define CONFIG_TOPIC_SWITCH_CHAIN 121 // "y" #define CONFIG_TOPIC_HOLD_POWER_ACTIVATION_TIME 65 // "A" #define CONFIG_TOPIC_DURATION 65 // "A" @@ -76,6 +77,7 @@ #define CONFIG_TOPIC_LIGHT_UP 85 // "U" #define CONFIG_TOPIC_ACTIVE_LOW 86 // "V" #define CONFIG_TOPIC_POWER 87 // "W" +#define CONFIG_TOPIC_NEXT_BOARD 88 // "X" #define CONFIG_TOPIC_TYPE 89 // "Y" #define CONFIG_TOPIC_EFFECT 89 // "Y" #define CONFIG_TOPIC_MODE 90 // "Z" diff --git a/src/EventDispatcher/EventDispatcher.cpp b/src/EventDispatcher/EventDispatcher.cpp index 0d4223e..50bfe26 100644 --- a/src/EventDispatcher/EventDispatcher.cpp +++ b/src/EventDispatcher/EventDispatcher.cpp @@ -41,6 +41,10 @@ void EventDispatcher::setCrossLinkSerial(HardwareSerial &reference) { void EventDispatcher::setDebug(bool enabled) { debugEnabled = enabled; } +void EventDispatcher::setNextSwitchBoard(byte boardId) { + nextSwitchBoard = boardId; +} + void EventDispatcher::addListener(EventListener *eventListener) { addListener(eventListener, EVENT_SOURCE_ANY); } @@ -153,6 +157,10 @@ size_t EventDispatcher::getV2PayloadBytes(ppuc::v2::FrameType frameType) { case ppuc::v2::kFrameOutputState: return ppuc::v2::BitsToBytes(runtimeConfig.coilBits) + ppuc::v2::BitsToBytes(runtimeConfig.lampBits); + case ppuc::v2::kFrameSwitchState: + return ppuc::v2::BitsToBytes(runtimeConfig.switchBits); + case ppuc::v2::kFrameSwitchNoChange: + return 0; case ppuc::v2::kFrameHeartbeat: case ppuc::v2::kFrameError: case ppuc::v2::kFrameReset: @@ -226,11 +234,26 @@ bool EventDispatcher::processV2Frame(const byte* frame, size_t payloadBytes) { const size_t lampBytes = ppuc::v2::BitsToBytes(runtimeConfig.lampBits); applyOutputStates(&frame[4], coilBytes, &frame[4 + coilBytes], lampBytes); if (frame[2] == board) { - sendSwitchStateFrame((byte)((board + 1) % ppuc::v2::kMaxBoards)); + if (switchDirty) { + sendSwitchStateFrame(nextSwitchBoard); + switchDirty = false; + } else { + sendSwitchNoChangeFrame(nextSwitchBoard); + } } return true; } + if (frameType == ppuc::v2::kFrameSwitchState) { + const size_t switchBytes = ppuc::v2::BitsToBytes(runtimeConfig.switchBits); + applySwitchStates(&frame[4], switchBytes); + return true; + } + + if (frameType == ppuc::v2::kFrameSwitchNoChange) { + return true; + } + if (frameType == ppuc::v2::kFrameReset) { dispatch(new Event(EVENT_RESET)); return true; @@ -405,6 +428,9 @@ void EventDispatcher::updateSwitchBitmap(Event *event) { ppuc::v2::SetBitmapBit(switchStates, (uint16_t)mappedIndex, event->value != 0); + if (!applyingRemoteSwitchState) { + switchDirty = true; + } } void EventDispatcher::applyOutputStates(const byte *coils, size_t coilBytes, @@ -437,6 +463,24 @@ void EventDispatcher::applyOutputStates(const byte *coils, size_t coilBytes, memcpy(outputLamps, lamps, lampBytes); } +void EventDispatcher::applySwitchStates(const byte* switches, + size_t switchBytes) { + // Global switch state is board-to-board on the RS485 bus. CPU/libppuc never + // broadcasts switch states. Every board consumes incoming switch frames and + // emits local switch events for fast-flip/effect listeners. + applyingRemoteSwitchState = true; + for (uint16_t n = 0; n < runtimeConfig.switchBits; ++n) { + bool oldState = ppuc::v2::GetBitmapBit(switchStates, n); + bool newState = ppuc::v2::GetBitmapBit(switches, n); + if (oldState != newState) { + dispatch(new Event(EVENT_SOURCE_SWITCH, switchIndexToNumber[n], + newState ? 1 : 0, true)); + } + } + applyingRemoteSwitchState = false; + memcpy(switchStates, switches, switchBytes); +} + void EventDispatcher::sendSwitchStateFrame(byte nextBoard) { // Switch updates are transmitted as a compact V2 frame containing the full // dense switch bitmap. The CPU selects the responding board via token @@ -472,6 +516,31 @@ void EventDispatcher::sendSwitchStateFrame(byte nextBoard) { lastPoll = millis(); } +void EventDispatcher::sendSwitchNoChangeFrame(byte nextBoard) { + byte* frame = v2DmaTxBuffer; + frame[0] = ppuc::v2::kSyncByte; + frame[1] = ppuc::v2::ComposeTypeAndFlags(ppuc::v2::kFrameSwitchNoChange, + ppuc::v2::kFlagNone); + frame[2] = nextBoard; + frame[3] = txSequence++; + uint16_t crc = ppuc::v2::Crc16Ccitt(frame, ppuc::v2::kHeaderBytes); + frame[4] = highByte(crc); + frame[5] = lowByte(crc); + + if (!v2UartDmaActive || !sendV2FrameUartDma(frame, ppuc::v2::kResetFrameBytes)) { + v2TxFallback++; + digitalWrite(rs485Pin, HIGH); // Write. + delayMicroseconds(RS485_MODE_SWITCH_DELAY); + hwSerial->write(frame, ppuc::v2::kResetFrameBytes); + hwSerial->flush(); + digitalWrite(rs485Pin, LOW); // Read. + delayMicroseconds(RS485_MODE_SWITCH_DELAY); + } + + v2SwitchNoChangeTx++; + lastPoll = millis(); +} + bool EventDispatcher::handleV2Frame() { if (hwSerial->available() < (int)ppuc::v2::kHeaderBytes) { return false; @@ -490,7 +559,8 @@ bool EventDispatcher::handleV2Frame() { if (frameType != ppuc::v2::kFrameHeartbeat && frameType != ppuc::v2::kFrameError && frameType != ppuc::v2::kFrameReset && payloadBytes == 0 && - frameType != ppuc::v2::kFrameOutputState) { + frameType != ppuc::v2::kFrameOutputState && + frameType != ppuc::v2::kFrameSwitchNoChange) { return false; } @@ -572,6 +642,8 @@ void EventDispatcher::update() { Serial.print(v2RxDmaTimeouts); Serial.print(" tx="); Serial.print(v2TxFrames); + Serial.print(" tx_nochange="); + Serial.print(v2SwitchNoChangeTx); Serial.print(" tx_fallback="); Serial.println(v2TxFallback); rp2040.resumeOtherCore(); diff --git a/src/EventDispatcher/EventDispatcher.h b/src/EventDispatcher/EventDispatcher.h index 1e788bb..c3a0050 100644 --- a/src/EventDispatcher/EventDispatcher.h +++ b/src/EventDispatcher/EventDispatcher.h @@ -40,6 +40,7 @@ class EventDispatcher { void setCrossLinkSerial(HardwareSerial& reference); void setDebug(bool enabled); + void setNextSwitchBoard(byte boardId); void addListener(EventListener* eventListener, char sourceId); @@ -61,8 +62,10 @@ class EventDispatcher { size_t getV2PayloadBytes(ppuc::v2::FrameType frameType); bool processV2Frame(const byte* frame, size_t payloadBytes); void sendSwitchStateFrame(byte nextBoard); + void sendSwitchNoChangeFrame(byte nextBoard); void applyOutputStates(const byte* coils, size_t coilBytes, const byte* lamps, size_t lampBytes); + void applySwitchStates(const byte* switches, size_t switchBytes); void updateSwitchBitmap(Event* event); int16_t findMappedIndex(const uint16_t* table, uint16_t count, uint16_t number); @@ -109,11 +112,15 @@ class EventDispatcher { uint32_t v2RxDmaRestarts = 0; uint32_t v2RxDmaTimeouts = 0; uint32_t v2TxFrames = 0; + uint32_t v2SwitchNoChangeTx = 0; uint32_t v2TxFallback = 0; + bool switchDirty = false; + bool applyingRemoteSwitchState = false; bool rs485 = false; uint8_t rs485Pin = 0; byte board = 255; + byte nextSwitchBoard = ppuc::v2::kNoBoard; uint32_t lastPoll; bool running = false; diff --git a/src/IOBoardController.cpp b/src/IOBoardController.cpp index 7c604a9..7eeb9de 100644 --- a/src/IOBoardController.cpp +++ b/src/IOBoardController.cpp @@ -117,6 +117,12 @@ void IOBoardController::handleEvent(ConfigEvent *event) { } break; + case CONFIG_TOPIC_SWITCH_CHAIN: + if (event->key == CONFIG_TOPIC_NEXT_BOARD) { + _eventDispatcher->setNextSwitchBoard((byte)event->value); + } + break; + case CONFIG_TOPIC_SWITCHES: switch (event->key) { case CONFIG_TOPIC_PORT: diff --git a/src/PPUCProtocolV2.h b/src/PPUCProtocolV2.h index d795e31..ef0e1f3 100644 --- a/src/PPUCProtocolV2.h +++ b/src/PPUCProtocolV2.h @@ -42,6 +42,7 @@ enum FrameType : uint8_t { kFrameMapping = 0x06, kFrameReset = 0x07, kFrameConfig = 0x08, + kFrameSwitchNoChange = 0x09, }; enum MappingDomain : uint8_t {