commit f5610bfea23506ef61cc8ae62a4cd7dc80475ee6 Author: C0d3v Date: Thu Jan 15 10:45:37 2026 +0100 Add working colorFade puzzle diff --git a/terminal/puzzle_colorFade/core/.gitignore b/terminal/puzzle_colorFade/core/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/terminal/puzzle_colorFade/core/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/terminal/puzzle_colorFade/core/platformio.ini b/terminal/puzzle_colorFade/core/platformio.ini new file mode 100644 index 0000000..d5fd72a --- /dev/null +++ b/terminal/puzzle_colorFade/core/platformio.ini @@ -0,0 +1,15 @@ +; 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:nanoatmega328new] +platform = atmelavr +board = nanoatmega328new +framework = arduino +lib_deps = adafruit/Adafruit NeoPixel@^1.15.2 diff --git a/terminal/puzzle_colorFade/core/src/main.cpp b/terminal/puzzle_colorFade/core/src/main.cpp new file mode 100644 index 0000000..b1c5869 --- /dev/null +++ b/terminal/puzzle_colorFade/core/src/main.cpp @@ -0,0 +1,361 @@ + +#include +#include +#include + +#define I2C_SLAVE_ADDRESS 0x08 + +#define MIDDLE_POTI_R A0 +#define MIDDLE_POTI_G A1 +#define MIDDLE_POTI_B A2 + +#define RIGHT_POTI_R A3 +#define RIGHT_POTI_G A6 +#define RIGHT_POTI_B A7 + +#define COMPLETED_PIN 3 +#define POWER_PIN 13 +#define REGENERATE_PIN 2 + +Adafruit_NeoPixel strip(6, 4, NEO_RGB + NEO_KHZ800); + +uint16_t slavePotiValues[6] = {0}; +bool powerOnState = true; + +void readExternalPotiValues() +{ + Wire.requestFrom(I2C_SLAVE_ADDRESS, (uint8_t)12); + + uint8_t *p = (uint8_t *)slavePotiValues; + uint8_t i = 0; + + while (Wire.available() && i < 12) + { + p[i++] = Wire.read(); + } +} + +// 49, 8, 28 +// 45, 39, 32 + +// the setup function runs once when you press reset or power the board + +struct Section +{ + uint16_t min; + uint16_t max; + uint8_t value; +}; + +struct NormalizedRGB +{ + uint8_t r; + uint8_t g; + uint8_t b; + + bool operator==(const NormalizedRGB &other) const + { + return r == other.r && g == other.g && b == other.b; + } +}; + +bool finishedLeft = false; +bool finishedMiddle = false; +bool finishedRight = false; + +struct GameBoard +{ + NormalizedRGB left; + NormalizedRGB middle; + NormalizedRGB right; + + bool operator==(const GameBoard &other) const + { + return left == other.left && middle == other.middle && right == other.right; + } +}; + +const Section pot2[] = { + {0, 511, 0}, + {512, 1023, 128}}; + +const Section pot3[] = { + {0, 340, 0}, + {341, 680, 64}, + {681, 1023, 128}}; + +const Section pot4[] = { + {0, 255, 0}, + {256, 511, 42}, + {512, 768, 84}, + {769, 1023, 128}}; + +const Section pot5[] = { + {0, 200, 0}, + {201, 400, 32}, + {401, 600, 64}, + {601, 800, 96}, + {801, 1023, 128}}; + +// TODO +const Section pot6[] = { + {0, 170, 0}, + {171, 340, 25}, + {341, 510, 50}, + {511, 680, 75}, + {681, 850, 100}, + {851, 1023, 128}}; + +uint8_t quantizizePoti(uint16_t val, const Section *sec, uint8_t count) +{ + for (uint8_t i = 0; i < count; i++) + { + if (val >= sec[i].min && val <= sec[i].max) + return sec[i].value; + } + return 0; +} + +int MAX_SUM = 64; + +NormalizedRGB updateLeft() +{ + + uint16_t inputR = quantizizePoti(slavePotiValues[0], pot3, 3); // analogRead(RIGHT_POTI_R); + uint16_t inputG = quantizizePoti(slavePotiValues[1], pot3, 3); // analogRead(RIGHT_POTI_G); + uint16_t inputB = quantizizePoti(slavePotiValues[2], pot3, 3); + uint32_t sum = inputR + inputG + inputB; + + NormalizedRGB leftRGB; + if (sum > 0) + { + leftRGB.r = (uint32_t)inputR * MAX_SUM / sum; + leftRGB.g = (uint32_t)inputG * MAX_SUM / sum; + leftRGB.b = (uint32_t)inputB * MAX_SUM / sum; + strip.setPixelColor(2, strip.Color(leftRGB.r, leftRGB.g, leftRGB.b, 0)); + } + else + { + strip.setPixelColor(2, strip.Color(0, 0, 0, 0)); + } + return leftRGB; +} + +NormalizedRGB updateMiddle() +{ + uint16_t inputR = quantizizePoti(slavePotiValues[3], pot4, 4); // analogRead(RIGHT_POTI_R); + uint16_t inputG = quantizizePoti(slavePotiValues[4], pot4, 4); // analogRead(RIGHT_POTI_G); + uint16_t inputB = quantizizePoti(slavePotiValues[5], pot4, 4); + uint32_t sum = inputR + inputG + inputB; + + NormalizedRGB middleRGB; + + if (sum > 0) + { + middleRGB.r = (uint32_t)inputR * MAX_SUM / sum; + middleRGB.g = (uint32_t)inputG * MAX_SUM / sum; + middleRGB.b = (uint32_t)inputB * MAX_SUM / sum; + strip.setPixelColor(1, strip.Color(middleRGB.r, middleRGB.g, middleRGB.b, 0)); + } + else + { + strip.setPixelColor(1, strip.Color(0, 0, 0, 0)); + } + return middleRGB; +} + +NormalizedRGB updateRight() +{ + uint16_t inputR = quantizizePoti(analogRead(RIGHT_POTI_R), pot5, 5); // analogRead(RIGHT_POTI_R); + uint16_t inputG = quantizizePoti(analogRead(RIGHT_POTI_G), pot5, 5); // analogRead(RIGHT_POTI_G); + uint16_t inputB = quantizizePoti(analogRead(RIGHT_POTI_B), pot5, 5); + uint32_t sum = inputR + inputG + inputB; + + NormalizedRGB rightRGB; + + if (sum > 0) + { + rightRGB.r = (uint32_t)inputR * MAX_SUM / sum; + rightRGB.g = (uint32_t)inputG * MAX_SUM / sum; + rightRGB.b = (uint32_t)inputB * MAX_SUM / sum; + strip.setPixelColor(0, strip.Color(rightRGB.r, rightRGB.g, rightRGB.b, 0)); + } + else + { + strip.setPixelColor(0, strip.Color(0, 0, 0, 0)); + } + + return rightRGB; +} + +NormalizedRGB generateRandomNormalizedRGB(const Section *section, uint8_t from, uint8_t to) +{ + NormalizedRGB rgb; + uint32_t sum = 0; + do + { + rgb.r = section[random(from, to)].value; + rgb.g = section[random(from, to)].value; + rgb.b = section[random(from, to)].value; + + sum = rgb.r + rgb.g + rgb.b; + + if (sum > 0) + { + rgb.r = (uint32_t)rgb.r * MAX_SUM / sum; + rgb.g = (uint32_t)rgb.g * MAX_SUM / sum; + rgb.b = (uint32_t)rgb.b * MAX_SUM / sum; + } + } while (sum == 0); + return rgb; +} + +GameBoard finishedBoard; +void generateTargetGameBoard() +{ + strip.begin(); + strip.clear(); + GameBoard board; + // left + board.left = generateRandomNormalizedRGB(pot3, 0, 4); + finishedLeft = false; + strip.setPixelColor(3, strip.Color(board.left.r, board.left.g, board.left.b, 0)); // left + // middle + board.middle = generateRandomNormalizedRGB(pot4, 0, 5); + finishedMiddle = false; + strip.setPixelColor(4, strip.Color(board.middle.r, board.middle.g, board.middle.b, 0)); // left + // right + board.right = generateRandomNormalizedRGB(pot5, 1, 6); + finishedRight = false; + strip.setPixelColor(5, strip.Color(board.right.r, board.right.g, board.right.b, 0)); // left + //------------------ + + finishedBoard = board; + strip.show(); +} + +GameBoard currentBoard; +void setup() +{ + // initialize digital pin LED_BUILTIN as an output. + + randomSeed(analogRead(A0)); + + Serial.begin(9600); + Wire.begin(); + + pinMode(RIGHT_POTI_R, INPUT); + pinMode(RIGHT_POTI_G, INPUT); + pinMode(RIGHT_POTI_B, INPUT); + + pinMode(POWER_PIN, INPUT_PULLUP); + powerOnState = digitalRead(POWER_PIN) == HIGH; + pinMode(COMPLETED_PIN, OUTPUT); + pinMode(REGENERATE_PIN, INPUT_PULLUP); + + if (powerOnState) + { + strip.begin(); + generateTargetGameBoard(); + strip.show(); + } +} + +void flicker(uint8_t amount, uint8_t pin1, uint8_t pin2, uint8_t r, uint8_t g, uint8_t b) +{ + for (size_t i = 0; i < amount; i++) + { + strip.begin(); + strip.setPixelColor(pin1, strip.Color(r, g, b)); + strip.setPixelColor(pin2, strip.Color(r, g, b)); + strip.show(); + delay(250); + strip.begin(); + strip.setPixelColor(pin1, strip.Color(0, 0, 0, 0)); + strip.setPixelColor(pin2, strip.Color(0, 0, 0, 0)); + strip.show(); + delay(250); + } +} + +void loop() +{ + if (powerOnState && digitalRead(POWER_PIN) == LOW) + { + powerOnState = false; + strip.begin(); + for (size_t i = 0; i < 6; i++) + { + strip.setPixelColor(i, strip.Color(0, 0, 0, 0)); + } + strip.show(); + } + // Detecting turn-on + if (!powerOnState && digitalRead(POWER_PIN) == HIGH) + { + generateTargetGameBoard(); + powerOnState = true; + } + if (!powerOnState) + { + // We are turned-off and stop anything after here + return; + } + + if (digitalRead(REGENERATE_PIN) == HIGH) + { + generateTargetGameBoard(); + delay(50); // Puls kurz blockieren + } + + strip.begin(); + readExternalPotiValues(); + + if (!finishedLeft) + { + currentBoard.left = updateLeft(); + if (finishedBoard.left == currentBoard.left) + { + flicker(3, 2, 3, finishedBoard.left.r, finishedBoard.left.g, finishedBoard.left.b); + finishedLeft = true; + } + } + + if (!finishedMiddle) + { + currentBoard.middle = updateMiddle(); + if (finishedBoard.middle == currentBoard.middle) + { + flicker(3, 1, 4, finishedBoard.middle.r, finishedBoard.middle.g, finishedBoard.middle.b); + finishedMiddle = true; + } + } + + if (!finishedRight) + { + currentBoard.right = updateRight(); + if (finishedBoard.right == currentBoard.right) + { + flicker(3, 0, 5, finishedBoard.right.r, finishedBoard.right.g, finishedBoard.right.b); + finishedRight = true; + } + } + + if (finishedLeft && finishedMiddle && finishedRight) + { + digitalWrite(3, HIGH); + } + + // if (finishedBoard == currentBoard) + // { + // Serial.println("won"); + // strip.clear(); + // for (uint8_t i = 0; i < 6; i++){ + // strip.setPixelColor(i, strip.Color(255, 255, 255, 0)); + // } + // strip.show(); + // delay(5000); + // } + + strip.show(); +}