diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/BuenzliAI.iml b/.idea/BuenzliAI.iml
new file mode 100644
index 0000000..bc2cd87
--- /dev/null
+++ b/.idea/BuenzliAI.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/editor.xml b/.idea/editor.xml
new file mode 100644
index 0000000..551ce98
--- /dev/null
+++ b/.idea/editor.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..e637d2e
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3e97aa7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# Bomb? Project
+
diff --git a/libraries/Adafruit-PN532-1.3.3.zip b/libraries/Adafruit-PN532-1.3.3.zip
new file mode 100644
index 0000000..fd06bc4
Binary files /dev/null and b/libraries/Adafruit-PN532-1.3.3.zip differ
diff --git a/libraries/DFRobotDFPlayerMini-1.0.5.zip b/libraries/DFRobotDFPlayerMini-1.0.5.zip
new file mode 100644
index 0000000..b14a0af
Binary files /dev/null and b/libraries/DFRobotDFPlayerMini-1.0.5.zip differ
diff --git a/libraries/og_Adafruit-PN532-1.3.3.zip b/libraries/og_Adafruit-PN532-1.3.3.zip
new file mode 100644
index 0000000..bb5c1bc
Binary files /dev/null and b/libraries/og_Adafruit-PN532-1.3.3.zip differ
diff --git a/libraries/pn532_spi.zip b/libraries/pn532_spi.zip
new file mode 100644
index 0000000..b152b44
Binary files /dev/null and b/libraries/pn532_spi.zip differ
diff --git a/libraries/vma211_spi.zip b/libraries/vma211_spi.zip
new file mode 100644
index 0000000..280efe6
Binary files /dev/null and b/libraries/vma211_spi.zip differ
diff --git a/main/context.cpp b/main/context.cpp
new file mode 100644
index 0000000..346df91
--- /dev/null
+++ b/main/context.cpp
@@ -0,0 +1,6 @@
+#include "Context.h"
+
+Context::Context(Station* stations, unsigned long delta) {
+ this->stations = stations;
+ this->delta = delta;
+}
diff --git a/main/context.h b/main/context.h
new file mode 100644
index 0000000..33db2c9
--- /dev/null
+++ b/main/context.h
@@ -0,0 +1,11 @@
+#pragma once
+#include
+#include "station.h"
+
+class Context {
+public:
+ Context(Station* stations, unsigned long delta);
+
+ Station* stations;
+ unsigned long delta;
+};
diff --git a/main/main.ino b/main/main.ino
new file mode 100644
index 0000000..27eb5b4
--- /dev/null
+++ b/main/main.ino
@@ -0,0 +1,208 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "station.h"
+#include "statemachine.h"
+#include "state.h"
+#include "states.h"
+#include "timer.h"
+
+#define PN532_CS 10
+
+// Using this library to set a timeout on readPassiveTagID
+// The library in use is slightly modified to fix this issue: https://github.com/adafruit/Adafruit-PN532/issues/117
+Adafruit_PN532 nfc(PN532_CS);
+
+const int rs = 9, en = 8, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
+LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
+
+SoftwareSerial softSerial(6, 7); // RX, TX
+DFRobotDFPlayerMini myDFPlayer;
+
+Station stations[4] = { Station(1680767519, "Yellow"), Station(3346823711, "Green"), Station(3569318175, "Pink"), Station(2174777887, "Blue") };
+Station* currentStation;
+
+Timer stationDetectionTimer(500, true);
+
+StateMachine stateMachine(new Startup());
+
+unsigned long lastLoopTime = 0;
+unsigned long currentLoopTime = 0;
+unsigned long deltaTime = 0;
+
+void setup(void) {
+ setupNFC();
+
+ lcd.begin(16, 2);
+ stationDetectionTimer.start();
+
+ softSerial.begin(9600);
+
+ lcd.print("Initializing MP3");
+ lcd.clear();
+ if (!myDFPlayer.begin(softSerial, true, true)) {
+ lcd.print("Failed to init");
+ lcd.setCursor(0, 1);
+ lcd.print("DFPlayer!");
+ while (true) {
+ delay(100);
+ printMp3Detail(myDFPlayer.readType(), myDFPlayer.read());
+ }
+ }
+
+ myDFPlayer.volume(5);
+ myDFPlayer.play(1);
+}
+
+void loop(void) {
+ currentLoopTime = millis();
+ deltaTime = currentLoopTime - lastLoopTime;
+
+ bool doCheck = stationDetectionTimer.update(deltaTime);
+ lcd.setCursor(0, 1);
+ lcd.print(" ");
+ if (doCheck) {
+ checkStations();
+ lcd.setCursor(7, 1);
+ lcd.print("check");
+ }
+ lcd.setCursor(0, 1);
+ lcd.print(String(deltaTime));
+
+ stateMachine.update(Context(stations, deltaTime));
+
+ lastLoopTime = currentLoopTime;
+ delay(10);
+}
+
+void setupNFC() {
+ nfc.begin();
+
+ uint32_t versiondata = nfc.getFirmwareVersion();
+ if (!versiondata) {
+ while (1)
+ ; // halt
+ }
+ // configure board to read RFID tags and cards
+ nfc.SAMConfig();
+}
+
+void checkStations() {
+ Station* station = detectStation();
+
+ if (station != 0) {
+ lcd.setCursor(0, 0);
+ lcd.print(" ");
+ lcd.setCursor(0, 0);
+ lcd.print("Station: " + station->getName());
+ if (currentStation == 0) {
+ currentStation = station;
+ stateMachine.putDown(currentStation);
+ }
+ } else {
+ lcd.setCursor(0, 0);
+ lcd.print(" ");
+ lcd.setCursor(0, 0);
+ lcd.print("not docked");
+ if (currentStation != 0) {
+ currentStation = 0;
+ stateMachine.pickedUp();
+ }
+ }
+}
+
+Station* detectStation() {
+ uint8_t uid[7];
+ uint8_t uidLength;
+ uint16_t timeout = 100;
+ bool success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength, timeout);
+
+ if (!success) {
+ return 0;
+ }
+
+ uint32_t id = 0;
+ for (uint8_t i = 0; i < uidLength; i++) {
+ id <<= 8;
+ id |= uid[i];
+ }
+
+
+ Station* found = 0;
+ for (int i = 0; i < sizeof(stations); i++) {
+ Station* currentStation = &stations[i];
+ if (currentStation->check(id)) {
+ found = currentStation;
+ }
+ }
+ return found;
+}
+
+void printMp3Detail(uint8_t type, int value) {
+ lcd.clear();
+ switch (type) {
+ case TimeOut:
+ lcd.print("Time Out!");
+ break;
+ case WrongStack:
+ lcd.print("Stack Wrong!");
+ break;
+ case DFPlayerCardInserted:
+ lcd.print("Card Inserted!");
+ break;
+ case DFPlayerCardRemoved:
+ lcd.print("Card Removed!");
+ break;
+ case DFPlayerCardOnline:
+ lcd.print("Card Online!");
+ break;
+ case DFPlayerUSBInserted:
+ lcd.print("USB Inserted!");
+ break;
+ case DFPlayerUSBRemoved:
+ lcd.print("USB Removed!");
+ break;
+ case DFPlayerPlayFinished:
+ lcd.print("Num:");
+ lcd.print(value);
+ lcd.print(" Finished!");
+ break;
+ case DFPlayerError:
+ lcd.print("DFPlayerError:");
+ switch (value) {
+ case Busy:
+ lcd.print("Card not found");
+ break;
+ case Sleeping:
+ lcd.print("Sleeping");
+ break;
+ case SerialWrongStack:
+ lcd.print("Wrong Stack");
+ break;
+ case CheckSumNotMatch:
+ lcd.print("Checksum Error");
+ break;
+ case FileIndexOut:
+ lcd.print("File Index OOB");
+ break;
+ case FileMismatch:
+ lcd.print("File Mismatch");
+ break;
+ case Advertise:
+ lcd.print("In Advertise");
+ break;
+ default:
+ lcd.print("Unknown Error");
+ break;
+ }
+ break;
+ default:
+ lcd.print("Unknown Type");
+ break;
+ }
+ delay(2000); // Display the message for 2 seconds
+}
diff --git a/main/state.h b/main/state.h
new file mode 100644
index 0000000..3697703
--- /dev/null
+++ b/main/state.h
@@ -0,0 +1,18 @@
+#pragma once
+#include
+#include
+#include "station.h"
+#include "context.h"
+
+class Station;
+
+class State {
+public:
+ virtual ~State() = default;
+
+ virtual State* pickedUp() { return this; }
+ virtual State* putDown(Station* newStation) { return this; }
+ virtual State* update(Context context) { return this; }
+
+ virtual void updateDisplay(LiquidCrystal* lcd) { }
+};
diff --git a/main/statemachine.cpp b/main/statemachine.cpp
new file mode 100644
index 0000000..cdbf893
--- /dev/null
+++ b/main/statemachine.cpp
@@ -0,0 +1,32 @@
+#include "statemachine.h"
+#include "station.h"
+#include "context.h"
+
+StateMachine::StateMachine(State* initialState)
+ : currentState(initialState) {}
+
+StateMachine::~StateMachine() {
+ delete currentState;
+}
+
+void StateMachine::updateState(State* newState) {
+ if (newState != currentState) {
+ delete currentState;
+ currentState = newState;
+ }
+}
+
+void StateMachine::pickedUp() {
+ State* newState = currentState->pickedUp();
+ updateState(newState);
+}
+
+void StateMachine::putDown(Station* newStation) {
+ State* newState = currentState->putDown(newStation);
+ updateState(newState);
+}
+
+void StateMachine::update(Context context) {
+ State* newState = currentState->update(context);
+ updateState(newState);
+}
\ No newline at end of file
diff --git a/main/statemachine.h b/main/statemachine.h
new file mode 100644
index 0000000..91b7db5
--- /dev/null
+++ b/main/statemachine.h
@@ -0,0 +1,22 @@
+#pragma once
+#include
+#include
+#include "state.h"
+#include "station.h"
+#include "context.h"
+
+class StateMachine {
+private:
+ State* currentState;
+ void updateState(State* newState);
+
+public:
+ StateMachine(State* initialState);
+ ~StateMachine();
+
+ void pickedUp();
+ void putDown(Station* newSation);
+ void update(Context context);
+
+ void updateDisplay(LiquidCrystal* lcd);
+};
diff --git a/main/states.cpp b/main/states.cpp
new file mode 100644
index 0000000..e2f7ad7
--- /dev/null
+++ b/main/states.cpp
@@ -0,0 +1,62 @@
+#include "states.h"
+#include "state.h"
+#include "station.h"
+
+//-------
+// On the Move
+//-------
+
+
+OnTheMove::OnTheMove(Station* targetStation) {
+ this->targetStation = targetStation;
+}
+
+State* OnTheMove::putDown(Station* newStation) {
+ return new Hacking(newStation);
+}
+
+
+//-------
+// Hacking
+//-------
+
+Hacking::Hacking(Station* currentStation) {
+ this->currentStation = currentStation;
+}
+
+State* Hacking::pickedUp() {
+ return this;
+}
+
+//-------
+// Waiting F orPickup
+//-------
+
+WaitingForPickup::WaitingForPickup(Station* currentStation, Station* targetStation) {
+ this->currentStation = currentStation;
+ this->targetStation = targetStation;
+}
+
+State* WaitingForPickup::pickedUp() {
+ return this;
+}
+
+//-------
+// Startup
+//-------
+
+State* Startup::putDown(Station* newStation) {
+ return new NewTargetFinder(newStation);
+}
+
+//-------
+// NewTargetFinder
+//-------
+
+NewTargetFinder::NewTargetFinder(Station* currentStation) {
+ this->currentStation = currentStation;
+}
+
+State* NewTargetFinder::update(Context context) {
+ return new WaitingForPickup(this->currentStation, (&context.stations)[0]);
+}
\ No newline at end of file
diff --git a/main/states.h b/main/states.h
new file mode 100644
index 0000000..cf9bf46
--- /dev/null
+++ b/main/states.h
@@ -0,0 +1,45 @@
+#pragma once
+#include
+#include "context.h"
+#include "state.h"
+#include "states.h"
+#include "station.h"
+
+class OnTheMove : public State {
+private:
+ Station* targetStation;
+public:
+ OnTheMove(Station* targetStation);
+ State* putDown(Station* newSation) override;
+};
+
+class Hacking : public State {
+private:
+ Station* currentStation;
+public:
+ Hacking(Station* currentStation);
+ State* pickedUp() override;
+};
+
+class WaitingForPickup : public State {
+private:
+ Station* currentStation;
+ Station* targetStation;
+public:
+ WaitingForPickup(Station* currentStation, Station* targetStation);
+ State* pickedUp() override;
+};
+
+class Startup : public State {
+public:
+ State* putDown(Station* newSation) override;
+};
+
+class NewTargetFinder : public State {
+private:
+ Station* currentStation;
+public:
+ NewTargetFinder(Station* currentStation);
+ State* update(Context context) override;
+};
+
diff --git a/main/station.cpp b/main/station.cpp
new file mode 100644
index 0000000..68927c7
--- /dev/null
+++ b/main/station.cpp
@@ -0,0 +1,17 @@
+#include
+#include "station.h"
+
+Station::Station(uint32_t nfcTagId, String name) {
+ {
+ this->nfcTagId = nfcTagId;
+ this->name = name;
+ }
+}
+
+bool Station::check(uint32_t nfcTagId) {
+ return nfcTagId == this->nfcTagId;
+}
+
+String Station::getName() {
+ return this->name;
+}
diff --git a/main/station.h b/main/station.h
new file mode 100644
index 0000000..c8468bc
--- /dev/null
+++ b/main/station.h
@@ -0,0 +1,12 @@
+#pragma once
+#include
+
+class Station {
+private:
+ uint32_t nfcTagId;
+ String name;
+public:
+ Station(uint32_t nfcTagId, String name);
+ bool check(uint32_t nfcTagId);
+ String getName();
+};
diff --git a/main/timer.cpp b/main/timer.cpp
new file mode 100644
index 0000000..4692ea2
--- /dev/null
+++ b/main/timer.cpp
@@ -0,0 +1,33 @@
+#include "timer.h"
+
+Timer::Timer(unsigned long duration, bool autoRestart) {
+ this->autoRestart = autoRestart;
+ this->duration = duration;
+ this->endTime = duration;
+}
+
+void Timer::start() {
+ this->running = true;
+}
+
+bool Timer::update(unsigned long delta) {
+ if (!running) {
+ return false;
+ }
+ bool timedOut = false;
+ this->currentTime += delta;
+ if (currentTime > this->endTime) {
+ timedOut = true;
+ }
+ if (timedOut && this->autoRestart) {
+ this->endTime += this->duration;
+ }
+ if (timedOut && !this->autoRestart) {
+ running = false;
+ }
+ return timedOut;
+}
+
+bool Timer::isRunning() {
+ return this->running;
+}
diff --git a/main/timer.h b/main/timer.h
new file mode 100644
index 0000000..11dbdbb
--- /dev/null
+++ b/main/timer.h
@@ -0,0 +1,18 @@
+#pragma once
+#include
+
+class Timer {
+private:
+ unsigned long duration;
+ bool autoRestart;
+
+ unsigned long currentTime;
+ unsigned long endTime;
+ bool running;
+
+public:
+ Timer(unsigned long duration, bool autoRestart);
+ void start();
+ bool update(unsigned long delta);
+ bool isRunning();
+};