LennartHennigs/SimpleFSM

Memory allocation problem

FabrizioRomanoGenovese opened this issue · 3 comments

First of all, thank you for the great library! My problem is the following: I need to define pretty big FSMs on my ESP8266, in the order of 400-500 transitions give or take. To make things more manageable, I've added this function to the library:

void SimpleFSM::addIncremental(Transition t[], int size) {
  if ( (transitions == NULL) || (num_standard == 0) ) {
    add(t, size);
  }
  else {
    for (int i=num_standard; i < (num_standard + size); i++) {
      transitions[i] = t[(i - num_standard)];
      _addDotTransition(transitions[i]);
    }
    num_standard += size;
  }
}

The idea is simple: Now I can define different arrays of states and transitions, like so:

State r[] = {
  State("Living", living),                 // 0
  State("Kitchen", kitchen),               // 1
  State("Office", office),                 // 2
  State("Bedroom", bedroom),               // 3
  State("Bath Big", bathBig),              // 4
  State("Bath Small", bathSmall),          // 5
};

State of[] = {
  State("ofLights", lights),               // 0
  State("ofAC", airCon),                   // 1
  State("ofCurtains", curtains),           // 2
};

Transition tr[] = {
  Transition(&r[0], &r[1], btnDownPressed),
  Transition(&r[1], &r[2], btnDownPressed),
  Transition(&r[2], &r[3], btnDownPressed),
  Transition(&r[3], &r[4], btnDownPressed),
  Transition(&r[4], &r[5], btnDownPressed),

  Transition(&r[1], &r[0], btnUpPressed),
  Transition(&r[2], &r[1], btnUpPressed),
  Transition(&r[3], &r[2], btnUpPressed),
  Transition(&r[4], &r[3], btnUpPressed),
  Transition(&r[5], &r[4], btnUpPressed),
};
int num_tr = sizeof(tr) / sizeof(Transition);

Transition tof[] = {
  Transition(&r[2], &of[0], btnEnterPressed),

  Transition(&of[0], &of[1], btnDownPressed),
  Transition(&of[1], &of[2], btnDownPressed),

  Transition(&of[1], &of[0], btnUpPressed),
  Transition(&of[2], &of[1], btnUpPressed),
  
  Transition(&of[0], &r[2], btnBackPressed),
  Transition(&of[1], &r[2], btnBackPressed),
  Transition(&of[2], &r[2], btnBackPressed),
};
int num_tof = sizeof(tof) / sizeof(Transition);

and then add them separately, like so:

  fsm.add(tr, num_tr);
  fsm.addIncremental(tof, num_tof);

This is pretty much the only way I can think of to make editing of big FSMs manageable, as it allows some degree of compositionality. My problem is that the ESP8866 doesn't seem to handle this well.

  • If I add just some transitions, then everything is fine.
  • If I add a bit more (say around a total of 30), it behaves fine but at some point it crashes. I've added some Serial.print to the trigger function and I noticed that the transition output is garbled (e.g. transition.to is cut or garbage altogethher).
  • If I keep adding transitions, the ESP eventually keeps crashing into a bootloop.

This makes me think that there is some problem with the memory management. I've tried to play with malloc and realloc a bit but being a total C++ noob I've ended up only wasting time. Any idea is appreciated!

By the way, I ran some tests using sizeOf. A state should occupy 32 bytes, while a transition occupies 40. Given this, at the moment my states occupy 2400 bytes, while my transitions occupy 8040 bytes, for a total of 10440. My chip should have ~90KiB of memory for instructions, so I should be well within that limit.
Moreover, I checked https://github.com/jonblack/arduino-fsm/ to which this library is inspired: In https://github.com/jonblack/arduino-fsm/blob/master/Fsm.cpp the way to add transitions is incremental (it doesn't recurse over an array, but adds transitions one by one at user request). In particular, immediately before adding a transition, memory is reallocated by giving:

 m_transitions = (Transition*) realloc(m_transitions, (m_num_transitions + 1) * sizeof(Transition));

I tried to do the same in the function I defined in the comment above, adding the line:

transitions = (Transition*) realloc(transitions, (num_standard + size) * sizeof(Transition));

just before the for cycle. This has the only effect of putting my chip in a cycle of crashes.

Ok, solved it. Created a pull request in case someone is interested: #7

Hey Fabrizio,
thank you for your issue report and for your pull request!
Will review your code and merge it.
🙇