Ideas for command protocol

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
On my Hard Drive POV Clock project, I have no buttons to set the time or date on the clock. I do have an HC05 Bluetooth serial device. First step I plan to set time, date, get rpm etc. via a simple menu. Just use terminal software to communicate to the pic.

But eventually I might want to develop an app for my phone to do the same. For that I would likely need some kind of protocol. I was thinking something like the old AT command set for modems,

Maybe something like:

ATSH01 Set hour to 01
ATGH Get the current hour


etc.

Has anyone done anything like this? Maybe offer some thoughts on what I should put into the design?
 

djsfantasi

Joined Apr 11, 2010
9,163
Since this is unlikely to become a standard, IMHO, you can do whatever you want.

This is what I’ve done in the past. Make a list. Brainstorm over a couple of days and list the actions you might want to perform.

Note I said actions and not commands. And don’t worry about parameters. Then, I start making groupings. Don’t stop at one. Force yourself to group the actions in at least two or three ways.

At this point, it should come easier. Groupings may suggest commands and sub-commands. Make a list of these, and then go through item by item and identify the parameters needed.

Now, I assign tokens to each command and sub-command. The tokens could be numbers, abbreviations, acronyms. The choice is yours.
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
Since this is unlikely to become a standard, IMHO, you can do whatever you want.

This is what I’ve done in the past. Make a list. Brainstorm over a couple of days and list the actions you might want to perform.

Note I said actions and not commands. And don’t worry about parameters. Then, I start making groupings. Don’t stop at one. Force yourself to group the actions in at least two or three ways.

At this point, it should come easier. Groupings may suggest commands and sub-commands. Make a list of these, and then go through item by item and identify the parameters needed.

Now, I assign tokens to each command and sub-command. The tokens could be numbers, abbreviations, acronyms. The choice is yours.

Can you post some examples?
 

cmartinez

Joined Jan 17, 2007
8,257
Can you post some examples?
I
Since the amount of information sent and retrieved will be quite limited, I'd probably settle for only two commands. One to set every single parameter needed for normal operation at once, and another one to receive a list of all parameters.

Keep things as simple as you can.
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
I
Since the amount of information sent and retrieved will be quite limited, I'd probably settle for only two commands. One to set every single parameter needed for normal operation at once, and another one to receive a list of all parameters.

Keep things as simple as you can.

So something as simple as ST10:12:30?
 

hexreader

Joined Apr 16, 2011
581
So something as simple as ST10:12:30?
You get full agreement from me.

For convenience of use:
1) I MIGHT allow the option for ST10:12 - as a quick way to set 10:12:00
2) I probably would allow ST10 to allow easy change of hour without affecting minutes and seconds - for daylight saving hour change
3) I would probably not add CRC, as this adds unnecessary complication IMHO (also makes simple terminal operation harder or impossible)
4) I might add strict position and syntax checking to reject any other format to catch silly typing mistakes
5) I would add a check for CR or LF or both at end of message (I would allow for all CR, LF possibilities)

Interesting project....
 

nsaspook

Joined Aug 27, 2009
13,312
If you have fixed length commands and fixed length data fields for all command it makes error checking so much easier if your communications link (CRC, ECC, etc) has end to end data integrity. A simple one byte unique character for beginning of transmission will allow for message timeouts after that start byte was received but the required length of message data was not received in the allotted time. You need a way to know whether the entire message was received - and a plan for what to do when it isn't ... A simple way is to just dump received characters until the beginning of transmission character is seen again for the next message.
 
Last edited:

cmartinez

Joined Jan 17, 2007
8,257
If you have fixed length commands and fixed length data fields for all command it makes error checking so much easier if your communications link (CRC, ECC, etc) has end to end data integrity. A simple one byte unique character for beginning of transmission will allow for message timeouts after that start byte was received but the required length of message data was not received in the allotted time. You need a way to know whether the entire message was received - and a plan for what to do when it isn't ... A simple way is to just dump received characters until the beginning of transmission character is seen again for the next message.
It seems to me that you're much more experienced than I am in this regard. But here's the way I've done it for years, and I'd like to hear what you have to say about it:

  • I always use single-byte commands to request or transmit information to the MCU, these commands are always non-printable characters.
  • That means that all pertinent information to be transmitted or received always uses the alphanumeric characters a to z, A to Z, 0 to 9, and the ones usually found on the keyboard.
  • All the other characters (except 13 which I always use as EOL) are used as commands
  • The MCU always knows how to handle each and every one of the predefined commands through simple case matching. And command chr(0) is reserved to serve as communications reset.

