summaryrefslogtreecommitdiff
path: root/det_hele/det_hele.ino
diff options
context:
space:
mode:
authorLinnnus <[email protected]>2024-04-09 09:20:05 +0200
committerLinnnus <[email protected]>2024-04-09 09:20:05 +0200
commit45e0f39612122163d0be114610bc7d99ec6fea84 (patch)
tree73ea75614669599d74e7eff1dee14a9ee48888f1 /det_hele/det_hele.ino
Initial commit
Diffstat (limited to 'det_hele/det_hele.ino')
-rw-r--r--det_hele/det_hele.ino333
1 files changed, 333 insertions, 0 deletions
diff --git a/det_hele/det_hele.ino b/det_hele/det_hele.ino
new file mode 100644
index 0000000..93ac90f
--- /dev/null
+++ b/det_hele/det_hele.ino
@@ -0,0 +1,333 @@
+#include <HX711.h>
+
+// Controls whether red/green LED is turned on.
+const uint8_t DISPLAY_LOCK_PIN = 12;
+
+// Pins used to interact with SIPO controlling four 7-segment dislays.
+const uint8_t DISPLAY_CLOCK_PIN = 11;
+const uint8_t DISPLAY_DATA_PIN = 10;
+const uint8_t DISPLAY_STROBE_PIN = 9;
+
+// Pin controls weather or not the alarm clock is ringing.
+const uint8_t NOISE_ENABLE_PIN = 8;
+
+// Pins used to interact with weight circuit.
+const uint8_t WEIGHT_DATA_PIN = 7; // Reads data from HX711 (DT)
+const uint8_t WEIGHT_CLOCK_PIN = 6; // Drives HX711 output. (SCK)
+HX711 scale;
+int WEIGHT_SAMPLE_AMOUNT = 5; // amount of samples of each observation.
+int AWARE_TIME = 2000; //amount of miliseconds in the aware state.
+
+// Pins used to interact with rotary dial circuit.
+const uint8_t DIAL_DATA_PIN = 5; // Reads data from PISO (4021).
+const uint8_t DIAL_CLOCK_PIN = 4; // Drives PISO output.
+const uint8_t DIAL_READY_PIN = 3; // Output from FLIP-FLOP.
+const uint8_t DIAL_RESET_PIN = 2; // Reset pin on FLIP-FLOP.
+
+// The program is centered around a state machine.
+// TODO: Describe states.
+enum {
+ STATE_UNARMED,
+ STATE_ARMED,
+ STATE_AWARE,
+ STATE_RINGING,
+} state;
+
+unsigned long awareStartTime;
+
+const double MAX_DEVIATION = 200;
+double savedWeight;
+
+typedef uint8_t Passcode[4];
+
+Passcode savedPass;
+
+Passcode currentPass;
+int currentPassIndex = 0;
+
+
+//All the setup functions.
+void unarmedSetup() {
+ Serial.println("Entering UNARMED state");
+ state = STATE_UNARMED;
+
+ digitalWrite(DISPLAY_LOCK_PIN, LOW);
+}
+
+void armedSetup() {
+ Serial.println("Entering ARMED state");
+
+ digitalWrite(DISPLAY_LOCK_PIN, HIGH);
+
+ // The weight isn't saved as part of armedSetup() because that would allow an attack where the weight is gradually
+ // lowered by alternating between the armed and aware states. If the weight were to be updated every time, an
+ // atacker could lower the weight graduadally by staying within the margin of error on every step.
+ if (state == STATE_UNARMED) {
+ scale.begin(WEIGHT_DATA_PIN, WEIGHT_CLOCK_PIN);
+ scale.tare();
+ savedWeight = scale.get_value(WEIGHT_SAMPLE_AMOUNT);
+ }
+
+ state = STATE_ARMED;
+}
+
+void awareSetup() {
+ Serial.println("Entering AWARE state");
+
+ state = STATE_AWARE;
+ awareStartTime = millis();
+}
+
+void ringingSetup() {
+ Serial.println("Entering RINGING state");
+
+ state = STATE_RINGING;
+ digitalWrite(NOISE_ENABLE_PIN, HIGH);
+}
+
+
+//Initial setup function.
+void setup() {
+ Serial.begin(9600);
+
+ pinMode(DISPLAY_LOCK_PIN, OUTPUT);
+
+ pinMode(DISPLAY_CLOCK_PIN, OUTPUT);
+ pinMode(DISPLAY_STROBE_PIN, OUTPUT);
+ pinMode(DISPLAY_DATA_PIN, OUTPUT);
+
+ pinMode(DIAL_DATA_PIN, INPUT);
+ pinMode(DIAL_CLOCK_PIN, OUTPUT);
+ pinMode(DIAL_READY_PIN, INPUT);
+ pinMode(DIAL_RESET_PIN, OUTPUT);
+
+ pinMode(WEIGHT_DATA_PIN, INPUT);
+ pinMode(WEIGHT_CLOCK_PIN, OUTPUT);
+
+ pinMode(NOISE_ENABLE_PIN, OUTPUT);
+
+ // Clear out display ibn case there's old data left in the encoders.
+ clearDisplay();
+
+ // Enter initial state;
+ unarmedSetup();
+}
+
+
+//other functions.
+uint8_t dialRead() {
+ Serial.println("Data ready from rotary dial circuit!!");
+
+ digitalWrite(DIAL_CLOCK_PIN, LOW);
+ uint8_t data = 0;
+ for (int i = 0; i < 8; ++i) {
+ int bit = digitalRead(DIAL_DATA_PIN);
+ data = (data << 1) | bit;
+
+ digitalWrite(DIAL_CLOCK_PIN, HIGH);
+ digitalWrite(DIAL_CLOCK_PIN, LOW);
+ }
+
+ // 0 is encoded as 10 pulses.
+ if (data == 10) {
+ data = 0;
+ }
+
+ //uint8_t data = shiftIn(PISO_DATA_PIN, PISO_CLOCK_PIN, MSBFIRST);
+ Serial.print("Number: ");
+ Serial.print(data, DEC);
+ Serial.print(", ");
+ Serial.println(data, BIN);
+
+ digitalWrite(DIAL_RESET_PIN, LOW);
+ digitalWrite(DIAL_RESET_PIN, HIGH);
+ digitalWrite(DIAL_RESET_PIN, LOW);
+
+ return data;
+}
+
+double weightDeviation() {
+ double currentWeight = scale.get_value(WEIGHT_SAMPLE_AMOUNT);
+ double deviation = fabs(currentWeight - savedWeight);
+ Serial.print("Deviation: ");
+ Serial.println(deviation, 1);
+ return deviation;
+}
+
+
+//All loop functions.
+void unarmedLoop() {
+ if (digitalRead(DIAL_READY_PIN)) {
+ currentPass[currentPassIndex] = dialRead();
+
+ displayDigitAt(currentPass[currentPassIndex], currentPassIndex);
+
+ if (currentPassIndex == 3) {
+ memcpy(savedPass, currentPass, sizeof(savedPass));
+
+ delay(1000);
+ clearDisplay();
+
+ armedSetup();
+ currentPassIndex = 0;
+ } else {
+ currentPassIndex += 1;
+ }
+ }
+}
+
+void displayDigitAt(uint8_t digit, uint8_t i) {
+ const uint8_t ALL_LATCHED = 0xF0;
+
+ uint8_t bits = ALL_LATCHED - (16 << i) + digit;
+ digitalWrite(DISPLAY_STROBE_PIN, LOW);
+ shiftOut(DISPLAY_DATA_PIN, DISPLAY_CLOCK_PIN, MSBFIRST, bits);
+ digitalWrite(DISPLAY_STROBE_PIN, HIGH);
+
+ bits = ALL_LATCHED + digit;
+ digitalWrite(DISPLAY_STROBE_PIN, LOW);
+ shiftOut(DISPLAY_DATA_PIN, DISPLAY_CLOCK_PIN, MSBFIRST, bits);
+ digitalWrite(DISPLAY_STROBE_PIN, HIGH);
+}
+
+void displayPasscode(Passcode p) {
+ for (int i = 0; i <= 3; ++i) {
+ displayDigitAt(p[i], i);
+ }
+}
+
+void displayNumber(int value) {
+ if (value > 9999) {
+ value = 9999;
+ } else if (value < 0) {
+ value = 0;
+ }
+
+ for (int i = 3; i >= 0; --i) {
+ uint8_t digit = value % 10;
+ value /= 10;
+ displayDigitAt(digit, i);
+ }
+}
+
+void clearDisplay() {
+ for (int i = 0; i <= 3; ++i) {
+ displayDigitAt(10, i);
+ }
+}
+
+bool handlePasscode() {
+ if (digitalRead(DIAL_READY_PIN)) {
+ currentPass[currentPassIndex] = dialRead();
+
+ displayDigitAt(currentPass[currentPassIndex], currentPassIndex);
+
+ if (currentPassIndex == 3) {
+ currentPassIndex = 0;
+
+ bool validPass = memcmp(savedPass, currentPass, sizeof(savedPass)) == 0;
+ if (validPass) {
+ // Very cool victory animation.
+ delay(300);
+ for (int i = 0; i < 2; ++i) {
+ clearDisplay();
+ delay(200);
+ for (int j = 0; j <= 3; ++j) {
+ delay(100);
+ displayDigitAt(currentPass[j], j);
+ }
+ delay(300);
+ }
+ clearDisplay();
+
+ return true;
+ } else {
+ // blink passcode
+ const unsigned long wait = 100;
+ for (int i = 0; i < 4; ++i) {
+ delay(wait);
+ clearDisplay();
+ delay(wait);
+ displayPasscode(currentPass);
+ }
+ delay(wait);
+ clearDisplay();
+
+ return false;
+ }
+ } else {
+ currentPassIndex += 1;
+ return false;
+ }
+ }
+
+ return false;
+}
+
+void armedLoop() {
+ if (handlePasscode()) {
+ unarmedSetup();
+ }
+
+ double deviation = weightDeviation();
+ if (deviation > MAX_DEVIATION) {
+ awareSetup();
+ }
+}
+
+void awareLoop() {
+ if (handlePasscode()) {
+ unarmedSetup();
+ }
+
+ double deviation = weightDeviation();
+ if (deviation < MAX_DEVIATION) {
+ armedSetup();
+ return;
+ }
+
+ int remainingTime = AWARE_TIME - (millis() - awareStartTime);
+ Serial.print("Remaining time:");
+ Serial.println(remainingTime);
+ if (remainingTime <= 0) {
+ ringingSetup();
+ }
+}
+
+// FIXME: What happens if user starts entering password while in aware state and ringing state only sees last two digits?
+
+void ringingLoop() {
+ if (handlePasscode()) {
+ digitalWrite(NOISE_ENABLE_PIN, LOW);
+ unarmedSetup();
+ }
+
+ // FIXME: SHouldn't be able to do this for non-testing purposes.
+ double deviation = weightDeviation();
+ Serial.println(deviation, 1);
+ if (deviation < MAX_DEVIATION) {
+ digitalWrite(NOISE_ENABLE_PIN, LOW);
+ armedSetup();
+ }
+}
+
+//initial loop function, wich contains the switch (state machine).
+void loop() {
+ switch (state) {
+ case STATE_UNARMED:
+ unarmedLoop();
+ break;
+ case STATE_ARMED:
+ armedLoop();
+ break;
+ case STATE_AWARE:
+ awareLoop();
+ break;
+ case STATE_RINGING:
+ ringingLoop();
+ break;
+ default:
+ Serial.println("warning: unhandled state");
+ break;
+ }
+} \ No newline at end of file