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(); +};