#include <EEPROM.h>
#define MODE_EEPROM_ADDR 10
// Define pin assignments
#define LED_PIN PB6
#define BUTTON_PIN PB7
// Init Pins
// const uint8_t buttonPins[] = {12, 11, 10, 9, 7, 6, 5, 4};
const uint8_t buttonPins[] = {4, 5, 6, 7, 9, 10, 11, 12};
const uint8_t ledPins[] = {A0, A1, 2, 3, A4, A5};
const uint8_t additionalLedPin = A2;
const int numButton = sizeof(buttonPins) / sizeof(buttonPins[0]);
const int numLed = sizeof(ledPins) / sizeof(ledPins[0]);
int buttonRead[numButton] = {LOW};
// Additional LED
bool isAnim = false;
bool isManual = false;
bool manualButtonState[numLed] = {0};
// Init Mode Button
int buttonState = 0; // 0 and 1
int modeLastButtonState = LOW;
int modeButtonState;
bool modeButtonPressed = false;
// Init Speed Button
bool delayUpButtonPressed = false;
bool delayDownButtonPressed = false;
// Init Animation Button
const int animDelayTimeRef = 1000;
int animDelayTime = animDelayTimeRef; // initial delay for animation
int buttonState[numButton] = {LOW}; // Array to store the current state of the buttons
int lastButtonStates[numButton] = {LOW}; // Array to store the previous state of the buttons
int buttonCounter = 0;
int animButtonLastPressed;
unsigned long buttonPressTime[numButton] = {0}; // Array to store the time when each button was last pressed
unsigned long lastDebounceTime[numButton] = {0, 0, 0, 0, 0, 0, 0, 0};
unsigned long debounceDelay = 50;
int selectedAnim = -1; // Array to store the current selected anim
unsigned long animPreviousMillis = 0;
uint32_t animBatch = 0;
unsigned long delayMillis = 10000;
bool elapsedButtonFlag = false;
unsigned long startButtonTime = 0;
unsigned long elapsedButtonTime = 0;
int animLedFlag[numLed] = {LOW}; // Array to store which LED is HIGH while anim is running
bool checkBothButtonsPressed(int button1, int button2, bool inverse=false);
void anim1();
void anim2();
void anim3();
void anim4();
void anim5();
void anim6();
void anim7();
void anim8();
void anim9();
void anim10();
void anim11();
// Function pointer type for animation functions
typedef void (*AnimationFunction)();
// Array of animation functions
AnimationFunction animations[] = {anim1, anim2, anim3, anim4, anim5, anim6, anim7, anim8, anim9, anim10, anim11};
void setup() {
// Disable the external crystal oscillator
cli(); // Disable interrupts
// Clear the external crystal oscillator bits in the configuration register
CLKPR = (1 << CLKPCE); // Enable change of clock division
CLKPR = 0; // Set clock division factor to 1 (no division)
sei(); // Enable interrupts
Serial.begin(9600);
for (uint8_t i = 0; i < numButton; i++) {
pinMode(buttonPins[i], INPUT);
}
for (uint8_t i = 0; i < numLed; i++) {
pinMode(ledPins[i], OUTPUT);
}
pinMode(additionalLedPin, OUTPUT);
buttonState = readIntFromEEPROM(MODE_EEPROM_ADDR);
if(buttonState == -1) {buttonState = 0;} // init
Serial.println(buttonState);
}
void loop() {
readButtons();
handleButtons();
handleAnimations();
handleAdditionalLed();
}
void handleAdditionalLed() {
isManual = false;
for (int i = 0; i < numLed; i++) {
if (manualButtonState[i] == true) {
isManual = true;
break;
}
}
if (isAnim == 1 || isManual == 1) {
digitalWrite(additionalLedPin, HIGH);
} else {
digitalWrite(additionalLedPin, LOW);
}
}
void handeButtonPress(int button[]) {
for(uint8_t i = 0; i < 4; i++) {
buttonCurrentState[i] = button[i];
if(buttonLastState[i] == HIGH && buttonCurrentState[i] == LOW) {
buttonPreviousMillis = millis();
animBatch = 0;
buttonState[i] = !buttonState[i];
if(buttonCounter > 1) {
buttonCounter = 0;
}
if(millis() - buttonCurrentMillis < 100) {
buttonCounter += 1;
} else {
buttonCounter = 0;
}
// Turn off other buttons
if(buttonCounter == 0) {
for(uint8_t y = 0; y < 4; y++) {
if(y == i) {continue;}
buttonState[y] = 0;
}
}
Serial.println(mode);
Serial.println("-------------");
Serial.println(buttonState[0]);
Serial.println(buttonState[1]);
Serial.println(buttonState[2]);
Serial.println(buttonState[3]);
Serial.println("-------------");
buttonCurrentMillis = millis();
turnOffAllLeds();
}
buttonLastState[i] = buttonCurrentState[i];
}
}
void handleButtonCombination() {
int buttonArray[] = {buttonState[0], buttonState[1], buttonState[2], buttonState[3],
buttonState[4], buttonState[5], buttonState[6], buttonState[7]};
int a0[] = {0,0,0,0}; // Animation Off
int a1[] = {1,0,0,0};
int a2[] = {0,1,0,0};
int a3[] = {0,0,1,0};
int a4[] = {0,0,0,1};
int a5[] = {1,1,0,0};
int a6[] = {1,0,1,0};
int a7[] = {1,0,0,1};
int a8[] = {0,1,1,0};
int a9[] = {0,1,0,1};
int a10[] = {0,0,1,1};
int combination[] = {a1,a2,a3,a4,a5,a6,a7,a8,a9,a10};
// If Animation is Off
if(compareArray(buttonArray, a0)) {
isAnim = false;
} else {
isAnim = true;
}
for(uint8_t i = 0; i < 11; i++) {
if(compareArray(buttonStateArray, combination[i])) {
startAnim(i);
}
}
}
void anim1() {
// Implement your anim1 function here
// Seperti delay pada umumnya namun tidak memblock program lain
// Tambah animasi dengan menambah else if animBatch +1
int maxAnimBatch;
if(buttonState == 0) {
maxAnimBatch = 5;
if(animBatch == 0) {
animDigitalWrite(0, HIGH);
delayMillis = animDelayTime;
} else if(animBatch == 1) {
animDigitalWrite(0, LOW);
delayMillis = animDelayTime;
} else if(animBatch == 2) {
animDigitalWrite(1, HIGH);
delayMillis = animDelayTime;
} else if(animBatch == 3) {
animDigitalWrite(1, LOW);
delayMillis = animDelayTime;
} else if(animBatch == 4) {
animDigitalWrite(2, HIGH);
delayMillis = animDelayTime;
} else if(animBatch == 5) {
animDigitalWrite(2, LOW);
delayMillis = 0; // Delay terakhir 0
}
} else {
maxAnimBatch = 5;
if(animBatch == 0) {
animDigitalWrite(0, HIGH);
animDigitalWrite(1, HIGH);
delayMillis = animDelayTime;
} else if(animBatch == 1) {
animDigitalWrite(0, LOW);
animDigitalWrite(1, LOW);
delayMillis = animDelayTime;
} else if(animBatch == 2) {
animDigitalWrite(2, HIGH);
animDigitalWrite(3, HIGH);
delayMillis = animDelayTime;
} else if(animBatch == 3) {
animDigitalWrite(2, LOW);
animDigitalWrite(3, LOW);
delayMillis = animDelayTime;
} else if(animBatch == 4) {
animDigitalWrite(4, HIGH);
animDigitalWrite(5, HIGH);
delayMillis = animDelayTime;
} else if(animBatch == 5) {
animDigitalWrite(4, LOW);
animDigitalWrite(5, LOW);
delayMillis = 0; // Delay terakhir 0
}
}
// Millis function logic. Set parameter to max animBatch
animMillisFunction(maxAnimBatch);
}
void anim2() {
// Implement your anim2 function here
anim1();
}
void anim3() {
// Implement your anim1 function here
anim1();
}
void anim4() {
// Implement your anim2 function here
anim1();
}
void anim5() {
// Implement your anim1 function here
anim1();
}
void anim6() {
// Implement your anim2 function here
anim1();
}
void anim7() {
// Implement your anim1 function here
anim1();
}
void anim8() {
// Implement your anim2 function here
anim1();
}
void anim9() {
// Implement your anim1 function here
anim1();
}
void anim10() {
// Implement your anim2 function here
anim1();
}
void anim11() {
// Implement your anim1 function here
anim1();
}
// Define other animation functions (anim3, anim4, ..., anim11) similarly
void modeFunction() {
// if (!checkBothButtonsPressed(1, 6, true)) {
resetAnim();
buttonState = !buttonState;
writeIntIntoEEPROM(MODE_EEPROM_ADDR, buttonState); // Save Mode to EEPROM
Serial.println(buttonState);
modeButtonAnimation();
// } else {Serial.println("DON'T DELETE THIS");}
}
void delayUp() {
animDelayTime = min(animDelayTime * 1.1, animDelayTimeRef * 2);
Serial.println(animDelayTime);
}
void delayDown() {
animDelayTime = max(animDelayTime / 1.1, animDelayTimeRef / 2);
Serial.println(animDelayTime);
}
// ----------------------------------
// Utility Function
void animMillisFunction(int maxBatch) {
if(millis() - animPreviousMillis > delayMillis) {
animPreviousMillis = millis();
// animBatch >= di sesuaikan dengan jumlah maksimal batch animasi
if(animBatch >= maxBatch) {
selectedAnim = -1;
// resetAnim();
} else {
animBatch += 1;
}
}
}
void animDigitalWrite(int ledIndex, int state) {
digitalWrite(ledPins[ledIndex], manualButtonState[ledIndex]? HIGH:state);
animLedFlag[ledIndex] = state;
}
void manualTurnOnLed(int ledIndex, int state) {
digitalWrite(ledPins[ledIndex], state);
manualButtonState[ledIndex] = true;
isManual = true;
}
void manualTurnOffLed(int ledIndex) {
if(animLedFlag[ledIndex] == LOW) {
digitalWrite(ledPins[ledIndex], LOW);
manualButtonState[ledIndex] = false;
}
}
void turnOffAllLeds() {
for(uint8_t i = 0; i < numLed; i++) {
digitalWrite(ledPins[i], LOW);
}
}
void resetAnim() {
animBatch = 0;
turnOffAllLeds();
// if(!isSelectedAnim) {
// selectedAnim = -1;
// }
}
boolean compareArray(int a[], int b[]) {
const int arraySize = sizeof(a) / sizeof(a[0]);
boolean res = true;
for (int i = 0; i < arraySize; i++) {
if( a[i] != b[i] ) {
// Serial.println("not equal");
//set your boolean flag here
res = false;
break;
}
}
return res;
}
void writeIntIntoEEPROM(int address, int number) {
EEPROM.write(address, number >> 8);
EEPROM.write(address + 1, number & 0xFF);
}
int readIntFromEEPROM(int address) {
return (EEPROM.read(address) << 8) + EEPROM.read(address + 1);
}