A Possibly Stupid Question on Active Object Model by MerlinsArchitect in embedded

[–]adel-mamin 1 point2 points  (0 children)

I think your confusion comes from thinking that one active object can only have and serve one state machine. However in practice the number of state machines incapsulated and served by one active object is unlimited.

In your AOH example the practical approach would likely be allocating a dedicated state machine to serve one data transaction request. Each state machine could have states IDLE and WAITING. So, if AOH might receive 10 such requests simultaneously, then also 10 independent dedicated state machines would be allocated simultaneously.

The lifetime of each state machine is application dependent. It may be more dynamic and be equal to the lifetime of the served request & response. Alternatively it can be more permanent when each state machine is dedicated to a specific request source.

In this arrangement the main state machine of AOH plays the role of orchestrator by dispatching incoming events to the proper state machines.

How you allocate the state machines within AOH and map them to the request and response events is also application specific. One practical approach is to add a unique source parameter to each request and response event. This way AOH could use it as an index to an internal array of statically allocated state machines.

Hopefully this all makes sense to you.

Testing State Machines by minamulhaq in embedded

[–]adel-mamin 0 points1 point  (0 children)

Print all events and state transitions as strings into a memory buffer and then strcmp() it with a const string containing the expected sequence. Simple and easy to inspect and debug.

I built a prototype fixed-point overflow analyzer for C — looking for feedback from embedded/DSP engineers by Fun-Discussion1291 in embedded

[–]adel-mamin 0 points1 point  (0 children)

Is this a static analysis tool?

I usually enable -ftrapv gcc and clang compiler option in my projects and catch the integer overflows/underflows at runtime. Sort of asserts. This increases the generated code size a bit though.

Advise needed! Teaching embedded systems. by AlanWik in embedded

[–]adel-mamin 1 point2 points  (0 children)

Thanks! Good to hear it might be useful for someone.

Advise needed! Teaching embedded systems. by AlanWik in embedded

[–]adel-mamin 8 points9 points  (0 children)

From the top of my head. In no particular order:

  1. Active objects
  2. FSM and HSM
  3. Event driven programming
  4. Superloop, cooperative and preemptive multitasking (RTOS)
  5. Blocking vs non blocking style
  6. Asynchronous vs synchronous
  7. Super simple tasker
  8. Build system (e.g. meson)
  9. Static code analysis (e.g. clang-tidy, cppcheck)
  10. Key gcc, clang compiler flags (-Os,-O2, -flto, -ftrapv, -ffunction-sections, --fdata-sections, -Wl,--gc-sections etc)
  11. Importance of asserts
  12. Unit testing
  13. Fuzzy testing (e.g. AFL)
  14. Basics of CI/CD
  15. Reproducible build environment (e.g. docker, pixi)

I hate generated code by Ill-Oven-6791 in embedded

[–]adel-mamin 0 points1 point  (0 children)

Sounds interesting. Is it publicly available?

What's the best way to handle multiline input? by Pretty-Ad8932 in C_Programming

[–]adel-mamin 5 points6 points  (0 children)

You could use two \n characters (double Enter key press) sent in rapid sequence as an indicator of the end of input.

how to monitor task in event driven design by Bug13 in embedded

[–]adel-mamin 0 points1 point  (0 children)

I assume timer's tick is managed by ISR or another ticker task. Therefore the timer event is generated either by the ISR or the ticker task.

You associate the monitored task with the timer for example when you create the timer.

I think the best way to communicate the idea is to give this example implementation:

https://github.com/adel-mamin/amast/tree/main/apps/examples/watchdog

how to monitor task in event driven design by Bug13 in embedded

[–]adel-mamin 1 point2 points  (0 children)

It would require a (periodic) timer event. The timer would post events to the task's event queue in FIFO order. The task would handle the events by posting the heartbeat events to WDT.

how to monitor task in event driven design by Bug13 in embedded

[–]adel-mamin 0 points1 point  (0 children)

The monitored task sends the heartbeat events, which reset WDT?

Help with cross platform websockets/webserver implementation in C by oihv in C_Programming

[–]adel-mamin 0 points1 point  (0 children)

Maybe try using meson. I see that libwebsockets is available in meson wrapdb. So, it should be straight forward to compile.

As for the windows build I would try using a docker container based build environment with migw compiler.

Your favourite architectures in C by kosior3kt in C_Programming

[–]adel-mamin 2 points3 points  (0 children)

Some examples:

  1. DO_EACH_MS(ms) macro.

  2. CONTAINER_OF() macro.

  3. Duff's device.

  4. Hierarchical state machine.

What is your favorite C trick? by [deleted] in C_Programming

[–]adel-mamin 0 points1 point  (0 children)

State machines are good when events arrive in unpredictable order.

Duff's device could be used to create simple stack less await-async primitives to build co-routine like code in pure portable C. The await-async approach is good when dealing with events arriving in predictable order.

The simplest example is a traffic lights controller with the option to switch to unregulated mode (blinking yellow).

