Hacker News new | past | comments | ask | show | jobs | submit login
Guide to Implementing Communication Protocols in C++ for Embedded Systems (gitbooks.io)
63 points by ingve 9 months ago | hide | past | web | favorite | 26 comments

> Many developers implement this logic using simple switch statement. However, after about 7 - 10 cases such dispatch mechanism becomes quite inefficient, and its inefficiency grows with number of new messages being introduced.

It's actually pretty cheap on ARM (2 cycles [1]), if the message IDs are consecutive, due to TBB/TBH [2], and GCC will use it when appropriate. Not sure if x86 has an equivalent.

[1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.... [2] http://infocenter.arm.com/help/topic/com.arm.doc.dui0553a/BA...

Switch is efficient on pretty much any platform I can think of (well, except some 8-bit uC compilers...).

That statement about switch inefficiency is simply not true, except for sparse case values.

But since one can generally choose those values (and they're often a running enum anyways), it's really a non-issue.

For sparse case, it's better to use a hash table. Perhaps a build phase to generate a perfect hash (https://en.wikipedia.org/wiki/Perfect_hash_function) to map each possible input value to continuous range of integer values.

> except for sparse case values

Even for sparse case values the compiler will emit a binary search once the list of labels is long enough.

i’m pretty sure i’ve heard of compilers generating a perfect hash (since the key space is known) also

This has been my expectation as well, but haven't seen this in real life.

I guess the main issue is that the compiler will need to also ensure no value outside the expected set can match a case statement either (no match and default cases), which kinda negates the benefit.

Maybe there are cases this is generated, anyone seen compiler generating those?

I wonder whether it is possible to generate reversible (almost) perfect "hashes"?

I mean a hash where every unique input value is guaranteed to map to a unique output value. Because this kind of hash could be used to handle no-match/default case safely.

..and his proposed alternative requires that you have already decoded the message to create the corresponding Message objects. To create those objects, you still need some sort of switch somewhere, eg switch(ip.protocol()) { case 6: m = new TcpMessage(); break; case 17: m = new UdpMessage(); break; .. }

Just use Restbed and you have as much of Apache's abilities as you want. I've been using Restbed for a few years now, for a communications application that scales from enterprise to embeds inside devices, and Restbed handles it all. https://github.com/corvusoft/restbed

Sorry, but this misses the point completely. The guide is about implementing communication on platforms that can be so tiny that using embedded OSes like FreeRTOS becomes tight and the RAM might not be sufficient to store a single TCP/IP packet. A full blown HTTP stack is a luxury that is way beyond these platforms. Besides, how do you do implement HTTP over I2C or SPI?

I tried really hard to find a main() function browsing the demo source code, but I could not. I also find it interesting that code boilerplating is called out as a problem, but I run into code like this:

  #include "Protocol.h"

  #include "comms/comms.h"

  namespace cc = comms_champion;

  namespace demo

  namespace cc_plugin

  Protocol::~Protocol() noexcept = default;

  const QString& Protocol::nameImpl() const
      static const QString& Str("Demo");
      return Str;

  }  // namespace cc_plugin

  }  // namespace demo

I'm trying to remain open minded to it, I found a few protocols :-


the ublox example seems a reasonably complex protocol of messages.

However, I'm not really sold on the framework to do it this way.

Eh, just write a state machine.

Embedded dev here.

Using C/C++ for embedded systems external communications feels like building a house out of matches.

Sure, there's tooling to help fire proofing things a bit, like static analysis and so on. You see, it's important to spray some fire retardant on the match house.

But wouldn't it be so much nicer to have a construction material other than matches for this purpose...

IEC 61131-3 Structured Text [1] is very similar to Pascal if you're more on the industrial / electrical side rather than 'real' embedded dev, quite a few PLCs support it these days and it's a fair compromise between safety and expressiveness.

[1] https://en.wikipedia.org/wiki/Structured_text

Unfortunately a large portion of the language spec is optional so it's not portable between PLC manufacturers, and implementation quality varies significantly. Source: it's my dayjob. :(

Quite cool, thanks for point it out.

I've done a fair bit of embedded stuff with C++ and I completely agree. I've been watching Rust quite closely in the hopes that it's suitable for embedded development by the time my next round of projects comes up.

So, which language or tool would you recommend?

Rust looks promising, but it is not ready yet. I use it on iMX6, which is relatively powerful system, but on NRF52 we still use C. Maybe I will use it on NRF52 when support for bare hardware metal will be in stable (working group[1] is working on that).

[1]: https://github.com/rust-lang-nursery/embedded-wg

Rust looks quite promising.

Currently limited microcontroller architecture support is one of the biggest issues with it.

Rust based RTOS would also be helpful for medium size devices. Of course small devices are fine on bare metal.

There are some projects, for example [1],[2], but they require nightly compiler, i.e. they cannot be used in production yet.

[1]: https://github.com/tock/tock/blob/master/doc/Getting_Started... [2]: https://github.com/hashmismatch/freertos.rs

If you don't use Rust yet, what do you use right now?

I would have guessed C or C++. Maybe they're not great for the purpose but they're also just about the only game in town, no?

Mostly C.

While C++ is easier to write, for very low level code, it is harder to maintain when you need to understand all of the side effects to maintain code safety.

C++ compiler support is also sometimes not available. (And of course it's very like there'll be no Rust compiler available either in this case.)

AutoSAR? or Ada?

Actually, does anyone know if FORTRAN is ever used for embedded applications?

RTF/68k [0] is a extended Fortran 77 for embedded systems based on the 68k.

It was used for a fair number of control systems in the 1980s and 1990s.

[0] https://webhome.weizmann.ac.il/home/fhlevins/RTF/RTF-TOC.htm...

I was working on a similar problem recently and ended up dropping all the fancy OOP footwork for a handful of static functions.

Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact