state machine help

i need to make a function to stop, jumpTo and disableTimer,. I tried to make them already but the disable timer is not working. I cant tell if there are any check to see if a timer is enabled before turning on the outputs. if i set a Timer[Number].status to 0 it breaks the whole program. what do i need to do in order to make these 3 function work properly?

 byte jumpToTimer(int newStep) {
    digitalWrite(pins[currentStep], HIGH);
    clrFlags(currentStep, tiOnPhase);
    clrFlags(currentStep, tiRunning);
    currentStep = newStep ;
    setNewState(tsCheckHighPhase);
    setFlags(currentStep, tiRunning);
  }

  byte StopTimer() {
    if (digitalRead(pins[currentStep]) == LOW) {
      digitalWrite(pins[currentStep], HIGH);
      clrFlags(currentStep, tiOnPhase);
    }
  }
  byte disableTimer(int timerNumber) {
    clrFlags(timerNumber, tiOnPhase);
    clrFlags(timerNumber, tiEnabled);
    Timers[timerNumber].status = 0;

    if (digitalRead(pins[timerNumber]) == LOW) {
      digitalWrite(pins[timerNumber], HIGH); //turn it off

    }

  }
  void process() {
   
    if (runTimer) {
      now = millis();
      switch (timerState) {
        case tsPowerUp:
          stateDuration = startupDelay;
          timeBase = now;
          setNewState(tsStartUpWait);
          break;
        case tsStartUpWait:
          if (now - timeBase >= stateDuration) {
            currentStep = 0;
            setNewState(tsCheckStep);
          }
          break;
        case tsCheckStep:
          if (noValidStep(currentStep)) {
            setNewState(tsNoTasks);
          } else {
            setFlags(currentStep, tiRunning);
            setNewState(tsCheckHighPhase);
          }
          break;
        case tsCheckHighPhase:
          if (Timers[currentStep].onTime) {
            setFlags(currentStep, tiOnPhase);
            timeBase = now;
            stateDuration = Timers[currentStep].onTime * conversionFactor;
            digitalWrite(pins[currentStep], LOW);
            setNewState(tsExecHighPhase);
          } else  {
            setNewState(tsCheckLowPhase);
          }
          break;
        case tsExecHighPhase:
          if (now - timeBase >= stateDuration) {
            digitalWrite(pins[currentStep], HIGH);
            clrFlags(currentStep, tiOnPhase);
            setNewState(tsCheckLowPhase);
          }
          break;
        case tsCheckLowPhase:
          if ((Timers[currentStep].status & tiEnabled) && Timers[currentStep].offTime) {
            timeBase = now;
            stateDuration = Timers[currentStep].offTime * conversionFactor;
            setNewState(tsExecLowPhase);
          } else  {
          
            setNewState(tsNextStep);
          }
          break;
        case tsExecLowPhase:
          if (now - timeBase >= stateDuration) {
            setNewState(tsNextStep);
          }
          break;
        case tsNextStep:
         Serial.print(currentStep);
          clrFlags(currentStep, tiRunning);
          currentStep++;
          setNewState(tsCheckStep);
          break;
        case tsNoTasks:
          if (!noValidStep(currentStep)) {
            setNewState(tsCheckHighPhase);
          }
          break;
        default:
          Serial.print(F("bad state reached "));
          Serial.println(timerState);
          runTimer = false;
      }
    }
    if (announce.checkTimeout()) {
      writeTo('*', this, sizeof(TimerInfos), true);
      Serial.print(F(" at>  "));
      disp();
      incId();
      clrUpdated();
    }
  }
};

i think jumpTo and stopTimer work but disable is not. and im not sure if i made any of them right.

For example i want to disable Timer[0] while its running. it should turn off the output and continue and start Timer[1]. or i might disable Timer[3] while some other timer is on and itnot break the state machine. the timer operate in order 1,2,3,4 and repeat forever. Unless i disable timer 2 it should run 1,3,4 or if i disable timer 4 1,2,3

Sorry i though i attached the whole file,

packetDefinitions.h (25.3 KB)

