Hello,
I'm having a tinker with an old project and thought I'd share it. It deals with the problem of getting information from one device to another. This is such a common issue, nearly every non-trivial robotics project has to deal with it. Quite often the first impulse of a developer is to start writing code to serialize and deserialize structs so that they can be pushed out over a UART, or maybe start hacking at an ASCII based protocol (yuck). You then quickly realize it's very repetitive, tedious and error prone.
C3 contains a code generator (i.e. a dodgy python script) that reads a protocol description file to produce a C++ API that does all the dirty work. All you need to do is create the protocol description file, which is in JSON format, to describe what you need to send back & forth.
I've also thrown in a Javascript module that uses the protocol description file to serialise/deserialise your data inside NodeJS. You can use the serialport library to read/write to your Teensy.
The protocol description file lets you define enums, so you can send enum types back and forth. This is pretty useful for when you need to send back a status or a state of something where the number of states is finite . . . like the status of a finite state machine. It also has a settings singleton class, which of course, can be ignored if you don't want it. But, basically, in a system you will often want to tweak or make adjustments or calibrations, or whatever. These adjustments (aka settings) are global within software and, often, in my experience, are sent from a PC to the device via a UART and stored in FLASH memory. If you flag a message as a 'setting' in the protocol description, C3 will deserialise it directly to the appropriate fields of the settings class where it is globally accessible. I've found this very nifty, but don't expect it to be everyone's cup of tea. I wonder if it's perhaps out of scope for a protocol API . .hmm . . .
C3 will 'ack' messages if they have 'ack_required': 'true' in the protocol description. This means messages will not be removed from the pool of messages to be sent, until an acknowledgement is received for that particular message. This effectively guarantees the other end has received the message (or you get a timeout).
Some of the basic features of C3 are checksums (fletcher-16), zero calls to new/malloc (uses a memory pool), completely header-only library.
It compiles for Arduino UNO, Arduino Mega 2650, Teensy, other ARM chips and of course Linux/Windows/Mac/whatever. The amount of memory it uses is adjustable by changing the max packet length and size of the memory pool in c3.h (lines 35, 36). Normally I work with ARM chips with plenty of RAM and so I typically have max packet length to 256 and pool size to 2048. Never had any issues with my use case and that configuration. It should go well on a Teensy too. I've never really used C3 on an UNO except limited tests, but to even get it to compile and not eat all RAM I dialed it right down to 64 and 256 pool size. The memory pool holds packets before they are serialized, so if you hold off calling 'serialise', you may require a large pool so that called to 'create_packet' don't return nullptr. If you call serialise immediately after every 'create_packet' then you can make the pool size small (like packet size x2).
Some TODO items are
It has one dependency (etk). To install etk, just download it off github, create a folder in your Arduino library directory called 'etk' and copy over all the files from EmbeddedToolKit/inc/etk.
C3 Github
Anyway, reason I'm posting this is because of the off chance someone will find it interesting, or otherwise bother to dig through the code. Feedback & contributions welcome.
Cheers
I'm having a tinker with an old project and thought I'd share it. It deals with the problem of getting information from one device to another. This is such a common issue, nearly every non-trivial robotics project has to deal with it. Quite often the first impulse of a developer is to start writing code to serialize and deserialize structs so that they can be pushed out over a UART, or maybe start hacking at an ASCII based protocol (yuck). You then quickly realize it's very repetitive, tedious and error prone.
C3 contains a code generator (i.e. a dodgy python script) that reads a protocol description file to produce a C++ API that does all the dirty work. All you need to do is create the protocol description file, which is in JSON format, to describe what you need to send back & forth.
I've also thrown in a Javascript module that uses the protocol description file to serialise/deserialise your data inside NodeJS. You can use the serialport library to read/write to your Teensy.
The protocol description file lets you define enums, so you can send enum types back and forth. This is pretty useful for when you need to send back a status or a state of something where the number of states is finite . . . like the status of a finite state machine. It also has a settings singleton class, which of course, can be ignored if you don't want it. But, basically, in a system you will often want to tweak or make adjustments or calibrations, or whatever. These adjustments (aka settings) are global within software and, often, in my experience, are sent from a PC to the device via a UART and stored in FLASH memory. If you flag a message as a 'setting' in the protocol description, C3 will deserialise it directly to the appropriate fields of the settings class where it is globally accessible. I've found this very nifty, but don't expect it to be everyone's cup of tea. I wonder if it's perhaps out of scope for a protocol API . .hmm . . .
C3 will 'ack' messages if they have 'ack_required': 'true' in the protocol description. This means messages will not be removed from the pool of messages to be sent, until an acknowledgement is received for that particular message. This effectively guarantees the other end has received the message (or you get a timeout).
Some of the basic features of C3 are checksums (fletcher-16), zero calls to new/malloc (uses a memory pool), completely header-only library.
It compiles for Arduino UNO, Arduino Mega 2650, Teensy, other ARM chips and of course Linux/Windows/Mac/whatever. The amount of memory it uses is adjustable by changing the max packet length and size of the memory pool in c3.h (lines 35, 36). Normally I work with ARM chips with plenty of RAM and so I typically have max packet length to 256 and pool size to 2048. Never had any issues with my use case and that configuration. It should go well on a Teensy too. I've never really used C3 on an UNO except limited tests, but to even get it to compile and not eat all RAM I dialed it right down to 64 and 256 pool size. The memory pool holds packets before they are serialized, so if you hold off calling 'serialise', you may require a large pool so that called to 'create_packet' don't return nullptr. If you call serialise immediately after every 'create_packet' then you can make the pool size small (like packet size x2).
Some TODO items are
- improve serialisation performance (it serialises to a buffer then iterates over the buffer atm)
- do some actual error checking during code generation
- make the nodeJS code better and do examples
It has one dependency (etk). To install etk, just download it off github, create a folder in your Arduino library directory called 'etk' and copy over all the files from EmbeddedToolKit/inc/etk.
C3 Github
Anyway, reason I'm posting this is because of the off chance someone will find it interesting, or otherwise bother to dig through the code. Feedback & contributions welcome.
Cheers