Popovici Sebi
Popovici Sebi

Reputation: 258

How to use global variables on a state machine

I made this state machine :

 enum states { STATE_ENTRY, STATE_....} current_state;
 enum events { EVENT_OK, EVENT_FAIL,EVENT_REPEAT, MAX_EVENTS } event;
 void (*const state_table [MAX_STATES][MAX_EVENTS]) (void) = {
   { action_entry , action_entry_fail , action_entry_repeat }, /* 
                                                  procedures for state 1 */
  ......}

void main (void){
   event = get_new_event (); /* get the next event to process */
   if (((event >= 0) && (event < MAX_EVENTS))
   && ((current_state >= 0) && (current_state < MAX_STATES))) {
      state_table [current_state][event] (); /* call the action procedure */
      printf("OK 0");
   } else {
      /* invalid event/state - handle appropriately */
         }
}

When I modify a global variable in one state the global variable remain the same , and I need that variable in all the states . Do you now what could be the problem ? My Global variable is this structure:

  #if (CPU_TYPE == CPU_TYPE_32)
     typedef uint32_t word;
     #define word_length 32
     typedef struct BigNumber {
     word words[64];
    } BigNumber;
   #elif (CPU_TYPE == CPU_TYPE_16)
    typedef uint16_t word;
    #define word_length 16
    typedef struct BigNumber {
    word words[128];
    } BigNumber;
   #else
     #error Unsupported CPU_TYPE
  #endif
  BigNumber number1 , number2;

 Here is how I modify:
 //iterator is a number from where I start to modify,
 //I already modified on the same way up to the iterator
 for(i=iterator+1;i<32;i++){
     nr_rand1=661;
     nr_rand2=1601;
     nr_rand3=1873;
     number2.words[i]=(nr_rand1<<21) | (nr_rand2<<11) | (nr_rand3);
  }

Upvotes: 0

Views: 1842

Answers (3)

4386427
4386427

Reputation: 44339

This is not an answer - rather it is a comment. But it is too big to fit the comment field so I post it here for now.

The code posted in the question is not sufficient to find the root cause. You need to post a minimal but complete example that shows the problem.

Something like:

#include<stdio.h>
#include<stdlib.h>
#include <stdint.h>

typedef uint32_t word;
#define word_length 32
typedef struct BigNumber {
  word words[4];
} BigNumber;

BigNumber number2;

enum states { STATE_0, STATE_1} current_state;
enum events { EVENT_A, EVENT_B } event;

void f1(void)
{
  int i;
  current_state = STATE_1;
  for (i=0; i<4; ++i) number2.words[i] = i;
}

void f2(void)
{
  int i;
  current_state = STATE_0;
  for (i=0; i<4; ++i) number2.words[i] = 42 + i*i;
}

void (*const state_table [2][2]) (void) =
{
    { f1 , f1 },
    { f2 , f2 }
};


int main (void){
  current_state = STATE_0;

  event = EVENT_A;
  state_table [current_state][event] (); /* call the action procedure */
  printf("%u %u %u %u\n", number2.words[0], number2.words[1], number2.words[2], number2.words[3]);

  event = EVENT_B;
  state_table [current_state][event] (); /* call the action procedure */
  printf("%u %u %u %u\n", number2.words[0], number2.words[1], number2.words[2], number2.words[3]);

  return 0;
}

The above can be considered minimal and complete. Now update this code with a few of your own functions and post that as the question (if it still fails).

My code doesn't fail.

Output:

0 1 2 3
42 43 46 51

Upvotes: 1

Remo.D
Remo.D

Reputation: 16522

Regarding the code that changese number2:

for(i=iterator+1;i<32;i){
    nr_rand1=661;
    nr_rand2=1601;
    nr_rand3=1873;
    number2.words[i]=(nr_rand1<<21) | (nr_rand2<<11) | (nr_rand3);
}

I can't fail to note that:

  • i is never incremented, so just one element of the array is changed (iterator+1) over an infinite loop;
  • even if i would be incremented, only the a portion of the words array it's changed depending on the value of iterator (but this might be the intended behaviour).
  • unless iterator can be -1, the element words[0] is never changed (again this could be the intended behaviour).

I would check if this is really what you intended to do.

If you're sure that it's just a visibility problem (since you said that when you declare it as local it worked as expected), the only other thing that I can think of is that you have the functions in one file and the main (or where you do your checks) in another.

Then you include the same .h header in both files and you end up (due to the linker you're using) with two different number2 because you did not declare it as extern in one of the two files. Your compiler (or, better, the linker) should have (at least) warned you about this, did you check the compilation messages?

Upvotes: 2

Remo.D
Remo.D

Reputation: 16522

This is just in case you may want to change your approach for defining the FSM. I'll show you with an example; say you have the following FSM:

enter image description here

You may represent it as:

void function process() {
   fsm {
     fsmSTATE(S) {
       /* do your entry actions heare */
       event = getevent();
       /* do you actions here */
       if (event.char == 'a') fsmGOTO(A); 
       else fsmGOTO(E);
     }

     fsmSTATE(A) {
       event = getevent();
       if (event.char == 'b' || event.char == 'B') fsmGOTO(B); 
       else fsmGOTO(E);
     }

     fsmSTATE(B) {
       event = getevent();
       if (event.char == 'a' ) fsmGOTO(A); 
       else fsmGOTO(E);
     }
     fsmSTATE(E) {
       /* done with the FSM. Bye bye! */
     }
   }
}

I do claim (but I believe someone will disagree) that this is simpler, much more readable and directly conveys the structure of the FSM than using a table. Even if I didn't put the image, drawing the FSM diagram would be rather easy.

To get this you just have to define the fsmXXX stuff as follows:

#define fsm            
#define fsmGOTO(x)    goto fsm_state_##x
#define fsmSTATE(x)   fsm_state_##x :

Upvotes: 2

Related Questions