#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <NewPing.h>
#include <SoftwareSerial.h>
#include <Keypad.h>
#include "PCF8574.h"
#define SIMULATION true // IMPORTANT! COMMENT FOR ACTUAL
#ifdef SIMULATION
bool simulation = true;
#else
bool simulation = false;
#endif
// Pins definitions
#define COIN_SIG_PIN 2
#define COIN_INH_PIN 3
#define PARCEL_SENS_ECHO_PIN 8
#define PARCEL_SENS_TRIG_PIN 9
#define PARCEL_LOCK_PIN 10
#define DRAWER_LOCK_PIN 11
#ifdef SIMULATION
// >>>> ACTUAL >>>>
#define PARCEL_LOCK_SENS_PIN 10
#define DRAWER_LOCK_SENS_PIN 11
#define GSM_RX_PIN 12
#define GSM_TX_PIN 13
// <<<< ACTUAL <<<<
#else
// >>>> SIMULATION >>>>
#define PARCEL_LOCK_SENS_PIN 22
#define DRAWER_LOCK_SENS_PIN 24
#define GSM_RX_PIN 99
#define GSM_TX_PIN 99
// <<<< SIMULATION <<<<
#endif
PCF8574 pcf8574(0x20);
SoftwareSerial sim(GSM_TX_PIN, GSM_RX_PIN);
const uint8_t ROWS = 4;
const uint8_t COLS = 4;
char keys[ROWS][COLS] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
uint8_t colPins[COLS] = { A3, A2, A1, A0 }; // Pins connected to C1, C2, C3, C4
uint8_t rowPins[ROWS] = { 7, 6, 5, 4 }; // Pins connected to R1, R2, R3, R4
Keypad keyPad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
LiquidCrystal_I2C lcd(0x27, 16, 2);
NewPing sonar(PARCEL_SENS_TRIG_PIN, PARCEL_SENS_ECHO_PIN, 420);
// Set variables
int SONAR_NORMAL_DISTANCE = 25;
// EEPROM address
const int eeprom_addr_first = 0;
const int eeprom_addr_change = 10;
const int eeprom_addr_pin = 15;
const int eeprom_addr_state = 50;
const int eeprom_addr_phone = 100;
// GSM Variables
int _timeout;
String _buffer;
// Stored Variables
bool isFirstLaunch = true;
String phone = "+639999999999";
String pin = "0000";
String state = "empty";
int change = 0;
// Input Variables
String otpInput = "";
String pinInput = "";
String phoneInput = "";
String changeInput = "";
// Generated Variables
String otp = "";
// State Variables
int buttonLastState = HIGH;
int credit = 0;
// Coin Slot Variables
unsigned long lastAction = 0; //When last action was made
unsigned long lastPulse = 0; //When last pulse was send
int pulseCount = 0; //How many pulses we got
bool coinEnabled = false;
const int pulseTimeout = 300;
const int actionTimeout = 5000;
unsigned long tempAction;
unsigned long tempPulse;
void coinInterrupt() {
lastAction = millis();
lastPulse = millis();
pulseCount++;
}
void (*resetFunc)(void) = 0;
void setup() {
pinMode(PARCEL_LOCK_PIN, OUTPUT);
pinMode(DRAWER_LOCK_PIN, OUTPUT);
pinMode(PARCEL_SENS_TRIG_PIN, OUTPUT);
pinMode(PARCEL_SENS_ECHO_PIN, INPUT);
pinMode(COIN_INH_PIN, OUTPUT);
pinMode(COIN_SIG_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(COIN_SIG_PIN), coinInterrupt, RISING);
digitalWrite(COIN_INH_PIN, LOW);
digitalWrite(PARCEL_LOCK_PIN, HIGH);
digitalWrite(DRAWER_LOCK_PIN, HIGH);
Serial.begin(9600);
Serial.println(F("[SYS] BEGIN"));
Serial.print(F("[SYS] Environment: "));
if (simulation) Serial.println(F("Simulation"));
else Serial.println(F("Hardware"));
// if (pcf8574.begin() == false) {
// Serial.println(F("\nERROR: cannot communicate to I2C.\nPlease reboot.\n"));
// while (1)
// ;
// } else {
// Serial.println("I2C Loaded.");
// }
// pcf8574.pinMode(P0, INPUT);
// pcf8574.pinMode(P1, INPUT);
pinMode(PARCEL_LOCK_SENS_PIN, INPUT);
pinMode(DRAWER_LOCK_SENS_PIN, INPUT);
if (!simulation) {
// >>>> ACTUAL >>>>
Serial.println(F("[GSM] Loading..."));
delay(7000);
sim.begin(9600);
_buffer.reserve(50);
delay(1000);
// sim.println("AT");
// delay(200);
Serial.println(F("[GSM] Loaded."));
sendSMS("Started");
// <<<< ACTUAL <<<<
}
Serial.println(F("[EEPROM] Checking..."));
Serial.print(F("[EEPROM] Length: "));
Serial.println(EEPROM.length());
Serial.print(F("[EEPROM] First launch: "));
Serial.println(EEPROM.read(eeprom_addr_first));
if (EEPROM.read(eeprom_addr_first) == 255) {
Serial.println(F("[EEPROM] System first launch. Setting inital values."));
EEPROM.put(eeprom_addr_first, isFirstLaunch);
EEPROM.put(eeprom_addr_change, change);
writeStringToEEPROM(eeprom_addr_pin, pin);
writeStringToEEPROM(eeprom_addr_state, state);
writeStringToEEPROM(eeprom_addr_phone, phone);
Serial.println(F("[EEPROM] Inital values set. Proceeding..."));
}
delay(500);
Serial.println(F("[EEPROM] Loading values..."));
EEPROM.get(eeprom_addr_change, change);
readStringFromEEPROM(eeprom_addr_pin, &pin);
readStringFromEEPROM(eeprom_addr_state, &state);
readStringFromEEPROM(eeprom_addr_phone, &phone);
Serial.print(F("[EEPROM] Pin: "));
Serial.println(pin);
Serial.print(F("[EEPROM] Phone: "));
Serial.println(phone);
Serial.print(F("[EEPROM] State: "));
Serial.println(state);
Serial.print(F("[EEPROM] Change: ") );
Serial.println(String(change));
randomSeed(analogRead(A5));
lcd.init();
lcd.backlight();
delay(1000);
}
int mode = 0;
const int menuSize = 4;
String menuStringList[menuSize] = {
"Deliver Parcel",
"Receive Parcel",
"Set Phone Number",
"Set Pin Code"
};
int menuCursor = 0;
String menuString = menuStringList[0];
unsigned long previousMillis = 0;
unsigned int interval = 500;
int iMenu = 0;
unsigned long previousMillisDebug = 0;
char key;
uint8_t parcelSenseVal = 0;
uint8_t drawerSenseVal = 0;
void loop() {
char key = keyPad.getKey();
if (sim.available() > 0)
Serial.write(sim.read());
// if (!simulation) {
// parcelSenseVal = pcf8574.digitalRead(P0);
// drawerSenseVal = pcf8574.digitalRead(P1);
// } else {
// parcelSenseVal = digitalRead(PARCEL_LOCK_SENS_PIN);
// drawerSenseVal = digitalRead(DRAWER_LOCK_SENS_PIN);
// }
// if (millis() - previousMillisDebug >= 1000) {
// previousMillisDebug = millis();
// Serial.print(simulation);
// Serial.print(F(" "));
// Serial.print(String(parcelSenseVal));
// Serial.print(F(","));
// Serial.print(String(drawerSenseVal));
// Serial.println(F(" Lock: "));
// }
switch (mode) {
case 0:
lcd.setCursor(0, 0);
lcd.print(F("Parcel Depository"));
if (millis() - previousMillis >= interval) {
previousMillis = millis();
if (iMenu < menuString.length() - 3) {
lcd.setCursor(0, 1);
lcd.print("< >");
lcd.setCursor(2, 1);
String displayText = menuString.substring(iMenu, iMenu + 12);
lcd.print(displayText);
iMenu++;
} else {
iMenu = 0;
}
}
if (key != NO_KEY) {
Serial.println(key);
switch (key) {
lcd.clear();
case '*':
if (menuCursor == 0) {
menuCursor = menuSize - 1;
} else {
menuCursor--;
}
iMenu = 0;
menuString = menuStringList[menuCursor];
break;
case '#':
if (menuCursor == menuSize - 1) {
menuCursor = 0;
} else {
menuCursor++;
}
iMenu = 0;
menuString = menuStringList[menuCursor];
break;
case 'D':
switch (menuCursor) {
case 0:
showDeliverParcel();
break;
case 1:
showReceiveParcel();
break;
case 2:
showSetPhone();
break;
case 3:
showSetPin();
break;
}
break;
}
}
break;
}
delay(10); // REMOVE for actual
}
int showReceiveParcel() {
bool authorized = authorize();
if (!authorized) {
return 0;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("STATUS: " + state);
lcd.setCursor(0, 1);
lcd.print(F("Press [D]"));
bool loopConfirm = true;
while (loopConfirm) {
char key = keyPad.getKey();
if (key != NO_KEY) {
switch (key) {
case 'D':
loopConfirm = false;
if (state == "pending") {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Receive Pending"));
lcd.setCursor(0, 1);
lcd.print(F("Cancel? [D]"));
bool loopReceive = true;
while (loopReceive) {
char key = keyPad.getKey();
if (key != NO_KEY) {
switch (key) {
case 'D':
loopReceive = false;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Parcel Cancelled"));
lcd.setCursor(0, 1);
lcd.print(F("Locks Unlocked"));
digitalWrite(DRAWER_LOCK_PIN, LOW);
bool loopCancel = true;
while (loopCancel) {
char key = keyPad.getKey();
if (key != NO_KEY) {
switch (key) {
case 'A':
loopCancel = false;
return 0;
break;
case 'D':
saveState("empty");
saveChange(0);
loopCancel = false;
delay(1000);
resetFunc();
return 0;
break;
}
}
}
// bool drawerOpen = false;
// while (!drawerOpen) {
// if (digitalRead(PARCEL_LOCK_SENS_PIN) == LOW) {
// drawerOpen = true;
// lcd.setCursor(0, 1);
// lcd.print(F("Drawer Opened"));
// }
// }
// delay(1000);
// while (drawerOpen) {
// if (digitalRead(PARCEL_LOCK_SENS_PIN) == HIGH) {
// drawerOpen = false;
// lcd.setCursor(0, 1);
// lcd.print("Drawer Closed");
// }
// }
// delay(1000);
// lcd.print("Locking...");
saveState("empty");
break;
case 'A':
loopReceive = false;
return 0;
break;
}
}
}
}
if (state == "received") {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Parcel Received");
bool detect = true;
while (detect) {
unsigned int uS = sonar.ping();
unsigned int distance = uS / US_ROUNDTRIP_CM;
Serial.print(F("Sonar Disance"));
Serial.println(distance);
if (distance > 25) {
lcd.setCursor(0, 1);
lcd.print("Parcel Retrieved.");
delay(3000);
saveState("empty");
delay(1000);
resetFunc();
return 0;
}
}
}
if (state == "empty") {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("System Idle"));
lcd.setCursor(0, 1);
lcd.print(F("Set Change..."));
delay(2000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F(" Set Change "));
lcd.setCursor(0, 1);
lcd.print(F("P "));
int changeInputCursor = 2;
lcd.setCursor(changeInputCursor, 1);
lcd.blink();
bool loop = true;
while (loop) {
char key = keyPad.getKey();
if (key != NO_KEY) {
switch (key) {
case 'A':
lcd.noBlink();
changeInput = "";
return 0;
break;
case 'B':
break;
case 'C':
if (changeInput.length() > 2) {
lcd.setCursor(changeInputCursor - 1, 1);
lcd.print(" ");
changeInputCursor -= 1;
lcd.setCursor(changeInputCursor, 1);
changeInput = changeInput.substring(0, changeInput.length() - 1);
lcd.blink();
}
break;
case 'D':
if (changeInput.length() > 0) {
loop = false;
change = changeInput.toInt();
saveChange(change);
saveState("pending");
changeInput = "";
lcd.noBlink();
delay(1000);
resetFunc();
return 0;
}
break;
case '*':
break;
case '#':
break;
default:
if (changeInput.length() < 5) {
changeInput += key;
lcd.setCursor(changeInputCursor, 1);
changeInputCursor += 1;
lcd.print(key);
}
break;
}
}
if (phone.length() == 13) {
lcd.noBlink();
}
}
lcd.noBlink();
}
break;
case 'A':
loopConfirm = false;
return 0;
break;
}
}
}
return 0;
}
int showDeliverParcel() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Press [D] to");
lcd.setCursor(0, 1);
lcd.print("send OTP code.");
bool loopConfirm = true;
while (loopConfirm) {
char key = keyPad.getKey();
if (key != NO_KEY) {
switch (key) {
case 'D':
sendOTP();
showSMSSentStatus();
loopConfirm = false;
break;
case 'A':
loopConfirm = false;
return 0;
break;
}
}
}
return 0;
}
int showSetPhone() {
lcd.clear();
lcd.setCursor(0, 0);
bool loopPin = true;
bool authorized = authorize();
if (!authorized) {
return 0;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F(" Set Phone No."));
lcd.setCursor(0, 1);
lcd.print(F(" ------------- "));
int phoneCursor = 1;
if (phone) {
phoneInput = phone;
lcd.setCursor(phoneCursor, 1);
lcd.print(phoneInput);
phoneCursor += phoneInput.length();
}
lcd.setCursor(phoneCursor, 1);
lcd.blink();
bool loop = true;
while (loop) {
char key = keyPad.getKey();
if (key != NO_KEY) {
switch (key) {
case 'A':
lcd.noBlink();
phoneInput = "";
return 0;
break;
case 'B':
break;
case 'C':
if (phoneInput.length() > 3) {
lcd.setCursor(phoneCursor - 1, 1);
lcd.print("-");
phoneCursor -= 1;
lcd.setCursor(phoneCursor, 1);
phoneInput = phoneInput.substring(0, phoneInput.length() - 1);
lcd.blink();
}
break;
case 'D':
if (phoneInput.length() == 13) {
loop = false;
phone = phoneInput;
savePhone(phone);
phoneInput = "";
lcd.noBlink();
return 0;
}
break;
case '*':
break;
case '#':
break;
default:
if (phoneInput.length() < 13) {
phoneInput += key;
lcd.setCursor(phoneCursor, 1);
phoneCursor += 1;
lcd.print(key);
}
break;
}
}
if (phone.length() == 13) {
lcd.noBlink();
}
}
lcd.noBlink();
return 0;
}
int showSetPin() {
lcd.clear();
lcd.setCursor(0, 0);
bool loopPin = true;
bool authorized = authorize();
if (!authorized) {
return 0;
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F(" Set Pin Code"));
lcd.setCursor(0, 1);
lcd.print(F(" ---- "));
int pinCursor = 6;
if (pin) {
pinInput = pin;
lcd.setCursor(pinCursor, 1);
lcd.print(pinInput);
pinCursor += pinInput.length();
}
lcd.setCursor(pinCursor, 1);
lcd.blink();
bool loop = true;
while (loop) {
char key = keyPad.getKey();
if (key != NO_KEY) {
switch (key) {
case 'A':
lcd.noBlink();
return 0;
break;
case 'B':
break;
case 'C':
if (pinInput.length() > 0) {
lcd.setCursor(pinCursor - 1, 1);
lcd.print("-");
pinCursor -= 1;
lcd.setCursor(pinCursor, 1);
pinInput = pinInput.substring(0, pinInput.length() - 1);
lcd.blink();
}
break;
case 'D':
lcd.noBlink();
if (pinInput.length() == 4) {
loop = false;
pin = pinInput;
savePin(pin);
return 0;
} else {
return 0;
}
break;
case '*':
break;
case '#':
break;
default:
if (pinInput.length() < 4) {
pinInput += key;
lcd.setCursor(pinCursor, 1);
pinCursor += 1;
lcd.print(key);
}
break;
}
}
if (phone.length() == 11) {
lcd.noBlink();
}
}
return 0;
}
bool authorize() {
pinInput = "";
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F(" Enter PIN"));
lcd.setCursor(0, 1);
lcd.print(F(" ---- "));
int pinCursor = 6;
lcd.setCursor(pinCursor, 1);
lcd.blink();
bool loop = true;
while (loop) {
char key = keyPad.getKey();
if (key != NO_KEY) {
switch (key) {
case 'A':
lcd.noBlink();
return false;
case 'B':
break;
case 'C':
if (pinInput.length() > 0) {
lcd.setCursor(pinCursor - 1, 1);
lcd.print("-");
pinCursor -= 1;
lcd.setCursor(pinCursor, 1);
pinInput = pinInput.substring(0, pinInput.length() - 1);
lcd.blink();
}
break;
case 'D':
lcd.noBlink();
if (pin == pinInput) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F(" Authorized"));
lcd.setCursor(0, 1);
lcd.print(F(" Correct PIN"));
delay(2000);
pinInput = "";
return true;
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F(" Access Denied"));
lcd.setCursor(0, 1);
lcd.print(F(" Invalid PIN"));
delay(2000);
lcd.clear();
pinInput = "";
return false;
}
case '*': break;
case '#': break;
default:
if (pinInput.length() < 4) {
pinInput += key;
lcd.setCursor(pinCursor, 1);
pinCursor += 1;
lcd.print(key);
}
break;
}
}
if (pinInput.length() == 4) {
lcd.noBlink();
}
}
}
int showSMSSentStatus() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F(" SUCCESS"));
lcd.setCursor(0, 1);
lcd.print(F(" OTP Sent"));
delay(2000);
lcd.clear();
String instructionTop = F("Ask receiver for the code.");
String instructionBottom = F("Press [D] to Proceed.");
unsigned long previousMillis = 0;
int i = 0;
lcd.print(F("Press [D] to Proceed."));
delay(1000);
bool loop = true;
while (loop) {
if (millis() - previousMillis >= 500) {
previousMillis = millis();
if (i < instructionTop.length() - 15) {
lcd.setCursor(0, 0);
String displayTextTop = instructionTop.substring(i, i + 16);
lcd.print(displayTextTop);
lcd.setCursor(0, 1);
String displayTextBot = instructionBottom.substring(i, i + 16);
lcd.print(displayTextBot);
i++;
} else {
i = 0;
}
}
char key = keyPad.getKey();
if (key != NO_KEY) {
switch (key) {
case 'A':
lcd.noBlink();
return 0;
break;
case 'B':
break;
case 'C':
break;
case 'D':
showOTPInputScreen();
break;
case '*':
break;
case '#':
break;
}
}
}
return 0;
}
int showOTPInputScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F(" INPUT OTP CODE"));
lcd.setCursor(0, 1);
lcd.print(F(" - - - - - -"));
int pinCursor = 2;
lcd.setCursor(pinCursor, 1);
lcd.blink();
bool loop = true;
while (loop) {
char key = keyPad.getKey();
if (key != NO_KEY) {
switch (key) {
case 'A':
lcd.noBlink();
return 0;
break;
case 'B':
break;
case 'C':
break;
case 'D':
break;
case '*':
break;
case '#':
break;
}
showCorrectCodeScreen();
// if (otpInput.length() < 6) {
// otpInput += key;
// lcd.print(key);
// lcd.print(" ");
// if (otpInput.length() == 6 && otpInput == otp) {
// showCorrectCodeScreen();
// } else if (otpInput.length() == 6 && otpInput != otp) {
// showIncorrectCodeScreen();
// }
// }
}
}
return 0;
}
int showCorrectCodeScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Code Correct"));
delay(1000);
lcd.setCursor(0, 1);
lcd.print(F("Openning..."));
digitalWrite(PARCEL_LOCK_PIN, LOW); // open
delay(1000);
lcd.setCursor(0, 1);
lcd.print(F("Box Opened!"));
delay(2000);
showParcelInputScreen();
return 0;
}
int showIncorrectCodeScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F(" Incorrect Code"));
lcd.setCursor(0, 1);
lcd.print(F(" Try Again"));
delay(2000);
otpInput = "";
showOTPInputScreen();
return 0;
}
unsigned int detectElapsed = 0;
unsigned long elapsedMillis = 0;
int showParcelInputScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Waiting for "));
lcd.setCursor(0, 1);
lcd.print(F("parcel..."));
bool parcelWaiting = true;
while (parcelWaiting) {
unsigned int uS = sonar.ping();
unsigned int distance = uS / US_ROUNDTRIP_CM;
if (distance < 25) {
if (millis() - elapsedMillis > 1000) {
elapsedMillis = millis();
detectElapsed += 1000;
if (detectElapsed == 3000) {
parcelWaiting = false;
}
}
}
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Parcel Detected"));
lcd.setCursor(0, 1);
delay(1000);
lcd.print(F("Please close the box."));
// bool boxCloseWaiting = true;
// if (boxCloseWaiting) {
// if (parcelSenseVal == 1) {
// boxCloseWaiting = false;
// }
// }
delay(2000);
lcd.clear();
lcd.noBlink();
lcd.setCursor(0, 0);
lcd.print(F("Box closed."));
lcd.setCursor(0, 1);
lcd.print(F("Lock? [D]"));
bool loopParcelLockConfirm = true;
while (loopParcelLockConfirm) {
char key = keyPad.getKey();
if (key != NO_KEY) {
switch (key) {
case 'D':
digitalWrite(PARCEL_LOCK_PIN, HIGH);
loopParcelLockConfirm = false;
break;
case 'A':
loopParcelLockConfirm = false;
return 0;
break;
}
}
}
delay(1000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Box Locked."));
delay(1000);
lcd.setCursor(0, 0);
lcd.print(F("Releasing"));
lcd.setCursor( 0, 1);
lcd.print(F("Payment..."));
digitalWrite(DRAWER_LOCK_PIN, LOW);
delay(1000);
// STAGE: OPEN DRAWER
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(F("Claim payment."));
lcd.setCursor(0, 1);
lcd.print(F("Lock? [D]"));
bool loopDrawerLockConfirm = true;
while (loopDrawerLockConfirm) {
char key = keyPad.getKey();
if (key != NO_KEY) {
switch (key) {
case 'D':
digitalWrite(DRAWER_LOCK_PIN, HIGH);
loopDrawerLockConfirm = false;
break;
case 'A':
loopDrawerLockConfirm = false;
return 0;
break;
}
}
}
// bool drawerOpen = false;
// while (!drawerOpen) {
// if (!simulation) {
// parcelSenseVal = pcf8574.digitalRead(P0);
// drawerSenseVal = pcf8574.digitalRead(P1);
// } else {
// parcelSenseVal = digitalRead(PARCEL_LOCK_SENS_PIN);
// drawerSenseVal = digitalRead(DRAWER_LOCK_SENS_PIN);
// }
// Serial.println(drawerSenseVal);
// if (drawerSenseVal == 0) {
// drawerOpen = true;
// delay(2000);
// }
// }
// while (drawerOpen) {
// if (drawerSenseVal == 1) {
// drawerOpen = false;
// }
// }
// STAGE: CLOSE DRAWER
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Drawer Closed.");
lcd.setCursor(0, 1);
lcd.print("Receiving Change");
delay(2000);
// STAGE: CHANGE
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Insert change.");
bool receiveChange = true;
coinEnabled = true;
lcd.noBlink();
while (receiveChange) {
lcd.setCursor(0, 1);
lcd.print(F("Change: "));
lcd.print(credit);
lcd.print(F("/"));
lcd.print(change);
tempAction = lastAction;
tempPulse = lastPulse;
digitalWrite(COIN_INH_PIN, coinEnabled);
if (pulseCount > 0) coinEnabled = false;
else coinEnabled = true;
if (millis() - lastPulse >= pulseTimeout && pulseCount > 0) {
if (tempAction != lastAction || tempPulse != lastPulse) return;
Serial.print("Coin: ");
switch (pulseCount) {
case 20:
Serial.println("20 Pesos");
credit += 20;
break;
case 10:
Serial.println("10 Pesos");
credit += 10;
break;
case 5:
Serial.println("5 Pesos");
credit += 5;
break;
case 1:
Serial.println("1 Peso");
credit += 1;
break;
}
pulseCount = 0;
}
if (credit >= change) {
receiveChange = false;
coinEnabled = false;
digitalWrite(COIN_INH_PIN, coinEnabled);
}
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Parcel Received.");
lcd.setCursor(0, 1);
lcd.print("Thank you!");
sendNotification();
delay(2000);
saveState("received");
delay(5000);
resetFunc();
return 0;
}
void showInputChange() {}
String generateRandomPin() {
static const char numChars[] = "0123456789";
String tmp_Pin;
tmp_Pin.reserve(6);
for (int i = 0; i < 6; ++i) {
tmp_Pin += numChars[random(0, 100) % (sizeof(numChars) - 1)];
}
return tmp_Pin;
}
void sendOTP() {
otp = generateRandomPin();
Serial.println(otp);
sendSMS("ParcelDepo OTP: " + otp);
}
void sendNotification() {
sendSMS("ParcelDepo: Parcel Received!");
}
void sendSMS(String message) {
Serial.println(F("Sending Message"));
sim.println("AT+CMGF=1"); // Sets the GSM Module in Text Mode
delay(200);
// Serial.println(F("[GSM] Set SMS Number"));
sim.println("AT+CMGS=\"" + phone + "\"\r"); // Mobile phone number to send message
delay(200);
sim.println(message);
delay(100);
sim.println((char)26); // ASCII code of CTRL+Z
delay(200);
#ifndef SIMULATION
// >>>> ACTUAL >>>>
_buffer = _readSerial();
// <<<< ACTUAL <<<<
#endif
Serial.println(F("[GSM] SMS Sent"));
}
String _readSerial() {
_timeout = 0;
while (!sim.available() && _timeout < 12000) {
delay(13);
_timeout++;
}
if (sim.available()) {
return sim.readString();
}
}
void saveChange(int change) {
EEPROM.put(eeprom_addr_change, change);
delay(100);
Serial.print(F("[SYS] Change now: "));
Serial.println(String(change));
}
void saveState(String state) {
writeStringToEEPROM(eeprom_addr_state, state);
delay(100);
Serial.print(F("[SYS] State now: "));
Serial.println(state);
}
void savePhone(String phone) {
writeStringToEEPROM(eeprom_addr_phone, phone);
delay(100);
Serial.print(F("[SYS] Phone now: "));
Serial.println(phone);
}
void savePin(String pin) {
writeStringToEEPROM(eeprom_addr_pin, pin);
delay(100);
Serial.print(F("[SYS] Pin now: "));
Serial.println(pin);
}
int writeStringToEEPROM(int addrOffset, const String &strToWrite) {
byte len = strToWrite.length();
EEPROM.write(addrOffset, len);
for (int i = 0; i < len; i++) {
EEPROM.write(addrOffset + 1 + i, strToWrite[i]);
}
return addrOffset + 1 + len;
}
int readStringFromEEPROM(int addrOffset, String *strToRead) {
int newStrLen = EEPROM.read(addrOffset);
char data[newStrLen + 1];
for (int i = 0; i < newStrLen; i++) {
data[i] = EEPROM.read(addrOffset + 1 + i);
}
data[newStrLen] = '\0';
*strToRead = String(data);
return addrOffset + 1 + newStrLen;
}