#include <stdint.h>
#define AMOUNT_OF_COLORS_TO_SAVE 100
#define AMOUNT_OF_LEDS_AND_BUTTONS 4
#define AMOUNT_OF_TIMES_TO_BLINK_END_GAME 4
#define BLINK_DELAY_IN_MS 500
#define GET_USER_INPUT_DELAY_IN_MS 120000
#define LEDS_TO_BLINK_MAX_AMOUNT 4
#define BIT_BUTTON_PRESSED (1 << 0)
#define BIT_NEW_ROUND (1 << 1)
#define BIT_END_GAME (1 << 2)
#define DEBOUNCE_TIME 300
#define DELAY_BETWEEN_ROUNDS_IN_MS 2000
// === pins ===
//blue, yellow, green, red
constexpr uint8_t leds[] = {2, 16, 18, 22};
constexpr uint8_t bts[] = {4, 17, 19, 23};
// ============
String labels[] = {"Blue", "Yellow", "Green", "Red"};
enum Colors {Blue, Yellow, Green, Red};
QueueHandle_t ledsToBlink;
EventGroupHandle_t evt;
Colors generatedColors[AMOUNT_OF_COLORS_TO_SAVE] = {Blue};
uint8_t currentRound = 0;
uint8_t currentPlay = 0;
bool hasToGenerateNewColor = true;
void generateRandomColor() {
Colors randomColor = (Colors) random(0, 4);
Serial.printf("New color generated: %d\n", randomColor);
generatedColors[currentRound] = randomColor;
}
Colors pinToColor(uint8_t pin) {
switch (pin) {
case bts[0]:
return Blue;
case bts[1]:
return Yellow;
case bts[2]:
return Green;
case bts[3]:
return Red;
}
}
uint8_t colorToPin(Colors color) {
switch (color) {
case Blue:
return leds[0];
case Yellow:
return leds[1];
case Green:
return leds[2];
case Red:
return leds[3];
}
}
void blinkAllLeds() {
Serial.println("Blinking all leds...");
for (uint8_t i = 0; i < AMOUNT_OF_TIMES_TO_BLINK_END_GAME; i++) {
for (uint8_t i = 0; i < AMOUNT_OF_LEDS_AND_BUTTONS; i++) {
digitalWrite(leds[i], HIGH);
}
vTaskDelay(BLINK_DELAY_IN_MS / portTICK_PERIOD_MS);
for (uint8_t i = 0; i < AMOUNT_OF_LEDS_AND_BUTTONS; i++) {
digitalWrite(leds[i], LOW);
}
vTaskDelay(BLINK_DELAY_IN_MS / portTICK_PERIOD_MS);
}
Serial.println("All leds blinked...");
}
void blinkLed(uint8_t ledPin) {
digitalWrite(ledPin, HIGH);
vTaskDelay(BLINK_DELAY_IN_MS / portTICK_PERIOD_MS);
digitalWrite(ledPin, LOW);
}
void blinkLedsOfGeneratedColors() {
for (uint8_t i = 0; i <= currentRound; i++) {
digitalWrite(leds[generatedColors[i]], HIGH);
vTaskDelay(BLINK_DELAY_IN_MS / portTICK_PERIOD_MS);
digitalWrite(leds[generatedColors[i]], LOW);
vTaskDelay(BLINK_DELAY_IN_MS / portTICK_PERIOD_MS);
}
}
void resetGame() {
Serial.println("Reseting game...");
currentRound = 0;
currentPlay = 0;
Serial.println("Game reset!");
}
void handleLeds(void *m) {
while (1) {
EventBits_t uxBits = xEventGroupWaitBits(
evt, /* The event group being tested. */
BIT_BUTTON_PRESSED | BIT_END_GAME | BIT_NEW_ROUND, /* The bits within the event group to wait for. */
pdTRUE, /* Should be cleared before returning. */
pdFALSE, /* Don't wait for both bits, either bit will do. */
GET_USER_INPUT_DELAY_IN_MS / portTICK_PERIOD_MS
);
Serial.println("handle leds");
if ((uxBits & BIT_END_GAME) != 0) {
Serial.println("Blink all leds!");
blinkAllLeds();
}
if ((uxBits & BIT_BUTTON_PRESSED) != 0) {
uint8_t led;
xQueueReceive(
ledsToBlink,
&led,
GET_USER_INPUT_DELAY_IN_MS / portTICK_PERIOD_MS
);
Serial.printf("Received led: %d\n", led);
blinkLed(led);
}
if ((uxBits & BIT_NEW_ROUND) != 0) {
Serial.println("new round!");
vTaskDelay(DELAY_BETWEEN_ROUNDS_IN_MS / portTICK_PERIOD_MS);
blinkLedsOfGeneratedColors();
}
}
}
void readButtons(void *m) {
uint64_t lastTimePressed = millis();
while (1) {
if (hasToGenerateNewColor) {
generateRandomColor();
hasToGenerateNewColor = false;
xEventGroupSetBits(
evt,
BIT_NEW_ROUND
);
}
for (uint8_t i = 0; i < AMOUNT_OF_LEDS_AND_BUTTONS ; i++) {
if (digitalRead(bts[i]) == LOW && ((millis() - lastTimePressed) > DEBOUNCE_TIME)) {
lastTimePressed = millis();
Colors selectedColor = pinToColor(bts[i]);
uint8_t ledPin = colorToPin(selectedColor);
Serial.printf("Color selected: %d\n", selectedColor);
if (selectedColor != generatedColors[currentPlay]) {
Serial.printf("You lost! Correct color: %d\n", generatedColors[currentPlay]);
resetGame();
hasToGenerateNewColor = true;
Serial.println("sending event bit");
xEventGroupSetBits(
evt,
BIT_END_GAME);
Serial.println(" event bit sent");
continue;
} else if (currentPlay == currentRound) {
Serial.printf("Yay! Going to round %d\n", currentRound + 1);
currentPlay = 0;
currentRound++;
hasToGenerateNewColor = true;
xQueueSend(
ledsToBlink,
&ledPin,
GET_USER_INPUT_DELAY_IN_MS / portTICK_PERIOD_MS
);
xEventGroupSetBits(
evt,
BIT_BUTTON_PRESSED);
continue;
}
currentPlay++;
xQueueSend(
ledsToBlink,
&ledPin,
GET_USER_INPUT_DELAY_IN_MS / portTICK_PERIOD_MS
);
xEventGroupSetBits(
evt,
BIT_BUTTON_PRESSED);
}
}
}
}
void setup() {
Serial.begin(115200);
Serial.printf("Simon\n");
for (int i = 0; i < 4 ; i++) {
pinMode(leds[i], OUTPUT);
pinMode(bts[i], INPUT_PULLUP);
}
ledsToBlink = xQueueCreate(LEDS_TO_BLINK_MAX_AMOUNT, sizeof(uint8_t));
evt = xEventGroupCreate();
TaskHandle_t taskReadButtons = NULL;
TaskHandle_t taskHandleLeds = NULL;
xTaskCreate(handleLeds, "Handle Leds", 4094, NULL, 1, &taskHandleLeds);
xTaskCreate(readButtons, "Read Buttons", 4094, NULL, 1, &taskReadButtons);
}
void loop() {
delay(10);
}