Hi, i tried to simplify a short version of the state machine. Will someone please tell me how to modify the states and make a check to make sure a timer is enabled status before turning on output. if someone could write me a function to disable a timer it would be really helpful. When all outputs are enabled this state machine would run the timers in a loop in order t1on/off-t2on/off-t3on/off-t4on/off and repeat . I need to disable a timer for example if i disable timer 4 the order would be t1on then off t2on then off -t3on then off and repeat. or if i disabled timers 2,3,4 it would just repeat timer 1. Im sure you get the point. Here is the shortest version of it i could make. Please help thanks.

enum TiStates {
  tiEnabled = 0x80,
  tiRunning = 0x40,
  tiOnPhase = 0x20,
  tiUpdated = 0x10,
  tiSetable = tiEnabled + tiRunning + tiOnPhase,
  tiTriggerUpdate = tiEnabled + tiRunning + tiOnPhase,
};

void setup() {
 Serial.begin(115200);

}

void loop() {
  unsigned long now = millis()
  ;
  struct aTimer {
  byte status;
  uint16_t onTime;
  uint16_t offTime;
  aTimer(uint16_t onTime, uint16_t offTime) : status(tiEnabled), onTime(onTime), offTime(offTime) {}
  aTimer() : status(tiEnabled), onTime(5), offTime(5) {}

  bool executable() {
    return (status & tiEnabled) && (onTime || offTime);
  }
};

struct TimerInfos {
          aTimer Timers[4];
    //TimerInfos (byte from)    {}
    TimerInfos (byte from) :  Timers{  aTimer(), aTimer(), aTimer(), aTimer()  } {}
  byte makeStepNumberValid(byte& curr) {
      if (curr >= sizeof(Timers) / sizeof(Timers[0])) {
        curr = 0;
      }
      return curr;
  }
    byte nextStep(byte& curr) {
      curr++;
      return makeStepNumberValid(curr);
    }
    bool noValidStep(byte& curr) {
      makeStepNumberValid(curr);
      for (auto& t : Timers) {
        if (t.executable()) {
          return false;
        }
        nextStep(curr);
      }
      return true;
    }
    
    bool setFlags(byte timerNumber, byte flags) {
      byte previous = Timers[timerNumber].status;
      Timers[timerNumber].status |= flags & tiSetable;
      return changedFlags(timerNumber, previous);
    }
    bool clrFlags(byte timerNumber, byte flags) {
      byte previous = Timers[timerNumber].status;
      Timers[timerNumber].status &= ~(flags & tiSetable);
      return changedFlags(timerNumber, previous);
    }
   
    void clrAllFlagsRaw(byte flag) {
      for (auto& t : Timers) {
        t.status &= ~flag;
      }
    }
    void clrAllFlags(byte flag) {
      for (byte i = 0; i < sizeof(Timers) / sizeof(Timers[0]); i++) {
        clrFlags(i, flag);
      }
    }
   
  protected:
    bool changedFlags(byte timerNumber, byte previous) {
      return adjustChangedFlag(timerNumber, (Timers[timerNumber].status ^ previous) & tiTriggerUpdate);
    }
    bool changedOn(byte timerNumber, uint16_t previous) {
      return adjustChangedFlag(timerNumber, Timers[timerNumber].onTime != previous);
    }
    bool changedOff(byte timerNumber, uint16_t previous) {
      return adjustChangedFlag(timerNumber, Timers[timerNumber].offTime != previous);
    }
    bool adjustChangedFlag(byte timerNumber, bool different) {
      if (different) {
        Timers[timerNumber].status |= tiUpdated;
      }
      return different;
    }
    
};

enum {
  tsPowerUp,
  tsStartUpWait,
  tsCheckStep,
  tsCheckHighPhase,
  tsExecHighPhase,
  tsCheckLowPhase,
  tsExecLowPhase,
  tsNextStep,
  tsNoTasks,
};

const uint32_t conversionFactor = 1000;

struct Sequencer : public TimerInfos {
  uint32_t stateDuration;
  uint16_t progressDuration;
  uint32_t timeBase;
  uint32_t timeProgress;
  bool runTimer;
  bool showStateTransitions;
  byte timerState;
  byte currentStep;
  byte pins[4];
  const uint16_t startupDelay;
  Sequencer(byte node, byte p1, byte p2, byte p3, byte p4) : TimerInfos(node),
    stateDuration(0), progressDuration(0), timeBase(0), timeProgress(0),
    runTimer(false), showStateTransitions(false), timerState(tsPowerUp), currentStep(0),
    pins{ p1, p2, p3, p4}, startupDelay(5000) {}
  void begin() {
    for (byte i = 0; i < sizeof(pins); i++) {
      digitalWrite(pins[i], HIGH);
      pinMode(pins[i], OUTPUT);
      digitalWrite(pins[i], HIGH);
    }
  }
  byte setNewState(byte newState) {
    timerState = newState;
    return timerState;
  }

  void process() {
   
     if (runTimer) {
      switch (timerState) {
        case tsPowerUp:
          stateDuration = startupDelay;
          timeBase = millis();
          setNewState(tsStartUpWait);
          break;
        case tsStartUpWait:
          if (millis() - timeBase >= stateDuration) {
            currentStep = 0;
            setNewState(tsCheckStep);
          }
          break;
        case tsCheckStep:
          if (noValidStep(currentStep)) {
            setNewState(tsNoTasks); //1
          } else {
            setFlags(currentStep, tiRunning);
            setNewState(tsCheckHighPhase);
          }
          break;
        case tsCheckHighPhase:
          if (Timers[currentStep].onTime) { //3
            setFlags(currentStep, tiOnPhase);
            timeBase = millis();
            stateDuration = Timers[currentStep].onTime * conversionFactor;
            digitalWrite(pins[currentStep], LOW);
            setNewState(tsExecHighPhase); //4
          } else  {
            setNewState(tsCheckLowPhase);
          }
          break;
        case tsExecHighPhase: 
          if (millis() - timeBase >= stateDuration) { //after timer
            digitalWrite(pins[currentStep], HIGH);
            clrFlags(currentStep, tiOnPhase);
            setNewState(tsCheckLowPhase); //5
          }
          break;
        case tsCheckLowPhase:
          if ((Timers[currentStep].status & tiEnabled) && Timers[currentStep].offTime) {
            timeBase = millis;
            stateDuration = Timers[currentStep].offTime * conversionFactor;
            setNewState(tsExecLowPhase); //6
          } else  {
          
            setNewState(tsNextStep);
          }
          break;
        case tsExecLowPhase:
          if (millis() - timeBase >= stateDuration) {
            setNewState(tsNextStep); //7
          }
          break;
        case tsNextStep:
         Serial.print(currentStep);
          clrFlags(currentStep, tiRunning);
          currentStep++;
          setNewState(tsCheckStep); //8
          break;
        case tsNoTasks:
          if (!noValidStep(currentStep)) {
            setNewState(tsCheckHighPhase); //2
          }
          break;
        default:
          Serial.print(F("bad state reached "));
          Serial.println(timerState);
          runTimer = false;
      }
    }
 
  }
};
}

