Compare commits

...

22 Commits

Author SHA1 Message Date
d501292f32 Add double opening 2026-01-20 15:44:33 +01:00
1974376134 Use double buffer 2026-01-20 10:41:27 +01:00
8c0f98b7a7 Add easy mode without shuffling 2026-01-20 10:33:32 +01:00
92a2d39e49 Reduce sampling rate 2026-01-19 21:40:37 +01:00
69f1cba2f8 Add potiNano Code 2026-01-19 21:38:04 +01:00
e2bf85c91e Switch easy timings 2026-01-19 21:02:24 +01:00
d3f10ea70b Optimize master behavior for reset 2026-01-19 20:59:07 +01:00
c2b5331bbd Simplify reset logic 2026-01-19 20:41:52 +01:00
462485dfa6 Remove unused variable 2026-01-19 18:37:31 +01:00
64cde85752 Fix range selection for games 2026-01-19 18:35:49 +01:00
26ee30d1e9 Add direction descriptions 2026-01-19 18:32:23 +01:00
9df16a82c4 Add easy mode based on pulse length 2026-01-19 13:30:10 +01:00
9f964f63d3 Add easy mode based on reset pulse duration 2026-01-19 13:21:42 +01:00
3ac09781e5 Add different puls length for reset type 2026-01-19 13:11:25 +01:00
54ffd02ab4 Show no colors in off mode 2026-01-18 14:15:52 +01:00
b3322b169b Update reading powerState 2026-01-18 13:52:41 +01:00
dd9ced2962 Change color to orange 2026-01-18 13:51:29 +01:00
99014b0f1d Optimize powerOnState 2026-01-18 13:45:29 +01:00
210f70a946 Change color to orange 2026-01-18 13:42:05 +01:00
5c0c1e5672 Reset puzzle 3 on reset 2026-01-16 19:45:00 +01:00
d198904319 Change input type for connectivity lines 2026-01-15 21:39:58 +01:00
1c36cfcde1 Inital commit leftRight puzzle 2026-01-15 21:27:55 +01:00
10 changed files with 344 additions and 51 deletions

View File

