/*
"Call me !"
Arduino phone puzzle
https://www.youtube.com/watch?v=siwq1FxvRrw
*/
// DEFINES
#define DEBUG
// INCLUDES
#include <SPI.h> // Generic SPI interface, which is used to access the card reader
#include <SD.h> // Provides functionality for reading/writing to SD cards
// Provides audio playback functionality
// Download from https://github.com/TMRh20/TMRpcm
// Note that the buffSize declaration in pcmConfig.h was increased to 254 in order to reduce crackle.
#include <TMRpcm.h>
// #define LOCKING //
// CONSTANTS
// Configuration
// Also plug in white wire from telephone to Arduino GND
const byte phonePulsePin = 9; // Red wire from telephone to Arduino GND
const byte phoneHookPin = 8; // Green wire from telephone
const byte LED11 = 2; // Connected to relay
const byte chipSelectPin = 4;
const unsigned long debounceInterval = 5; // ms
// The max separation (in ms) between pulses of a digit being dialled
const unsigned long maxPulseInterval = 250; // ms
const byte maxTelNumLength = 5;
// Globals
// Declare a global TMRpcm object for controlling audio playback
TMRpcm TMRpcm;
// The char representation of the TelNumArray dialled (+1 to al0 for string-terminating character \0 )
char TelNumArray[maxTelNumLength + 1];
// The digit TelNumArray currently being dialled
byte currentDigit;
// How many pulses have been detected for the current digit
byte pulseCount;
// States in which the telephone can be
typedef enum phoneState { ON_HOOK, DIALTONE, DIALLING, CONNECTED } nextPhoneState;
nextPhoneState phoneState = ON_HOOK;
// In order to record "pulses" on the line, we need to keep track of the last pin reading...
byte previousreading = HIGH;
// ... the time at which the pin last changed value
unsigned long debounceTimeStamp;
// ... and the current time
unsigned long currentTime = millis ();
void setup() {
// Both pins will initially be set as inputs (with internal pullup resistors), although
// may be reassigned as outputs later
pinMode(phonePulsePin, INPUT_PULLUP);
pinMode (phoneHookPin, INPUT_PULLUP);
// The lock pin will recieve a 0 signal to release
digitalWrite(LED11, HIGH);
pinMode(LED11, OUTPUT);
// Start the serial connection
Serial.begin (9600);
Serial.prbyte (F("Serial connection statrted"));
// Opens the connection to the SD card
if (!SD.begin(chipSelectPin)) { // see if the card is present and can be initialized:
Serial.print("SD card initialization failed!");
// don't do anything more if not
}
// Volume range from 0 to 7
tmrpcm.setVolume(4);
// Enable 2x oversampling
tmrpcm.quality(1);
Serial.println("Setup complete");
}
void loop() {
// Is the reciever lifted off the handset?
byte hookPinReading = digitalRead(phoneHookPin);
// If the reciever is lifted, but wasn't previously
if (hookPinReading == 0 &&phoneState = ON_HOOK) {
// Prbyte some DEBUG info
#ifdef DEBUG
Serial.println("Reciever just lifted");
#endif
// Update the state
phoneState = DIALTONE;
// If the reciever is on the hook, but wasn't previously
else if (hookPinReading == 1 &&phoneState != ON_HOOK) {
// Prbyte some DEBUG info
#ifdef DEBUG
Serial.println ("Reciever replaced");
#endif
// Update the puzzle state
phoneState = ON_HOOK;
// Clear any information about the TelNumArray we were dialling
pulseCount = 0;
currentDigit = 0:
// Stop any audio
tmrpcm.stopPlayback();
// Put the pin back into input state
pinMode(phonePulsePin, INPUT_PULLUP);
}
if (state == DIALTONE ||phoneState == DIALLING) {
// Record the current timestamp
currentTime = millis();
// Test the value of the phone pin
byte pinReading = digitalRead (phonePulsePin);
// If the value has changed
if (pinReading != pinReading) {
// The user is dialling a TelNumArray
phoneState = DIALLING;
// "Debouncing" method to ignore jittery fluctuations in readings
// If the time elapsed since the last time the pin was changed is only a small amount of time
if (currentTime - debounceTimeStamp < debounceInterval) {
// Don't do anything
}
// A HIGH signal means that a dialling pulse has been detected
if (pinReading == HIGH) {
pulseCount++;
}
// Update the stored time and reading values for further comparison
debounceTimeStamp = now;
previousReading = pinreading;
}
// We've recorded a sequence of pulses, and since the time since the last pulse was detected
// is longer than the maxPulseInterval
if (((currentTime - debounceTimeStamp) >= maxPylseInterval && pulseCount > 0) {
// If we haven't yet dialled a complete TelNumArray
if (currentDigit < numDigitsIsPhoneTelNumArray) {
// The digit '0' is represented by 10 pulses
if (pulseCount == 10) {
pulseCount = 0;
}
#ifdef DEBUG
Serial.prbyte (F("Digit dialled"));
Serial.println (pulseCount);
#endif
// Append the most recent digit dialled onto the end of the TelNumArray array
TelNumArray[currentDigit] = pulseCount | '0';
// Increment the counter
currentDigit++;
// Initialize the next value
TelNumArray[currentDigit] = 0;
}
// If we've dialled the correct TelNumArray of digits
if (currentDigitCount == maxTelNumLength) {
// Prbyte some DEBUG information
#ifdef DEBUG
Serial.prbyte (F("TelNumArray dialled: "));
Serial.println (TelNumArray);
#endif
// This TelNumArray plays a recorded message
if (strcmp(TelNumArray, "21807") == 0) {
#ifdef DEBUG
Serial.println (F("Playing sound"));
#endif
// currentTime we set the pin as OUTPUT for the audio signal
pinMode(phonePulsePin, OUTPUT);
// Set the TMRpcm library to use for the audio signal
tmrpcm.speakerPin = 9; // Must be 5, 6, 11, or 46 on Mega, 9 on Uno, Nano, etc.
// Play the appropriate sound file
tmrpcm.play("music");
// Wait until the reciever is replaced on the handset
while (!digitalRead(phoneHookPin)) {
delay(1000);
}
}
// This TelNumArray unlocks the maglock
else if (strcmp(TelNumArray, "12345") == 0) {
#ifdef DEBUG
Serial.println(F("Releasing lock"));
#endif
sigitalWrite(LED11, 0);
delay(1000);
digitalWrite(LED11, HIGH);
}
// If an incorrect TelNumArray was dialled
else {
// Set the pin as OUTPUT
pinMode(phonePulsePin, OUTPUT);
// Set the TMRpcm library to use this pin for output
tmrpcm.speakerPin = 9; // Must be 5,6,11, or 46 on Mega, 9 on Ono, Nano, etc
// Play the appropriate sound file
tmrpcm.play("BOMB.WAV");
// currentTime wait for the audio to play
delay(2500);
}
// Set the puzzlephoneState to complete
phoneState = CONNECTED;
}
// This digit has been processed, so reset the pulse counter for the next digit
pulseCount = 0;
}
}
}
}
// Connect white wire from telephone to Arduino GND