look like a bit much. you should be able to set up your situation with arrays to represent the timers and a simple index number that keeps track of what timer you are on.

here is a simple example to loop through timers.

if you let your pin changes happen in accordance with the timers instead of trying to resign your pins in your functions or button pushes then things will be much easier for you and stay more organized.

im not sure what you are trying to do with your pins but im giving you an example that has one different pin that stays on when each different timer is going.

unsigned long previousMillis = 0;
const long interval = 1000;
byte last;
byte current ;
int timers [4]; 
bool disabled [4];

int times [4]={10,2,50,8};//<- default seconds for each timer 
int pins [4]={2,3,4,5};//<- pins that are enabled during each timer


void setup() {
 

}
void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
   byte foundoff = 0;
   if(timers[current]>0){timers[current]--;}else{
     
     //timer expired .. move to next
    current++; if(current>3){current=0;}
     
     // skip over disabled timers
  
     while(disabled[current]){foundoff++;
        current++; if(current>3){current=0;}
        if(foundoff>3){Serial.print("oops... all timers disabled"); break;}
      }
      
    //reset the new timer
    timers[current]=times[current];
    }
    
  //check for change
if(last!=current){last=current;
Serial.println("changed:"+String(current));
}
  // write to corresponding pin
    byte i = 4;
    while(i>0){i--;
    if(i==current&&foundoff<4){
      // write pins[current] high here
      }else{
          // write pins[i] low here
        }
    }
    
    }}

