#include <stdio.h>
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include <MD_MAX72xx.h>
//freertos core setup
#if CONFIG_FREERTOS_UNICORE
static const BaseType_t app_cpu = 0;
#else
static const BaseType_t app_cpu = 1;
#endif
//pause button pin
#define pause_button_pin 2
//bar pin
#define bar1_1_pin 22
#define bar1_2_pin 21
#define bar1_3_pin 4
#define bar2_1_pin 25
#define bar2_2_pin 33
#define bar2_3_pin 32
//controller pin
uint8_t p1_ctrl_pin = 12;
uint8_t p2_ctrl_pin = 13;
uint8_t buzzer_pin = 15;
//led matrix setup
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 8
#define CS_PIN 5
#define CLK_PIN 18
#define DATA_PIN 23
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);
//max matrix
uint8_t max_x = 31;
uint8_t max_y = 15;
//ball position
uint8_t ball_x = 0;
uint8_t ball_y = 0;
//player position
uint8_t p1_x = 0;
uint8_t p1_y = 9;
uint8_t p2_x = max_x;
uint8_t p2_y = 9;
//ball direction
int ball_di;
int ball_from;
//score
uint8_t p1_score;
uint8_t p2_score;
//game settings
uint8_t game_status = 1;
int gameover_delay = 300;
uint8_t update_delay = 10;
//event group
EventGroupHandle_t tasks_status;
uint32_t update_task_bit = 0b001;
uint32_t p1_task_bit = 0b010;
uint32_t p2_task_bit = 0b100;
uint32_t all_task_bits = 0b111;
//FUNCTIONS/////////////////////////////
void start() {
ball_from = random(2);
switch (ball_from) {
case 0:
ball_di = random(0, 2);
ball_x = 2;
ball_y = random(4, 12);
break;
case 1:
ball_di = random(2, 4);
ball_x = max_x-2;
ball_y = random(4, 12);;
break;
}
}
void gameover() {
ledcWrite(0, 50);
vTaskDelay(pdMS_TO_TICKS(gameover_delay));
ledcWrite(0, 0);
start();
}
void bar() {
switch (p1_score) {
case 0:
digitalWrite(bar1_1_pin, LOW); //1
digitalWrite(bar1_2_pin, LOW); //2
digitalWrite(bar1_3_pin, LOW); //3
break;
case 1:
digitalWrite(bar1_1_pin, HIGH); //1
digitalWrite(bar1_2_pin, LOW); //2
digitalWrite(bar1_3_pin, LOW); //3
break;
case 2:
digitalWrite(bar1_1_pin, HIGH); //1
digitalWrite(bar1_2_pin, HIGH); //2
digitalWrite(bar1_3_pin, LOW); //3
break;
case 3:
digitalWrite(bar1_1_pin, HIGH); //1
digitalWrite(bar1_2_pin, HIGH); //2
digitalWrite(bar1_3_pin, HIGH); //3
break;
}
switch (p2_score) {
case 0:
digitalWrite(bar2_1_pin, LOW); //1
digitalWrite(bar2_2_pin, LOW); //2
digitalWrite(bar2_3_pin, LOW); //3
break;
case 1:
digitalWrite(bar2_1_pin, HIGH); //1
digitalWrite(bar2_2_pin, LOW); //2
digitalWrite(bar2_3_pin, LOW); //3
break;
case 2:
digitalWrite(bar2_1_pin, HIGH); //1
digitalWrite(bar2_2_pin, HIGH); //2
digitalWrite(bar2_3_pin, LOW); //3
break;
case 3:
digitalWrite(bar2_1_pin, HIGH); //1
digitalWrite(bar2_2_pin, HIGH); //2
digitalWrite(bar2_3_pin, HIGH); //3
break;
}
}
void update_ball_pos() {
switch (ball_di)
{
case 0: //down RIGHT
ball_x +=1;
ball_y -=1;
break;
case 1: //up RIGHT
ball_x +=1;
ball_y +=1;
break;
case 2: //down LEFT
ball_x -=1;
ball_y -=1;
break;
case 3: //up LEFT
ball_x -=1;
ball_y +=1;
break;
}
}
void collision(){
if (ball_x == 1 && ball_y == max_y) { //hit LEFT & top
ball_from = !ball_from;
if (p1_y == ball_y || p1_y-1 == ball_y || p1_y-2 == ball_y || p1_y-3 == ball_y) {
//bounce down RIGHT
ball_di = 0;
}
else {
//game over
p2_score++;
bar();
gameover();
if (p2_score == 3) {
p1_score = 0;
p2_score = 0;
bar();
}
start();
}
}
else if (ball_x == 1 && ball_y == 0) { //hit LEFT & bottom
ball_from = !ball_from;
if (p1_y == ball_y || p1_y-1 == ball_y || p1_y-2 == ball_y || p1_y-3 == ball_y) {
//bounce up RIGHT
ball_di = 1;
}
else {
//game over
p2_score++;
bar();
gameover();
if (p2_score == 3) {
p1_score = 0;
p2_score = 0;
bar();
}
start();
}
}
else if (ball_x == max_x-1 && ball_y == max_y) { //hit RIGHT & top
ball_from = !ball_from;
if (p2_y == ball_y || p2_y-1 == ball_y || p2_y-2 == ball_y || p2_y-3 == ball_y) {
//bounce down LEFT
ball_di = 2;
}
else {
//game over
p1_score++;
bar();
gameover();
if (p1_score == 3) {
p1_score = 0;
p2_score = 0;
bar();
}
start();
}
}
else if (ball_x == max_x-1 && ball_y == 0) { //hit RIGHT & bottom
ball_from = !ball_from;
if (p2_y == ball_y || p2_y-1 == ball_y || p2_y-2 == ball_y || p2_y-3 == ball_y) { //hit p2
//bounce up LEFT
ball_di = 3;
}
else {
//game over
p1_score++;
bar();
gameover();
if (p1_score == 3) {
p1_score = 0;
p2_score = 0;
bar();
}
start();
}
}
else if (ball_y == max_y) { //hit top
if (ball_from == 0) { //from LEFT
//bounce down RIGHT
ball_di = 0;
}
else { //from RIGHT
//bounce down LEFT
ball_di = 2;
}
}
else if (ball_y == 0) { //hit bottom
if (ball_from == 0) { //from LEFT
//bounce up RIGHT
ball_di = 1;
}
else { //from RIGHT
//bounce up LEFT
ball_di = 3;
}
}
else if (ball_x == 1) { //hit LEFT
ball_from = !ball_from;
if (p1_y == ball_y || p1_y-1 == ball_y || p1_y-2 == ball_y || p1_y-3 == ball_y ) {
//bounce up/down RIGHT
ball_di = random(0,2);
}
else {
//game over
p2_score++;
bar();
gameover();
if (p2_score == 3) {
p1_score = 0;
p2_score = 0;
bar();
}
start();
}
}
else if (ball_x == max_x-1) { //hit RIGHT
ball_from = !ball_from;
if (p2_y == ball_y || p2_y-1 == ball_y || p2_y-2 == ball_y || p2_y-3 == ball_y) {
//bounce up/down LEFT
ball_di = random(2,4);
}
else {
//game over
p1_score++;
bar();
gameover();
if (p1_score == 3) {
p1_score = 0;
p2_score = 0;
bar();
}
start();
}
}
}
void matrix_map(int y, int x) {
if (y > 7) {
y = 8-(y-7);
x = 63-x;
}
mx.setPoint(y, x, true);
}
//TASK////////////////////////////////
void render(void *p) {
while(1) {
if (game_status == 1) { //1
//check for all task bits to set
if (xEventGroupWaitBits(tasks_status, 0b111, pdTRUE, pdTRUE, 2000) == 0b111) {
mx.clear();
//ball
matrix_map(ball_y, ball_x);
//player 1
matrix_map(p1_y, p1_x);
matrix_map(p1_y-1, p1_x);
matrix_map(p1_y-2, p1_x);
matrix_map(p1_y-3, p1_x);
//player 2
matrix_map(p2_y, p2_x);
matrix_map(p2_y-1, p2_x);
matrix_map(p2_y-2, p2_x);
matrix_map(p2_y-3, p2_x);
mx.update();
}
}
vTaskDelay(1);
}
}
void update_ball(void *p) {
while(1) {
if (game_status == 1) { //1
//update pos
collision();
update_ball_pos();
xEventGroupSetBits(tasks_status, update_task_bit); //set task bit
vTaskDelay(pdMS_TO_TICKS(update_delay));
}
vTaskDelay(1);
}
}
//player 1 position task
void p1_pos(void *p) {
while(1) {
if (game_status == 1) { //1
int input_p1 = map (analogRead(p1_ctrl_pin), 0, 4095, 0, 12);
switch (input_p1) {
case 0:
p1_y = max_y-12;
break;
case 1:
p1_y = max_y-11;
break;
case 2:
p1_y = max_y-10;
break;
case 3:
p1_y = max_y-9;
break;
case 4:
p1_y = max_y-8;
break;
case 5:
p1_y = max_y-7;
break;
case 6:
p1_y = max_y-6;
break;
case 7:
p1_y = max_y-5;
break;
case 8:
p1_y = max_y-4;
break;
case 9:
p1_y = max_y-3;
break;
case 10:
p1_y = max_y-2;
break;
case 11:
p1_y = max_y-1;
break;
case 12:
p1_y = max_y;
break;
}
xEventGroupSetBits(tasks_status, p1_task_bit); //set task bit
}
vTaskDelay(1);
}
}
//player 2 position task
void p2_pos(void *p) {
while(1) {
if (game_status == 1) { //1
int input_p2 = map (analogRead(p2_ctrl_pin), 0, 4095, 0, 12);
switch (input_p2) {
case 0:
p2_y = max_y-12;
break;
case 1:
p2_y = max_y-11;
break;
case 2:
p2_y = max_y-10;
break;
case 3:
p2_y = max_y-9;
break;
case 4:
p2_y = max_y-8;
break;
case 5:
p2_y = max_y-7;
break;
case 6:
p2_y = max_y-6;
break;
case 7:
p2_y = max_y-5;
break;
case 8:
p2_y = max_y-4;
break;
case 9:
p2_y = max_y-3;
break;
case 10:
p2_y = max_y-2;
break;
case 11:
p2_y = max_y-1;
break;
case 12:
p2_y = max_y;
break;
}
xEventGroupSetBits(tasks_status, p2_task_bit); //set task bit
}
vTaskDelay(1);
}
}
//player 2 position task
void game_state(void *p) {
int lastState = HIGH;
while(1) {
int value = digitalRead((pause_button_pin));
if (lastState != value) {
lastState = value;
if (value == LOW) {
game_status = !game_status;
}
}
vTaskDelay(1);
}
}
void setup()
{
Serial.begin(115200);
//pinmode setup
//pause button
pinMode(pause_button_pin, INPUT_PULLUP);
//bar 1
pinMode(bar1_1_pin, OUTPUT);
pinMode(bar1_2_pin, OUTPUT);
pinMode(bar1_3_pin, OUTPUT);
//bar 2
pinMode(bar2_1_pin, OUTPUT);
pinMode(bar2_2_pin, OUTPUT);
pinMode(bar2_3_pin, OUTPUT);
//player
pinMode(p1_ctrl_pin, INPUT);
pinMode(p2_ctrl_pin, INPUT);
//buzzer
pinMode(buzzer_pin, OUTPUT);
ledcSetup(0, 200, 8);
ledcAttachPin(buzzer_pin, 0);
//led matrix
mx.begin();
mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY);
//game set
bar();
start();
//event group
tasks_status = xEventGroupCreate();
//tasks
xTaskCreatePinnedToCore(
update_ball,
"update_ball",
2048,
NULL,
1,
NULL,
0);
xTaskCreatePinnedToCore(
render,
"render",
2048,
NULL,
2,
NULL,
0);
xTaskCreatePinnedToCore(
p1_pos,
"p1_pos",
2048,
NULL,
1,
NULL,
1);
xTaskCreatePinnedToCore(
p2_pos,
"p2_pos",
2048,
NULL,
1,
NULL,
1);
xTaskCreatePinnedToCore(
game_state,
"game_state",
2048,
NULL,
1,
NULL,
1);
}
void loop() {}