Skip to content

Commit

Permalink
added arduino support
Browse files Browse the repository at this point in the history
  • Loading branch information
Leone25 committed Sep 11, 2024
1 parent 824d7ab commit 9626277
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 4 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
backend/leaderboard.json
backend/leaderboard.json
package-lock.json
78 changes: 78 additions & 0 deletions arduino/arduino.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include <ezButton.h>

#define BUTTON0 2
#define BUTTON1 3
#define RESETBUTTON 4
#define LED 13

ezButton button0(BUTTON0);
ezButton button1(BUTTON1);
ezButton resetButton(RESETBUTTON);

void setup() {
Serial.begin(9600);
pinMode(LED, OUTPUT);
button0.setDebounceTime(50);
button1.setDebounceTime(50);
resetButton.setDebounceTime(50);
}

#define LOW 0
#define HIGH 1
#define BLINKING 2

int ledState = LOW;
int blinkTime = 1000;
unsigned long lastTime = 0;

void loop() {
button0.loop();
button1.loop();
resetButton.loop();

if (button0.isPressed()) {
Serial.println("button-0-1");
}

if (button0.isReleased()) {
Serial.println("button-0-0");
}

if (button1.isPressed()) {
Serial.println("button-1-1");
}

if (button1.isReleased()) {
Serial.println("button-1-0");
}

if (resetButton.isPressed()) {
Serial.println("reset-1");
}

if (resetButton.isReleased()) {
Serial.println("reset-0");
}

if (Serial.available()) {
String command = Serial.readStringUntil('\n');
if (command == "led-on") {
ledState = HIGH;
digitalWrite(LED, HIGH);
} else if (command == "led-off") {
ledState = LOW;
digitalWrite(LED, LOW);
} else if (command.startsWith("led-blink")) {
ledState = BLINKING;
blinkTime = command.substring(10).toInt();
lastTime = millis();
}
}

if (ledState == BLINKING) {
if (millis() - lastTime > blinkTime) {
lastTime += blinkTime;
digitalWrite(LED, !digitalRead(LED));
}
}
}
4 changes: 2 additions & 2 deletions backend/Gpio.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ export default class Gpio {
}
}
if (states.every(s => s === 1)) {
this.timer.stop();
timer.stop();
}
} else {
if (states.every(s => s === 0)) {
this.timer.start();
timer.start();
this.lastButton1Press -= 1000;
this.lastButton2Press -= 1000;
}
Expand Down
109 changes: 109 additions & 0 deletions backend/SerialIO.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { SerialPort } from 'serialport';

import config from './config.js';

import { timer } from './index.js';

export default class SerialIO {
constructor() {
this.lastLedState = 'off';
this.lastButton1Press = -1000;
this.lastButton2Press = -1000;
this.states = [0, 0];
this.openTimeout = null;

this.buffer = '';

this.serial = new SerialPort({
path: config.serialPort,
baudRate: 9600,
autoOpen: false,
});

this.serial.on('data', (data) => {
this.buffer += data.toString();
let lines = this.buffer.split('\n');
this.buffer = lines.pop();
for (let line of lines) {
this.handleCommand(line);
}
});

timer.on('start', () => {
this.setLed('on');
});
timer.on('stop', () => {
this.setLed('off');
});
timer.on('reset', () => {
this.setLed('off');
});
timer.on('newHighscore', () => {
this.setLed('blink', 200);
});

if (config.serialPort) this.begin();
}

begin() {
this.serial.open((err) => {
if (err) {
console.error(err);
this.openTimeout = setTimeout(() => {
this.begin();
}, 1000);
}
});
}

handleCommand(command) {
if (command.startsWith('button')) {
let [_, pin, state] = command.split('-');
this.handleButtonUpdate(parseInt(pin), parseInt(state));
} else if (command.startsWith('resetButton')) {
let [_, state] = command.split('-');
this.handleResetButton(parseInt(state));
}
}

handleButtonUpdate(pin, state) {
this.states[pin] = state;
this[`lastButton${pin}Press`] = performance.now();
if (this.timer.isRunning) {
for (let i = 0; i < 2; i++) {
if (this.states[i] === 0 && performance.now() - this[`lastButton${i + 1}Press`] < 500) { // debounce
this.states[i] = 1;
}
}
if (states.every(s => s === 1)) {
timer.stop();
}
} else {
if (states.every(s => s === 0)) {
timer.start();
this.lastButton1Press -= 1000;
this.lastButton2Press -= 1000;
}
}
}

handleResetButton(state) {
if (state === 1) {
timer.reset();
}
}

/**
*
* @param {('on'|'off'|'blink')} state
* @param {number} interval (optional, only used for 'blink' state)
*/
setLed(state, interval = 500) {
if (state === 'blink') {
this.lastLedState = 'blink' + interval;
} else {
this.lastLedState = state;
}
this.serial.write('\nled-' + this.lastLedState + '\n');
}
}
3 changes: 3 additions & 0 deletions backend/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
export default {
"port": 3000,
"leaderboardFile": "./leaderboard.json",
"serialPort": "/dev/ttyACM0", // set to null to disable serial

// pins are only for the Raspberry Pi
"button1Pin": 17,
"button2Pin": 18,
"resetButtonPin": 22,
Expand Down
4 changes: 3 additions & 1 deletion backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const argv = yargs(process.argv.slice(2))
.argv;

import Timer from "./Timer.js";
import SerialIO from "./SerialIO.js";

export const app = express();
const httpServer = createServer(app);
Expand All @@ -29,9 +30,10 @@ export const io = new Server(httpServer, {
});

export const timer = new Timer();
export const serialIO = new SerialIO();

if (["arm", "arm64"].includes(arch)) {
const gpio = new (await import("array-gpio")).default();
const gpio = new (await import("./Gpio.js")).default();
}

if (argv.prod) {
Expand Down
1 change: 1 addition & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
},
"dependencies": {
"express": "^4.19.2",
"serialport": "^12.0.0",
"socket.io": "^4.7.5",
"uuid": "^10.0.0",
"yargs": "^17.7.2"
Expand Down

0 comments on commit 9626277

Please sign in to comment.