For instance, if I were to send through the serial port a command to request all parameters (which I'd set as chr(1), for example), then the MCU would answer with something like "128177218239125XXX" + chr(13). Which is something that can easily be retrieved using the ReadLine() command in VB, and a timeout condition (and its corresponding action) can be added to said command.

In the previous example, the previous numbers are given in sets of three characters which represent a single byte of data, and the XXX final number (which could be anything between 000 and 255) represents the CRC of the previous number.

CRC calculation is always done automatically, of course. So the user doesn't need to bother knowing what it is, only if it had a valid result or not.

In spin's project, I'd go for something like "ST12:30pm"<Enter> at a VB dialog, and have the program translate it into something like chr(2)+"YYYYYYYYYXXX". In which chr(2) is the command for the MCU to start receiving time set parameters, YYYYYYYYY would be three bytes representing the total number of seconds to set in the clock (given in ascii characters 0 through 9), and XXX a three digit ascii number representing the CRC of all previously sent characters.

i.e. 10:45:31 pm would be equal to 81,931 in decimal, which is converted to the three-byte equivalent ascii number "001064011". These characters are transmitted to the MCU (preceded by the chr(2) command, of course). The MCU receives said characters, and interprets them by assigning 1 to the most significant byte, 64 to the middle byte, and 11 to the LSB. Finally, the MCU then responds with its own single-byte (but translated into a three-digit ascii number) calculated CRC using a format similar to "ZZZ"+chr(13). Makes sense?

I know that the previous system can be considered as slow for some programmers, but it's proven to be extremely robust.
 

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
I am going with readable characters. And with something that sort of makes sense like the AT command set I mentioned. I also want to be able to control from terminal software. No idea when I will be able to gt to writing an app,
 

Papabravo

Joined Feb 24, 2006
21,227
I favor a sparse 3-tag address space which can be thought of as [Object, Instance, Attribute]. This address space can be populated with all the data an embedded device could reasonably use. Each tag can be whatever size it needs to be. There are two basic Services called GET and PUT. You can have a display version of things that you might print or enter from a keyboard and a compact version which can optimally be coded as single bytes for efficient transmission and reception.
Example:
GET [3,10,1] would get the piece of data that is associated with Object 3, Instance 10, Attribute 1.
SET [1,1,5] <27> would set the piece of data associated with Object 1, Instance 1, Attribute 5 to the value 27
Each service would have a reply to indicate success or failure
GETR [3,10,1] <"OK"> would be a GET Reply from [3,10,1] with the string "OK"
SETR [1,1,5] would be a SET Reply from [1,1,5] saying the value had been successfully updated
GETERR [3,10,1] <EC XC> would be a GET Error with error code EC and Extended Code XC

Using GET [3,10,1] as an example we might encode this message as <0x10, 0x03, 0x0A, 0x01> which takes all of 4 bytes
The corresponding GET Reply might look like <0x90, 0x03, 0x0A, 0x01, 0x1B> The 0x90 is just the service code with the high order bit set. The 0x1B is the value of the attribute [3,10,1] = 27

Using single byte encoding you can have 256 objects, each with 256 instances, with each instance having 256 pieces of data with any type. This is 16,777,216 pieces of data which would cover a large subset of all the embedded applications.

Other services you might want to use include: START, STOP, RESET, GETALL, SETALL

One advantage of this protocol is that you don't have to wait for a reply to a request that might take a while to gather the data for. If the embedded application is multi-threaded the responses can come back out of order. You do have to be careful not to ask for the same thing twice. You might get two different answers and not know which one was the most recent.

Something like is is currently being used worldwide in industrial automation products.
 

joeyd999

Joined Jun 6, 2011
5,287
If you have fixed length commands and fixed length data fields for all command it makes error checking so much easier if your communications link (CRC, ECC, etc) has end to end data integrity. A simple one byte unique character for beginning of transmission will allow for message timeouts after that start byte was received but the required length of message data was not received in the allotted time. You need a way to know whether the entire message was received - and a plan for what to do when it isn't ... A simple way is to just dump received characters until the beginning of transmission character is seen again for the next message.
Essentially a SLIP protocol...which is how I frame my hardware-to-hardware data packets.
 

jfitter

Joined Mar 14, 2019
14
You only have a few commands then use the KISS principle. This is what I do on simple projects;

ASCII, single CHAR command, comma separated parameters, 8 bit CRC, terminator

8bit CRC in C is just 2 lines of code and very fast and lean.
If CRC does not match ignore the command.
Write a parser for the command string. It is stunningly simple in C.

The code is really simple.
Wait for a char and ignore it if unrecognized.
Else get everything up to the terminator (or timeout, or buffer full, etc.).
Parse the arguments.
Check the CRC and ignore everything if check fails.
Reset the timeout.
 

nsaspook

Joined Aug 27, 2009
13,312
It seems to me that you're much more experienced than I am in this regard. But here's the way I've done it for years, and I'd like to hear what you have to say about it:

  • I always use single-byte commands to request or transmit information to the MCU, these commands are always non-printable characters.
  • That means that all pertinent information to be transmitted or received always uses the alphanumeric characters a to z, A to Z, 0 to 9, and the ones usually found on the keyboard.
  • All the other characters (except 13 which I always use as EOL) are used as commands
  • The MCU always knows how to handle each and every one of the predefined commands through simple case matching. And command chr(0) is reserved to serve as communications reset.

For instance, if I were to send through the serial port a command to request all parameters (which I'd set as chr(1), for example), then the MCU would answer with something like "128177218239125XXX" + chr(13). Which is something that can easily be retrieved using the ReadLine() command in VB, and a timeout condition (and its corresponding action) can be added to said command.

In the previous example, the previous numbers are given in sets of three characters which represent a single byte of data, and the XXX final number (which could be anything between 000 and 255) represents the CRC of the previous number.

CRC calculation is always done automatically, of course. So the user doesn't need to bother knowing what it is, only if it had a valid result or not.

In spin's project, I'd go for something like "ST12:30pm"<Enter> at a VB dialog, and have the program translate it into something like chr(2)+"YYYYYYYYYXXX". In which chr(2) is the command for the MCU to start receiving time set parameters, YYYYYYYYY would be three bytes representing the total number of seconds to set in the clock (given in ascii characters 0 through 9), and XXX a three digit ascii number representing the CRC of all previously sent characters.

i.e. 10:45:31 pm would be equal to 81,931 in decimal, which is converted to the three-byte equivalent ascii number "001064011". These characters are transmitted to the MCU (preceded by the chr(2) command, of course). The MCU receives said characters, and interprets them by assigning 1 to the most significant byte, 64 to the middle byte, and 11 to the LSB. Finally, the MCU then responds with its own single-byte (but translated into a three-digit ascii number) calculated CRC using a format similar to "ZZZ"+chr(13). Makes sense?

I know that the previous system can be considered as slow for some programmers, but it's proven to be extremely robust.
That's perfectly fine. My comments were directed to the simple clock get/set, start/stop, etc.. command set he most likely will implement. Obviously the efficiency in the general scope of variable length data messages would be poor but here it's not a big factor. You can add on extras like application level CRC but the Bluetooth serial already provides for that and more for each byte of data actually presented to the application. Serial data might be missing if the link fails but the bytes that are received will be correct. A L2CAP FCS SPP Profile option will deliver data with 16bit CRC at lower-level + 16 bit FCS at the L2CAP layer + 8 bit FCS at RFCOMM level.
 
Last edited:

Picbuster

Joined Dec 2, 2013
1,047
On my Hard Drive POV Clock project, I have no buttons to set the time or date on the clock. I do have an HC05 Bluetooth serial device. First step I plan to set time, date, get rpm etc. via a simple menu. Just use terminal software to communicate to the pic.

But eventually I might want to develop an app for my phone to do the same. For that I would likely need some kind of protocol. I was thinking something like the old AT command set for modems,

Maybe something like:

ATSH01 Set hour to 01
ATGH Get the current hour


etc.

Has anyone done anything like this? Maybe offer some thoughts on what I should put into the design?
I used a simple thing allowing read and write format

sending header; address ; function; location;value; checksum; terminator
address =0 to all devices
address=x to device x
function = R(ead) (W)rite (R)ply
Location = (A)ll (T)ime (S)ound (L)ist (P)osition ' what else you need'
Value = any value following location format.
All = dump all known information.

set time all units header;0,W;T,10-10-2018 09:07:00; checksum;terminator
read time from device 22 header;22,R;T,10-10-2018 09:07:00; checksum;terminator

Picbuster
 

djsfantasi

Joined Apr 11, 2010
9,163
Can you post some examples?
This is the best to which I have quick access. It’s more complex, in which the “tokens” are full words, but the process I used is the same as the one I described. Note how I ended using a total of three parameters for all cases. This simplified command parsing.

<Link to Animatron8.3>

Take a look at the example, ScriptExample.txt, in step 9
 
Last edited:

Thread Starter

spinnaker

Joined Oct 29, 2009
7,830
This is the best to which I have quick access. It’s more complex, in which the “tokens” are full words, but the process I used is the same as the one I described. Note how I ended using a total of three parameters for all cases. This simplified command parsing.

<Link to Animatron8.3>

Take a look at the example, ScriptExample.txt, in step 9

This is pretty cool. Do you have a video of it in action?
 
Top