after this everything else should be simple

// jump to  timer #2
current = 2;  timers[current]=times[current];
// disable timer #2
disabled[2]=true;
//skip to next enabled timer
timers[current]=0;

this code reacts every second. if you wanted a more instant responce
you would also say previousMillis=0;

hopefully this helps

taterking:
look like a bit much. you should be able to set up your situation with arrays to represent the timers and a simple index number that keeps track of what timer you are on.

here is a simple example to loop through timers.
im not sure what you are trying to do with your pins but im giving you an example that has one different pin that stays on when each different timer is going.

unsigned long previousMillis = 0;

const long interval = 1000;

byte current ;
int timers [4];
bool disabled [4];

int times [4]={10,2,50,8};//<- default seconds for each timer
int pins [4]={2,3,4,5};//<- pins that are enabled during each timer

void setup() {

}
void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
  byte foundoff = 0;
  if(timers[current]>0){timers[current]–;}else{
   
    //timer expired … move to next
    current++; if(current>3){current=0;}
   
    // skip over disabled timers
 
    while(disabled[current]){foundoff++;
        current++; if(current>3){current=0;}
        if(foundoff>3){Serial.print(“oops… all timers disabled”); break;}
      }
     
    //reset the new timer
    timers[current]=times[current];
    }
   
    // write to corresponding pin
    byte i = 4;
    while(i>0){i–;
    if(i==current&&foundoff<4){
      // write pins[current] high here
      }else{
          // write pins[i] low here
        }
    }
   
    }}





after this everything else should be simple



// jump to  timer #2
current = 2;  timers[current]=times[current];
// disable timer #2
disabled[2]=true;
//skip to next enabled timer
timers[current]=0;




this code reacts every second. if you wanted a more instant response 
you would also say previousMillis=0; 

hopefully this helps

that is a good example of a short way to do this. i would really like to be able to use the code i posted. I am pretty new to c++ and that structure i posted is part a much larger program. I have been trying to figure out how to disable a timer in this state machine for quite a while now. every attempt i make causes then order to become un-synchronized or freeze.

Any time i try to change a flag the timers become out of order and turning on the wrong output. I dont know what to do

byte disableTimer(int timerNumber) {
digitalWrite(pins[timerNumber], HIGH);
setNewState(tsCheckLowPhase);
// Timers[timerNumber].status = 0;
//clrFlags(timerNumber, tiRunning);
//clrFlags(timerNumber, tiEnabled);
}

Is my question not clear enough? Why when i set Timers[currentStep].status to 0 to disable a timer the whole sequence comes out of order? I dont know what happening in this piece of code but this is the main part i dont understand. i think its basically searching for a flag and returns false if t.executable finds and bits set? I dont know but i have been stuck here a while.

    bool noValidStep(byte& curr) {
      makeStepNumberValid(curr);
      for (auto& t : Timers) {
        if (t.executable()) {
          return false;
        }
        nextStep(curr);
      }
      return true;
    }

This is a mistake:

              timeBase = millis;

You meant:

              timeBase = millis();

johnwasser:
This is a mistake:

              timeBase = millis;

You meant:

              timeBase = millis();

i figured out this problem already. that was in my example only i checked my code thanks for the warning

notsolowki:
Is my question not clear enough? Why when i set Timers[currentStep].status to 0 to disable a timer the whole sequence comes out of order? I dont know what happening in this piece of code but this is the main part i dont understand. i think its basically searching for a flag and returns false if t.executable finds and bits set? I dont know but i have been stuck here a while.

You seem to not understand this code very well, as evidenced by your inability to clearly articulate the problem. Did you write it? If so, how did you get to such a large and complex program without understanding how all the individual pieces work?