Return to the beggining of the loop

I have a rotary dialing phone, and Im using an arduino to "read" the dialed number and verifies if it matches the sequence chosen previously. I already find and modify a code that does all of that, but now I want to add a button to indicate when a new phone number is being dialed. The problem is that a cant think of a way to when they are in the midle of dialing, like in the 3rd of a 7-number phone number, they can just press the button and reset.
This is my current code:

/*

   Telephone Dial Interpreter and Game
   LED - pin 13
   Dialer - between pin 2 and ground assuming dialer is NC (normally closed)
   Note: currently written to support a NC dialer. 
   Note: currently supports a dialer with a dialed 0 giving 1 pulse
   Note: alter magicNumberSize && magicNumber to suit.
   You may have to experiment with the timings depending on the dialer.
   
*/

const unsigned long dialingSessionTimeOut = 10000UL ;  // 10 seconds of no activity
const unsigned long singleDigitDialTimeOut = 1000UL ;   // 2000 mS of no activity
const unsigned long contactDebounce = 50UL ;
const unsigned long successPhaseDuration = 10000UL ;  // how long LED (relay) etc. is activated  if success.


const int magicNumberSize = 7 ;  // number of digits to be dialed
const int magicNumber[ magicNumberSize ] = { 1, 2, 3, 4, 5, 6, 7 } ;  // digit sequence to be dialed

const byte ledPin = 13 ;
const byte dialPin = 2 ;
const byte buttonPin=4;

bool inDialingSession = false ;
bool inSingleDigitDial = false ;
bool inSuccessPhase = false ;

unsigned long pulseReceivedAtMs = 0 ;
unsigned long successPhaseStartedAtMs = 0 ;

int numberOfPulsesReceivedForCurrentDigit = 0 ;
int currentDigitIndex = 0 ;
bool dialPinLast;
bool dialPinCurrent ;
int collectedDialedDigit[ magicNumberSize ] ;   // here are our results


void setup() {
  Serial.begin( 9600 ) ;
  pinMode( ledPin, OUTPUT ) ;
  pinMode( dialPin, INPUT_PULLUP ) ;  // external pullup/down depending on dial  NC = pullup, NO = pulldown
  dialPinLast = digitalRead( dialPin ) ;
  Serial.println( "Dialer Game Starting. . . " ) ;
}

void loop() {

  if ( inSuccessPhase ) {
     if ( millis() -  successPhaseStartedAtMs < successPhaseDuration ) {
        digitalWrite( ledPin, HIGH ) ;
        // put code to hanle unlocking / relay etc. here
     }
     else {
         digitalWrite( ledPin, LOW ) ;
         inSuccessPhase = false ;
         Serial.println( "End of SUCCESS period" ) ;
     }
  }

  if ( inDialingSession ) digitalWrite( ledPin, digitalRead( dialPin ) ) ;  // flash led with dial pulses

  if ( inDialingSession && millis() - pulseReceivedAtMs > dialingSessionTimeOut ) {
    // abandoned session - cleanup
    inDialingSession = false ;
    inSingleDigitDial = false ;
    numberOfPulsesReceivedForCurrentDigit = 0 ;
    Serial.println( "Dialing Session Timeout reached" ) ;
  }

  if ( inSingleDigitDial && millis() - pulseReceivedAtMs > singleDigitDialTimeOut ) {
    // dialling of current Digit has ended

    // Only one line below should be active depending on the type of dial uses:

    // Case 1:  a dialed 0 gives 1 pulse, then subtract 1 for all digits
    //numberOfPulsesReceivedForCurrentDigit -- ;

    // Case 2:  a dialed 0 delivers 10 pulses
    if (numberOfPulsesReceivedForCurrentDigit == 10 ){
      numberOfPulsesReceivedForCurrentDigit = 0 ;
    }

    Serial.println () ;
    Serial.print ("Digit " ) ;
    Serial.print ( currentDigitIndex ) ;
    Serial.print ("; pulses received= " ) ;
    Serial.println ( numberOfPulsesReceivedForCurrentDigit ) ;

    collectedDialedDigit[ currentDigitIndex ] = numberOfPulsesReceivedForCurrentDigit ;
    if ( currentDigitIndex + 1 == magicNumberSize ) {
      // we have all our digits 0..6 so teminate session
      Serial.println ( "Terminating Current Dialing Session" ) ;
      inDialingSession = false ;

      bool success = true ;
      for ( int i = 0 ; i < magicNumberSize ; i++ ) {
        if ( magicNumber[ i ] == collectedDialedDigit[ i ] ) {
          Serial.print("digit: " ) ;
          Serial.print( i + 1) ;
          Serial.println (" matched magic number" ) ;
        }
        else {
          Serial.print("digit: " ) ;
          Serial.print( i + 1 ) ;
          Serial.println (" did NOT match magic number" ) ;
          success = false ;
        }
      }
      if (success) {
        Serial.println ("SUCCESS" ) ;
        inSuccessPhase = true ;
        successPhaseStartedAtMs = millis() ;
      }
      else {
        Serial.println ("FAILURE" ) ;
      }
      Serial.println () ;
      Serial.println () ;
      Serial.println () ;

      // check here if it was a success
    }

    inSingleDigitDial = false ;
    currentDigitIndex++ ;
  }

  dialPinCurrent = digitalRead( dialPin) ;
  if ( dialPinCurrent != dialPinLast && dialPinCurrent == HIGH && millis() - pulseReceivedAtMs > contactDebounce ) {

    if ( ! inDialingSession ) {
      Serial.println()  ;
      Serial.println()  ;
      Serial.println( "Start new dialing session") ;
      inDialingSession = true ;
      // startOfDialingSessionMs = millis() ;
      currentDigitIndex = 0 ;
      inSingleDigitDial = false ;  // force cleanup
    }
    if ( ! inSingleDigitDial ) {
      Serial.println() ;
      Serial.println( "Start new single digit") ;
      inSingleDigitDial = true ;
      numberOfPulsesReceivedForCurrentDigit = 0 ;
    }
    Serial.println ( "dial pulse received" ) ;
    pulseReceivedAtMs = millis() ;
    numberOfPulsesReceivedForCurrentDigit ++ ;
  }
  dialPinLast = dialPinCurrent ;
}

