diff options
author | Linnnus <[email protected]> | 2024-04-09 09:20:05 +0200 |
---|---|---|
committer | Linnnus <[email protected]> | 2024-04-09 09:20:05 +0200 |
commit | 45e0f39612122163d0be114610bc7d99ec6fea84 (patch) | |
tree | 73ea75614669599d74e7eff1dee14a9ee48888f1 /det_hele/det_hele.ino |
Initial commit
Diffstat (limited to 'det_hele/det_hele.ino')
-rw-r--r-- | det_hele/det_hele.ino | 333 |
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 |