@@ -43,9 +43,13 @@ unsigned long lockTimer = 0;
bool unlocked = false;
void openLock(uint8_t indexOn) {
digitalWrite(schubladen[indexOn].schlossPin, HIGH);
delay(400);
digitalWrite(schubladen[indexOn].schlossPin, LOW);
delay(400);
digitalWrite(schubladen[indexOn].schlossPin, HIGH);
unlocked = true;
lockTimer = millis();
digitalWrite(schubladen[indexOn].schlossPin, HIGH);
}
void onI2CReceive(int len) {

View File

@@ -1,7 +1,7 @@
#include <Arduino.h>
#include <Wire.h>
void resetPuzzles();
void resetPuzzles(bool easy);
/* ========================================================= */
const uint8_t ARCHIV_ADDR = 0x10;
@@ -70,21 +70,27 @@ ISR(PCINT1_vect)
}
lastState = state;
}
uint8_t inputPattern = 0;
uint8_t secretPattern = 0b10101010;
void handleEncoderMovement()
{
long diff = encoderPostion - lastClickPosition;
if (abs(diff) >= stepsPerClick)
{
resetPuzzles();
if (diff > 0)
{
// right turn
selectedIndex = (selectedIndex + 1) % 8;
inputPattern = ((inputPattern << 1) | 1) & 0xFF;
}
else
{
//left turn
selectedIndex = (selectedIndex + 7) % 8;
inputPattern = ((inputPattern << 1) | 0) & 0xFF;
}
bool reset = inputPattern == secretPattern;
resetPuzzles(reset);
setDrawerLight(selectedIndex);
lastClickPosition = encoderPostion;
}
@@ -133,13 +139,20 @@ const int puzzleResetPins[3] = {7, 8, 9};
bool puzzlesSolved[3] = {false, false, false};
bool allSolvedSent = false;
void resetPuzzles()
void resetPuzzles(bool easy)
{
for (size_t i = 0; i < 3; i++)
{
puzzlesSolved[i] = false;
digitalWrite(puzzleResetPins[i], HIGH);
delay(30);
puzzlesSolved[i] = false;
}
if (easy)
delay(400);
else
delay(90);
for (size_t i = 0; i < 3; i++)
{
digitalWrite(puzzleResetPins[i], LOW);
}
allSolvedSent = false;

View File

@@ -127,6 +127,7 @@ NormalizedRGB updateLeft()
uint32_t sum = inputR + inputG + inputB;
NormalizedRGB leftRGB;
strip.begin();
if (sum > 0)
{
leftRGB.r = (uint32_t)inputR * MAX_SUM / sum;
@@ -138,6 +139,7 @@ NormalizedRGB updateLeft()
{
strip.setPixelColor(2, strip.Color(0, 0, 0, 0));
}
strip.show();
return leftRGB;
}
@@ -149,7 +151,7 @@ NormalizedRGB updateMiddle()
uint32_t sum = inputR + inputG + inputB;
NormalizedRGB middleRGB;
strip.begin();
if (sum > 0)
{
middleRGB.r = (uint32_t)inputR * MAX_SUM / sum;
@@ -161,6 +163,7 @@ NormalizedRGB updateMiddle()
{
strip.setPixelColor(1, strip.Color(0, 0, 0, 0));
}
strip.show();
return middleRGB;
}
@@ -172,7 +175,7 @@ NormalizedRGB updateRight()
uint32_t sum = inputR + inputG + inputB;
NormalizedRGB rightRGB;
strip.begin();
if (sum > 0)
{
rightRGB.r = (uint32_t)inputR * MAX_SUM / sum;
@@ -184,7 +187,7 @@ NormalizedRGB updateRight()
{
strip.setPixelColor(0, strip.Color(0, 0, 0, 0));
}
strip.show();
return rightRGB;
}
@@ -211,28 +214,36 @@ NormalizedRGB generateRandomNormalizedRGB(const Section *section, uint8_t from,
}
GameBoard finishedBoard;
void generateTargetGameBoard()
void generateTargetGameBoard(bool easy)
{
for (size_t i = 0; i < 6; i++)
{
slavePotiValues[i] = 0;
}
digitalWrite(COMPLETED_PIN, LOW);
GameBoard board;
if (easy)
{
board.left = generateRandomNormalizedRGB(pot3, 2, 3);
board.middle = generateRandomNormalizedRGB(pot4, 3, 4);
board.right = generateRandomNormalizedRGB(pot5, 4, 5);
}
else
{
board.left = generateRandomNormalizedRGB(pot3, 0, 3);
board.middle = generateRandomNormalizedRGB(pot4, 0, 4);
board.right = generateRandomNormalizedRGB(pot5, 1, 5);
}
strip.begin();
strip.clear();
GameBoard board;
// left
board.left = generateRandomNormalizedRGB(pot3, 0, 3);
finishedLeft = false;
strip.setPixelColor(3, strip.Color(board.left.r, board.left.g, board.left.b, 0)); // left
// middle
board.middle = generateRandomNormalizedRGB(pot4, 0, 4);
finishedMiddle = false;
strip.setPixelColor(4, strip.Color(board.middle.r, board.middle.g, board.middle.b, 0)); // middle
// right
board.right = generateRandomNormalizedRGB(pot5, 1, 5);
finishedRight = false;
strip.setPixelColor(5, strip.Color(board.right.r, board.right.g, board.right.b, 0)); // left
//------------------
strip.setPixelColor(5, strip.Color(board.right.r, board.right.g, board.right.b, 0)); // right
finishedBoard = board;
strip.show();
@@ -260,7 +271,7 @@ void setup()
if (powerOnState)
{
strip.begin();
generateTargetGameBoard();
generateTargetGameBoard(false);
strip.show();
}
}
@@ -297,7 +308,7 @@ void loop()
// Detecting turn-on
if (!powerOnState && digitalRead(POWER_PIN) == HIGH)
{
generateTargetGameBoard();
generateTargetGameBoard(false);
powerOnState = true;
}
if (!powerOnState)
@@ -308,11 +319,14 @@ void loop()
if (digitalRead(REGENERATE_PIN) == HIGH)
{
generateTargetGameBoard();
delay(50); // Puls kurz blockieren
unsigned long resetTimer = millis();
while (digitalRead(REGENERATE_PIN) == HIGH)
{
delay(10);
}
generateTargetGameBoard(millis() - resetTimer > 150);
}
strip.begin();
readExternalPotiValues();
if (!finishedLeft)
@@ -347,7 +361,6 @@ void loop()
if (finishedLeft && finishedMiddle && finishedRight)
{
digitalWrite(3, HIGH);
digitalWrite(COMPLETED_PIN, HIGH);
}
strip.show();
}

View File

@@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

View File

@@ -0,0 +1,14 @@
; 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

View File

@@ -0,0 +1,39 @@
#include <Arduino.h>
#include <Wire.h>
#define I2C_SLAVE_ADDRESS 0x08
volatile uint16_t bufferA[6];
volatile uint16_t bufferB[6];
// Pointer to the buffer currently exposed to ISR
volatile uint16_t* activeBuffer = bufferA;
void onI2CRequest() {
// Safe: ISR only reads active buffer
Wire.write((uint8_t*)activeBuffer, 6 * sizeof(uint16_t));
}
void setup() {
Wire.begin(I2C_SLAVE_ADDRESS);
Wire.onRequest(onI2CRequest);
analogReference(DEFAULT);
}
void loop() {
// Choose the inactive buffer
volatile uint16_t* writeBuffer =
(activeBuffer == bufferA) ? bufferB : bufferA;
writeBuffer[0] = analogRead(A0);
writeBuffer[1] = analogRead(A1);
writeBuffer[2] = analogRead(A2);
writeBuffer[3] = analogRead(A3);
writeBuffer[4] = analogRead(A6);
writeBuffer[5] = analogRead(A7);
// Atomic pointer swap
noInterrupts();
activeBuffer = writeBuffer;
interrupts();
}

View File

@@ -97,20 +97,26 @@ bool readButton(uint8_t i) {
// ------------------ Neues Spiel ------------------
void generateNewGame() {
void generateNewGame(bool easy) {
for (uint8_t i = 0; i < 6; i++) solutionOrder[i] = i;
for (uint8_t i = 0; i < 6; i++)
solutionOrder[i] = i;
for (int i = 5; i > 0; i--) {
if (!easy)
{
for (int i = 5; i > 0; i--)
{
int j = random(i + 1);
uint8_t t = solutionOrder[i];
solutionOrder[i] = solutionOrder[j];
solutionOrder[j] = t;
}
}
for (uint8_t i = 0; i < 6; i++)
expectedOrder[i] = solutionOrder[5 - i];
pixelsSolution.begin();
for (uint8_t i = 0; i < 6; i++) {
uint8_t c = solutionOrder[i];
pixelsSolution.setPixelColor(
@@ -124,6 +130,7 @@ void generateNewGame() {
}
pixelsSolution.show();
pixelsButtons.begin();
for (uint8_t i = 0; i < 18; i++) {
buttonAssignment[i] = -1;
pixelsButtons.setPixelColor(i, 0);
@@ -135,12 +142,16 @@ void generateNewGame() {
uint8_t idx[18];
for (uint8_t i = 0; i < 18; i++) idx[i] = i;
for (int i = 17; i > 0; i--) {
if (!easy)
{
for (int i = 17; i > 0; i--)
{
int j = random(i + 1);
uint8_t t = idx[i];
idx[i] = idx[j];
idx[j] = t;
}
}
for (uint8_t i = 0; i < 6; i++)
buttonAssignment[idx[i]] = solutionOrder[i];
@@ -220,7 +231,6 @@ void setup() {
pinMode(PIN_TRIGGER_SHUFFLE, INPUT);
pinMode(PIN_POWER_ON, INPUT);
powerOnState = digitalRead(PIN_POWER_ON);
pinMode(PIN_SEND_WIN, OUTPUT);
digitalWrite(PIN_SEND_WIN, LOW);
@@ -231,16 +241,20 @@ void setup() {
pinMode(7, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
for (uint8_t i = 0; i < 12; i++)
expander.write(i, HIGH);
pixelsButtons.begin();
pixelsSolution.begin();
generateNewGame();
for (uint8_t i = 0; i < 18; i++)
lastPressed[i] = false;
powerOnState = digitalRead(PIN_POWER_ON) == HIGH;
if (powerOnState)
{
generateNewGame(false);
}
}
// ------------------ Loop ------------------
@@ -266,7 +280,7 @@ void loop() {
// Detecting turn-on
if (!powerOnState && digitalRead(PIN_POWER_ON) == HIGH)
{
generateNewGame();
generateNewGame(false);
powerOnState = true;
}
if (!powerOnState)
@@ -274,14 +288,18 @@ void loop() {
// We are turned-off and stop anything after here
return;
}
unsigned long now = millis();
bool trigger = digitalRead(PIN_TRIGGER_SHUFFLE);
if (trigger && !lastTriggerState) {
generateNewGame();
if (digitalRead(PIN_TRIGGER_SHUFFLE) == HIGH)
{
unsigned long resetTimer = millis();
while (digitalRead(PIN_TRIGGER_SHUFFLE) == HIGH)
{
delay(10);
}
generateNewGame(millis() - resetTimer > 150);
}
lastTriggerState = trigger;
unsigned long now = millis();
for (uint8_t i = 0; i < 18; i++) {
bool pressed = readButton(i);

5
terminal/puzzle_leftRight/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

View File

@@ -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

View File

@@ -0,0 +1,167 @@
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
/*
Slave Modul 1
- Taster an A0 und A1 (INPUT_PULLUP)
- 16 Neopixel an D4
- D3 -> Master
LOW = nicht gelöst
HIGH = gelöst (bleibt HIGH)
- D2 -> Master
HIGH = neue Sequenz generieren
*/
#define LED_PIN 4
#define NUM_LEDS 16
#define POWER_PIN 12
bool powerOnState = true;
#define BUTTON1_PIN A0
#define BUTTON2_PIN A1
#define austausch_master_pin 3
#define randomizer_master_pin 2
Adafruit_NeoPixel strip(NUM_LEDS, LED_PIN, NEO_RGB + NEO_KHZ800);
int sequence[NUM_LEDS];
int currentStep = 0;
bool gameWon = false;
int lastButton1State = HIGH;
int lastButton2State = HIGH;
int ledIndex(int logical) {
return (NUM_LEDS - 1) - logical;
}
void generateNewSequence(bool easy) {
for (int i = 0; i < NUM_LEDS; i++) {
if (easy)
{
sequence[i] = 0;
}
else {
sequence[i] = random(0, 2);
}
}
}
void setAll(uint32_t color) {
for (int i = 0; i < NUM_LEDS; i++) {
strip.setPixelColor(i, color);
}
}
void resetGame() {
setAll(strip.Color(0, 0, 0));
strip.show();
currentStep = 0;
gameWon = false;
digitalWrite(austausch_master_pin, LOW);
}
void winAnimation() {
strip.show();
delay(250);
setAll(strip.Color(0, 0, 0));
strip.show();
delay(250);
for (int i = 0; i < NUM_LEDS; i++) {
strip.setPixelColor(
ledIndex(i),
strip.Color(35, 10, 0)
);
strip.show();
delay(20);
}
setAll(strip.Color(35, 10, 0));
strip.show();
}
void checkPress(int buttonID) {
if (buttonID == sequence[currentStep]) {
strip.setPixelColor(
ledIndex(currentStep),
strip.Color(35, 10, 0)
);
strip.show();
currentStep++;
if (currentStep >= NUM_LEDS) {
winAnimation();
gameWon = true;
digitalWrite(austausch_master_pin, HIGH);
}
} else {
resetGame();
}
}
void setup() {
pinMode(BUTTON1_PIN, INPUT_PULLUP);
pinMode(BUTTON2_PIN, INPUT_PULLUP);
pinMode(POWER_PIN, INPUT);
powerOnState = digitalRead(POWER_PIN) == HIGH;
pinMode(austausch_master_pin, OUTPUT);
pinMode(randomizer_master_pin, INPUT);
digitalWrite(austausch_master_pin, LOW);
strip.begin();
strip.show();
randomSeed(millis());
generateNewSequence(false);
resetGame();
}
void loop() {
//Detecting turn-off
if (powerOnState && digitalRead(POWER_PIN) == LOW) {
powerOnState = false;
resetGame();
}
//Detecting turn-on
if (!powerOnState && digitalRead(POWER_PIN) == HIGH) {
powerOnState = true;
}
if (!powerOnState) {
//We are turned-off and stop anything after here
return;
}
// Master-D2 HIGH → neue Sequenz
if (digitalRead(randomizer_master_pin) == HIGH)
{
unsigned long resetTimer = millis();
while (digitalRead(randomizer_master_pin) == HIGH)
{
delay(10);
}
generateNewSequence(millis() - resetTimer > 150);
resetGame();
}
int currentButton1State = digitalRead(BUTTON1_PIN);
int currentButton2State = digitalRead(BUTTON2_PIN);
if (!gameWon) {
if (lastButton1State == HIGH && currentButton1State == LOW) {
checkPress(0);
delay(200);
}
if (lastButton2State == HIGH && currentButton2State == LOW) {
checkPress(1);
delay(200);
}
}
lastButton1State = currentButton1State;
lastButton2State = currentButton2State;
}