If you mean like resetting so you can start over it looks fairly simple.

Add a pushbutton for resetting. Make its pin mode INPUT_PULLUP.

At the top of your loop, see if the button is pressed. When the button is seen to be pressed, reset the handful of variables that are involved with counting and validating the digits that are rotary-dialed in.

No need to do any special handling - if you leave your fat finger on the button, it will just keep resetting, big deal.

a7

why can't you monitor a switch-hook input which enables dialing. any rotary input should be ignored when dialing is not enabled.

i don't see any while loops or delays in your code

1 Like

i think your code could be much simpler

i'm not sure, but doesn't the dialer only make switch contacts when moving clockwise. if so

each contact should increment a digit count and capture a timestamp.

a separate timer captures the digit value when a timer expires because a new contact hasn't occured.

and a (telephone) number is recognized when an appropriate # of digits is captured.

2 Likes

I think that is what the code does. Or close enough. Perhaps it could be more concise and clever, but the claim is that it works.

These look like timer\s for the various aspects of capturing a telephone number.

const unsigned long dialingSessionTimeOut = 10000UL ;  // 10 seconds of no activity
const unsigned long singleDigitDialTimeOut = 1000UL ;   // 2000 mS of no activity
const unsigned long contactDebounce = 50UL ;
const unsigned long successPhaseDuration = 10000UL ;  // how long LED (relay) etc. is 

@toinapt, this code

  if ( inDialingSession && millis() - pulseReceivedAtMs > dialingSessionTimeOut ) {
    // abandoned session - cleanup
    inDialingSession = false ;
    inSingleDigitDial = false ;
    numberOfPulsesReceivedForCurrentDigit = 0 ;
    Serial.println( "Dialing Session Timeout reached" ) ;
  }

resets for another attempt in the event of someone just ignoring going further; a button press doing the same "abandoned session - cleanup" steps seems like it might be worth trying to address the modification you are asking about. Setting those three variables sets the process back to no numbers dialed, ready and waiting, the initial conditions of the first run for the first guess.

HTH

a7

1 Like

Did you know that my father called a hammer an ‘American Screwdriver!

2 Likes

maybe i misunderstand what is needed
look this over

const byte PinSwHook  = A2;
const byte PinContact = A1;
      byte contactState;

const unsigned long MsecTimeout = 350;
      unsigned long msec0;

int  cnt;
int  idx;
bool tmr;

// -----------------------------------------------------------------------------
void
loop (void)
{
    unsigned long msec = millis ();

    if (tmr && msec - msec0 > MsecTimeout) {
        Serial.print (" ");
        Serial.print (cnt);

        if (4 <= ++idx)  {
            idx  = 0;
            Serial.println (" **");
        }

        cnt = 0;
        tmr = false;
    }

    if (LOW == digitalRead (PinSwHook))  {
        if (idx)
            Serial.println ();
        cnt = idx = 0;
        return;
    }

    byte contact = digitalRead (PinContact);
    if (contactState != contact)  {
        contactState  = contact;
        delay (20);

        if (LOW == contact)  {
            cnt++;
            msec0 = msec;
            tmr   = true;
        }
    }
}

// -----------------------------------------------------------------------------
void
setup (void)
{
    Serial.begin (9600);

    pinMode (PinSwHook,  INPUT_PULLUP);
    pinMode (PinContact, INPUT_PULLUP);
    contactState = digitalRead (PinContact);
}

OP did not write it. chatDump. OP never returns to respond to posts. Just waiting to copy/paste a finished product while everyone is tripping over another troll avatar.

On real phones you used to just push the off-hook button back down for a reset period to get a new dial tone. (If you clicked it too fast it would just dial a '1'.)

1 Like

@6v6gt wrote it:

That brings back memories. I don't remember being paid for it, though. No doubt it can be improved and I'd start with the typos in the comments but nowadays I would
tend to use an explicit finite state machine model instead of a series of flags. However, I would still try to avoid using delay() despite any suggestions to the contrary.

1 Like

Kudos to the author, @6v6gt. It looks like a fun execise; counting pulses. The "escape room" threads are enjoyable to read.

About that 100% unresponsive OP... and others of the same ilk. I would like a nice banner that says
THIS AUTHOR HAS NEVER PARTICIPATED IN ANY THREAD AFTER STARTING A TOPIC so as not to waste resources and bandwidth which could be better used for NPK enthusiasts and King Raj DFPlayer stone soup.

1 Like

Haha, mine did too.

1 Like

This may be a bit unfair. The OP appears to have opened only 2 threads, this being the second. The previous one seems to have been dominated by forum heavyweights slogging away at the issue of single letter variable names and it may all have been quite intimidating for a new user.

The forum counter is incorrect. Three topics started (see acticity). Regardless of 2 or 3, 100% non-responsive.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.