hierarchical state machines in c  - Page 1
Forum section: electronics / beginners

author: syntax333
author_rank: Regular Contributor
timestamp: August 26, 2020, 05:41:11 pm
content: Hi, I am new to the concept of hierarchical state machines and nested states. I am confused about state variables. Am I suppose to create new state variable for each substate (like s and s1)?In the attachment there is a pseudo code of simple state machine.Is this the way to do it? I couldn't find any resources about hierarchical state machine C implementation.

author: Renate
author_rank: Super Contributor
timestamp: August 26, 2020, 06:47:29 pm
content: Any set of FSMs could be consolidated into a single FSM.The number of total states would be at most the product of the number of the states in the individual FSMs.If the FSMs are very much independent then keeping them separate might make sense.If the FSMs are just a conceptualization then integrating might make sense.I get bored by deeply nested switches, I prefer to distill things down to a single table.I'm not sure what tools are out there to do this. So, tell me.In any case, I think that the source input is not that different from humongous switch statements.

author: tggzzz
author_rank: Super Contributor
timestamp: August 26, 2020, 07:31:31 pm
content: Quote from: Renate on August 26, 2020, 06:47:29 pmThose are two design patterns, and there are others.One, which is useful more complex and evolving FSMs that have to be maintained and extended is:each state maps onto a separate OOD classeach event maps onto a separate method implemented by the classesthe current state is a singleton instance of one of the state classessubstates are modelled by the corresponding class hierarchythe abstract superclass of all state classes contains methods for every event, with an implementation that aborts execution becauses that method should never be executedevery event is handled where appopriate in the state classeseventA is executed by invoking currentState.eventA(), and state transtions are currentState = aStateClassInstance

author: emece67
author_rank: Frequent Contributor
timestamp: August 26, 2020, 07:34:39 pm
content: .

author: syntax333
author_rank: Regular Contributor
timestamp: August 26, 2020, 07:39:35 pm
content: Quote from: Renate on August 26, 2020, 06:47:29 pmI know coding state machine into state table makes the code cleaner but compiler converts switches into jump tables which requires less clock cycles to transiton from one state to other.Quote from: tggzzz on August 26, 2020, 07:31:31 pmI am planning to use the state machine in an embedded system. I don't prefer the C++ coding approach (classes etc.) when I am coding microcontrollers.

author: emece67
author_rank: Frequent Contributor
timestamp: August 26, 2020, 07:42:45 pm
content: .

author: tggzzz
author_rank: Super Contributor
timestamp: August 26, 2020, 07:51:28 pm
content: Quote from: syntax333 on August 26, 2020, 07:39:35 pmAnd far less comprhendable and maintainable over time. I've seen such if-then-elses 10 levels deep. Truely grim!QuoteThen don't use c++! Personally my attitude is that if c++ is the answer then you he asked the wrong question.I was doing a limited form of OOP in C before c++ existed.

author: emece67
author_rank: Frequent Contributor
timestamp: August 26, 2020, 08:00:10 pm
content: .

author: Fredderic
author_rank: Regular Contributor
timestamp: August 26, 2020, 09:15:23 pm
content: C++ offers more than just OOP, though… especially the more recent additions.I'm no C++ expert, but I've been a little spoilt by D of late (not good for small architectures, unfortunately), so went and hunted out the C++ equivalents — and I've been able to use just a sprinkling of C++ quite effectively. Such things as templates, constexpr and friends, and using classes as "better structs". These features allow you to pretty much completely replace the brittle preprocessor incantations with far more readable regular code, at no cost — some of those arcane incantations hid hard to spot inefficiencies, code generators to pre-compute or convert data were often their very own nightmare, etc.And overall, then when constrained to basic C, readability rather often comes at the cost of efficiency. Honestly if using a modern C++ compiler makes your binary less readable or efficient, you're probably just using it wrong. You don'thaveto go all-out OOP just because you're using C++.

author: Renate
author_rank: Super Contributor
timestamp: August 26, 2020, 09:43:37 pm
content: The problem with switches is:Let's say that your state diagram is simple, most nodes go forward to a single node or back to themselves.You have a couple of places where a node decides to two (or more) other nodes.Well, you have a switch(state) and probably a single if (input) for each state, nice, clean.When you start having global signals what do you do?Are you going to put an if (reset) in each case?Are you going to have a bunch of if (signal) switch(state) before your major switch(state)?It can get messy. You're switching back and forth between state being the major category and input being the major category.

author: Doctorandus_P
author_rank: Super Contributor
timestamp: August 27, 2020, 12:47:51 am
content: I like to divide my code into small functions.State machines implemented with a switch tend to get pretty big.So, some time ago I experimented a bit with function pointers and it worked beutifully.The idea is that you write a function for each state, and you have a function pointer as the current state.Each of the state machine functions then either returns NULL (or a pointer to itself) if nothing changes, but if a new state is initiated, it returns a function pointer to the next state.What's left is some way to repeatedly call the function tat the function pointer points to at that moment.In C++ it's easy to put the whole state machine in a class, which wraps it up nicely, and you have easy access to private variables for complicated state machines.In C you can make a structure with meta data, and give a pointer to such a structure to each function of the statemachine.Note that each state machine function needs to have the same format of all parameters, or the compiler complains (and rightly so). Trying to circumvent this with casts seems a road to disaster.

