const byte triggerInputPin  = 3;
const byte triggerIsActive = LOW; // LOW o HIGH

const byte PinToSwitch     = 12;
const byte OutPutOn  = HIGH;
// the attention-mark ! is the not-operator which inverts the value
// !true = false  !false = true     !HIGH = LOW    !LOW = HIGH
const byte OutPutOff = !OutPutOn; 

// set InitialWaitTime to 0 if you don't want a delay between triggering and switching output
unsigned long InitialWaitTime = 050; // was 2000, 500, 50
unsigned long ActiveTime = 1000; // was 3000
unsigned long LockedTime = 100; // was 10000, 5000, 500

unsigned long MonoFlopTimer; // variable used for non-blocking timing

// constants of the state-machine
const byte sm_Idling      = 0;
const byte sm_InitialWait = 1;
const byte sm_Activated   = 2;
const byte sm_Locked      = 3;

byte MonoFlopState = sm_Idling; // state-variable of the state-machine


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

unsigned long MyTestTimer = 0;                   // Timer-variables MUST be of type unsigned long
const byte    OnBoard_LED = 13;


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
  PrintFileNameDateTime();
  pinMode(triggerInputPin,INPUT_PULLUP); // INPUT_PULLUP
  digitalWrite(PinToSwitch,OutPutOff);
  pinMode(PinToSwitch,OUTPUT);
}


void MonoFlopStateMachine() {

  switch (MonoFlopState) {

    case sm_Idling:
      // check if trigger-input reads triggering signal
      if (digitalRead(triggerInputPin) == triggerIsActive) {
        MonoFlopTimer = millis();       // make snapshot of time
        MonoFlopState = sm_InitialWait; // set next state of state-machine
        Serial.println( F("trigger-signal detected start inital wait") );
      }
      break; // IMMIDIATELY jump down to END OF SWITCH

    case sm_InitialWait:
      // wait until initial waittime has passed by
      if ( TimePeriodIsOver(MonoFlopTimer,InitialWaitTime) ) {
        // if waittime HAS passed by
        MonoFlopTimer = millis();           // make new snapshot of time
        digitalWrite(PinToSwitch,OutPutOn); // switch IO-Pin to activated state
        MonoFlopState = sm_Activated;       // set next state of state-machine
        Serial.println( F("InitialWaitTime is over switching output to ACTIVE") );
      }
      break; // IMMIDIATELY jump down to END OF SWITCH

    case sm_Activated:
      // check if time the IO-pin shall be active is over
      if ( TimePeriodIsOver(MonoFlopTimer,ActiveTime) ){
        // if activetime of IO-pin IS over
        MonoFlopTimer = millis();             // make new snapshot of time
        digitalWrite(PinToSwitch,OutPutOff);  // switch IO-pin to DE-activated state
        MonoFlopState = sm_Locked;            // set next state of state-machine
        Serial.println( F("Activetime is over switching output to IN-active") );
        Serial.println( F("and starting locktime") );
      }
      break; // IMMIDIATELY jump down to END OF SWITCH

    case sm_Locked:
      // check if time the logic shall be locked against too early re-triggering is over
      if ( TimePeriodIsOver(MonoFlopTimer,LockedTime) ){
        // if locked time IS over
        Serial.println( F("locktime is over change state to idling") );
        MonoFlopState = sm_Idling; // set state-machine to idle-mode
      }
      break; // IMMIDIATELY jump down to END OF SWITCH
  } // END OF SWITCH
}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 250);

  // run down code of state-machine over and over again
  // all the logic for reading in sensor-signal and switching output ON/OFF 
  // is inside the function
  MonoFlopStateMachine(); 
}