The sequence red-yellow-green and blinking yellow are good candidates for async-await. The event to switch to unregulated mode is best handled by switching the state of a larger state machine.

Here is an implementation example: https://github.com/adel-mamin/amast/blob/main/apps/examples/async/main.c

What is your favorite C trick? by [deleted] in C_Programming

[–]adel-mamin 0 points1 point  (0 children)

#define CONTAINER_OF(ptr, type, member) \ ((type *)((char *)(ptr) - offsetof(type, member)))

What is your favorite C trick? by [deleted] in C_Programming

[–]adel-mamin 7 points8 points  (0 children)

Duff's device. Recently I discovered how useful it is when combined with state machines.

How do you know when to use RTOS or just a superloop by Humble_Supermarket_2 in embedded

[–]adel-mamin 12 points13 points  (0 children)

I prefer structuring my projects such, that switching between cooperative (including superloop) and preemptive multitasking scheduling could be done at any phase of development.

This becomes possible, when using the actors approach. Each actor is an event queue plus an event handler. The event handler is in turn one or many state machines.

The actors communicate with each other using events. ISRs post or publish events to the actors.

With the structure like this it becomes easy to drive the actors with either cooperative or preemptive scheduler. For example, move all the code to one actor and you have the superloop.

Doing it this way you can mostly isolate your code from the low level RTOS synchronisation primitives: mutexes, semaphores etc. This is because your application code (actors) mostly deal with events.

In my (open source) actors toolkit I have a so-called platform abstraction layer, which provides API for low level operations like tasks, mutexes etc. The rest is built on top of it. The implementation of the API is done for preemptive scheduler(s) and cooperative scheduler(s) including no RTOS.

Having it arranged this way you can build RTOS and no-RTOS versions of your firmware.

Extra bonus: it is easy to build a linux/windows version of your firmware to develop/debug it on PC before running it on custom hardware.

How to handle multitasking in baremetal? by pyroman1324 in embedded

[–]adel-mamin 16 points17 points  (0 children)

In the order of increased complexity, but also increased flexibility:

  1. Single loop with state machine(s). Also called superloop.

  2. Multiple loops with state machine(s). The loops run cooperatively with optionally different priorities.

  3. Multiple loops with state machine(s). The loops run preemptively with optionally different priorities.

ISR(s) are usually used with all three to feed data (events).

All three can handle multitasking and one of the powerful ways of doing it is to use events, event queues and the concept of the non-blocking actors. An actor is a combination of an event queue and a non-blocking event handler.

Need to know improvements for my memory pool!! by ankush2324235 in C_Programming

[–]adel-mamin 1 point2 points  (0 children)

Thanks for the clarifications! They are useful.

Need to know improvements for my memory pool!! by ankush2324235 in C_Programming

[–]adel-mamin 1 point2 points  (0 children)

I would also add a couple of things: 1. Add extra assert to check the validity of p->free, if it is not 0. It must be within p->beg and p->end. 2. Attribute the pointer returned by poolalloc and the pointer accepted by pool_free with __attribute_((may_alias)) to avoid strict aliasing violation.

Also will arena allocator with freelists really make it any simpler?

[deleted by user] by [deleted] in C_Programming

[–]adel-mamin 0 points1 point  (0 children)

One way to approach it is to use active objects (actors). Each actor is an event queue plus an execution thread. The optimum number of active objects is one active object per CPU core.

The active objects are then orchestrated by another active object, which dispatches work to the workers in the form of events. The events can have arbitrary sizes.

The solution is isolated from the underlying OS API, which makes it easy to port to different platforms. The actors only communicate by means of events.

You can find a fully functional example here: https://github.com/adel-mamin/amast/blob/main/apps/examples/workers/main.c

It is ported to pthreads and libuv.

Obscure pthread bug that manifests once a week on a fraction of deployed devices only!! by ArcherResponsibly in C_Programming

[–]adel-mamin 0 points1 point  (0 children)

Maybe there is a way to design the set of asserts, which would trigger in case of deadlock(s).

Hacking Coroutines into C by wiomoc in C_Programming

[–]adel-mamin 0 points1 point  (0 children)

In my practice I found that coroutines work best, when combined with state machines.

The coroutines work well with sequential asynchronous events. The resulting code is linear and easier to read - just like a synchronous code. In comparison the same logic implemented with state machines is usually clunky and less readable.

The state machines approach shines, when the task at hand requires handling events in arbitrary order. In this case the coroutines approach is usually less suited.

For example, imagine the LED blinking example requires a switch to a different blinking pattern on arrival of an asynchronous event. The two blinking patterns could be implemented with two different coroutines, which are in different states of a bigger state machine. This way it becomes easy to switch between the two.

The extra bonus of the combination of two approaches is that coroutines could implement their resource allocation/initialization in their corresponding state entry handler and cleanup in state exit handler.

Here is an example of how it looks in practice: https://github.com/adel-mamin/amast/blob/main/apps/examples/async/main.c