author: Renate
author_rank: Super Contributor
timestamp: August 27, 2020, 02:25:28 am
content: Whether we are talking about switches or functions or methods or lambdas there is still the issue of what is "top level".If you have a flow that is mostly going to the next state then state as top level makes sense.OTOH, a (really poor) example where you would want it the other way would be four buttons that do a latching priority encoder.You would really want your input (the buttons) to be the top level and if there were complexities/features have checking on state be secondary.That's the point I was trying to make that in some cases these two opposing schemes don't mesh well.The advantage of tables is that you have meshed all this stuff already because state and input have already been merged into a single address space.Of course, the source definitions still have the sort of difficulties of any switch/method/function solution.

author: tggzzz
author_rank: Super Contributor
timestamp: August 27, 2020, 07:24:46 am
content: Suppose your design includes three modes of operation, each relatively complex:initialisation mode, of itself, several subsystems and several different FSMs that are not part of this designnormal mode, the bit beginners think about and which can be arbitrarily complexfailure mode, where most events are ignored until the failure has been clearedIf you use switch/if-then-else statements, good luck assuring that the implementationcontinuesto match the specification over time.Merging all that into a single table driven implementation would be possible, but it would be large!Alternatively use hierarchical specification and a matching implementation, where there are three abstract classes corresponding to each of the three modes, plus concrete subclasses for each of the "real" states.

author: MosherIV
author_rank: Super Contributor
timestamp: August 27, 2020, 07:39:29 am
content: Another handy thing to do with state machines is to use an enum for the state, the enum can be named to represent what the state means.This makes it clearer, it also helps stop invalid states because the states should only be one of the enums

author: rstofer
author_rank: Super Contributor
timestamp: August 29, 2020, 06:04:22 pm
content: There are at least two kinds of sub-state machines that I can think of. The first models a subroutine in that the parent state machine kicks the lower level machine into operation and essentially stalls until it is complete. Clearly, the two state machines can be combined. At best, this model allows the writer to create cleaner code.The second type is something like a co-routine (a thread in today's parlance). The parent FSM kicks off the co-routine and, somehow, the co-routine executes in parallel. Some time later, the parent will check to see if the dependent has finished. This could be many states later.This co-routine model would involve some kind of multi-tasking or time slicing. Each running co-routine would be eligible for a slice of time. This could be done in a superloop by checking if the co-routine should be called during this pass. The code is clean and definitely modular. Scheduling is the more difficult part. Co-operative multi-tasking, maybe even an RTOS.

author: tggzzz
author_rank: Super Contributor
timestamp: August 29, 2020, 07:52:45 pm
content: Hierarchical FSM != multiple cooperating FSMs. Hierarchy is simply a problemspecificationtool, used forconvenienceandconciseness. It is often coupled with a similar implementation. The hierarchy can be flattened to a non-hierarchical representation with no semantic change. Each event has to be processed to conclusion before the starting to process the next event.The concept of "co-routine executes in parallel" is problematic. It implies that multiple events in the same FSM are being processed simultaneously, which could lead to event E1 setting next state S1 and event E2 setting nextstate S2. That has all the problems of hardware asynchronous state machine - avoid like the plagueThat is all avoided if there are multiple cooperating FSMs, each sending events to the others.Problems with events that would otherwise take an arbitrary time to complete, require the events and states to be changed and/or use a half-sync-half-async design pattern.I've designed and implemented FSMs using all the above mechanisms, including co-routines in a very simple RTOS - cooperative scheduling (i.e. threads call yield() one way or another).

author: rstofer
author_rank: Super Contributor
timestamp: August 29, 2020, 08:40:37 pm
content: Quote from: tggzzz on August 29, 2020, 07:52:45 pmAnd yet it is done all the time in FPGAs. The main FSM kicks off another FSM that does whatever and the parent checks back later. Even a simple UART peripheral would qualify is a dependent FSM, particularly the output portion. The main FSM doesn't know or care what the child is doing as long as there is some kind of handshake to pass status/data.Asynchronous state machines are pretty much out of the question but they have been done for very long time with relays - machine control and telephone PBX systems come to mind. Relay based PBXs are one of the things I have spent some time on.

author: tggzzz
author_rank: Super Contributor
timestamp: August 29, 2020, 09:24:34 pm
content: Quote from: rstofer on August 29, 2020, 08:40:37 pmMultipleseparateFSMs connected by events are fine. Each FSM processes just one event at a time, to completion. If there are N independent FSMs, they can process up to N events in parallel.But thoseseparateFSMs arenot hierarchical.QuoteI've architected and implemented several telecom systems too. If you look at the formal standards specs, they are full ofcooperating separateFSMs, often implemented by several independent companies. The half-sync half-async design pattern is very relevant to call control. If well implemented (as I outlined earlier), instrumenting the FSM state/event trajectory is a superb way of demonstrating that the problem lies in the other company's product; blissThe same is true of computer networks (and I've implemented those too).

author: Renate
author_rank: Super Contributor
timestamp: August 29, 2020, 09:49:28 pm
content: I didn't want to totally pollute this thread, so I started a thread in Computing on generating FSM tables out of legible source:https://www.eevblog.com/forum/programming/generating-a-finite-state-machine-from-legible-source/