Bootladder Engineering

AT Command Target-Side Framework
C/C++ Framework for Receiving AT Commands
Client's product contains a microcontroller and a cellular modem. The modem is controlled by AT Commands. We decided to also test the entire system via AT Commands.
This is how I approached it.

AT*LED=0,0,0,0\n


  typedef struct {
    uint8_t * command_template;
    uint8_t * command_description;
    AtCommandHandler_CommandFunc_t command_func;
    AtCommandHandler_ReadFunc_t read_func;
    AtCommandHandler_WriteFunc_t write_func;
  } AtCommandHandler_t;
Deciding to test the product with AT Commands
We were evaluating several different modem modules as well as telecom carriers. Also, RF performance such as antenna selection was being evaluated.
Once the project was getting close to production, we had to plan out factory testing. Factory testing would include a test of the cellular modem module as well as everything else on the device.
It was a natural idea for my colleagues to suggest that all of the testing be done over a AT command style interface. One advantage is that by exposing an AT Command interface on the microcontroller, you get the cellular modem testing for free in a sense, because you can simply pass through all of the serial communication to the cellular modem. All of the effort spent testing the cellular modem in isolation could be reused. Except maybe one extra command to escape out of the normal flow.
I thought this was a reasonable idea and moreover my colleagues had already prepared a spreadsheet documenting a set of AT Commands they would like to be implemented for factory testing. These AT Commands would cover testing in the lab, customer sites, and at the contract manufacturer.
In fact, the legacy firmware from before I had joined already had an implementation for receiving parsing and dispatching AT Commands. However, it was bespoke typical 20th century style C code with essentially zero abstraction. And, there were a ton of new commands to implement, and many of the legacy commands would be discarded due to hardware change.

Looking for a library

So my first thought was to look for an open source library to factor this framework stuff out. It's not complicated software and in fact I had close to an exact idea of what it should be. So I basically searched to find what I would have written myself.

However, I was surprised to find nothing. I found several frameworks and libraries dealing with the host side of AT Command communication, which of course makes sense because generally the host side is what is being customized and the target side is a third party module that will not be changed.

In this case, we were working on the receiving side ie. target side. I could have looked farther, but at a certain point it's not worth it when I only wanted maybe 100 lines of code anyway. Plus I thought it would be a good exercise, which would take a fraction of a day to complete. So I set out to do that.

Intro to AT Commands

AT Commands are commonly used to control modems such as cellular modems. Although very outdated, AT Commands are still in use today.

AT Commands are a natural text based interface which can be commanded manually by a keyboard.

AT Commands are extremely simple. They start with a prefix and then a command name. Then there there is a common syntax for the suffix part. Put simply, there are three suffixes.

There is the command which is basically no suffix, which is just a side effect. There is a test which is a suffix ending with question mark which is basically a read. And then there is a write where you can give parameters. If you squint really hard. It is a little bit similar to URL queries. So when receiving one of these commands, it is very simple. You just validate the string which could be as simple as checking that it begins with the letters AT. After that you find the name of the command which appears after the AT and before the equal sign. This is a key to look up the handler in a table of function pointers. Then if there are parameters, then they will be parsed out of the suffix. Then you simply call the function and pass the parameters.

Implementation

This is very simple of course, but the thing is this is being implemented on a bare metal target in C/C++. The legacy implementation had no abstraction. In other words, it was just a giant if else block with tons of duplication on the validation and extracting of query parameters. And there was no function table. The handling of commands was done in place at the point of parsing. So the approach I took is very obvious. I'm sure we've all seen a similar pattern.

I'm not sure what to call it, but basically I defined a struct to represent an AT Command and all of its suffix types. So for example, AT Command for LED control would allow you to set or get an LED brightness. So what I would define is what I call a command template, which is a string that can be used to uniquely match the prefix of the command and associate it with handler functions. Then there's also a description which would be useful for auto generating a help message. And then there are up to three function pointer fields or members for a write read and command. Some of these command definitions will define all three command types and others will only define one. The feature or value gained by doing this is that the logic for extracting arguments can be factored out. So for example, if a command is going to write a value, then that determines that arguments need to be parsed out as well as determines that a certain function handler pointer needs to be called with those arguments.

So that is the data structure which I call ATCommandHandler.

Then there is ATCommandParser, which takes a line, meaning an input string such as from a serial port. It tries to match the line with a struct from a set of structs that is defined at initialization. Initialization is done by defining all of the ATCommandHandler structs that are part of the command set. Then a main application simply waits for lines, then takes each line, tries to match it with a handler struct. Then if there is a match, it may extract arguments out and then will call the appropriate function. And as I mentioned before, another advantage of this framework is that a help message can be generated automatically by scanning through all of the defined at command handlers. So, quite simple and straightforward. This is actually also a good exercise in writing good quality software with unit tests, end to end tests and an exercise in portability.

Errosdfdr pretty-printing HTML: mismatched tag: line 99, column 2 AT Command Target Side Framework - Bootladder
AT Command Target-Side Framework
C/C++ Framework for Receiving AT Commands
Client's product contains a microcontroller and a cellular modem. The modem is controlled by AT Commands. We decided to also test the entire system via AT Commands.
This is how I approached it.

AT*LED=0,0,0,0\n


  typedef struct {
    uint8_t * command_template;
    uint8_t * command_description;
    AtCommandHandler_CommandFunc_t command_func;
    AtCommandHandler_ReadFunc_t read_func;
    AtCommandHandler_WriteFunc_t write_func;
  } AtCommandHandler_t;
Deciding to test the product with AT Commands
We were evaluating several different modem modules as well as telecom carriers. Also, RF performance such as antenna selection was being evaluated.
Once the project was getting close to production, we had to plan out factory testing. Factory testing would include a test of the cellular modem module as well as everything else on the device.
It was a natural idea for my colleagues to suggest that all of the testing be done over a AT command style interface. One advantage is that by exposing an AT Command interface on the microcontroller, you get the cellular modem testing for free in a sense, because you can simply pass through all of the serial communication to the cellular modem. All of the effort spent testing the cellular modem in isolation could be reused. Except maybe one extra command to escape out of the normal flow.
I thought this was a reasonable idea and moreover my colleagues had already prepared a spreadsheet documenting a set of AT Commands they would like to be implemented for factory testing. These AT Commands would cover testing in the lab, customer sites, and at the contract manufacturer.
In fact, the legacy firmware from before I had joined already had an implementation for receiving parsing and dispatching AT Commands. However, it was bespoke typical 20th century style C code with essentially zero abstraction. And, there were a ton of new commands to implement, and many of the legacy commands would be discarded due to hardware change.

Looking for a library

So my first thought was to look for an open source library to factor this framework stuff out. It's not complicated software and in fact I had close to an exact idea of what it should be. So I basically searched to find what I would have written myself.

However, I was surprised to find nothing. I found several frameworks and libraries dealing with the host side of AT Command communication, which of course makes sense because generally the host side is what is being customized and the target side is a third party module that will not be changed.

In this case, we were working on the receiving side ie. target side. I could have looked farther, but at a certain point it's not worth it when I only wanted maybe 100 lines of code anyway. Plus I thought it would be a good exercise, which would take a fraction of a day to complete. So I set out to do that.

Intro to AT Commands

AT Commands are commonly used to control modems such as cellular modems. Although very outdated, AT Commands are still in use today.

AT Commands are a natural text based interface which can be commanded manually by a keyboard.

AT Commands are extremely simple. They start with a prefix and then a command name. Then there there is a common syntax for the suffix part. Put simply, there are three suffixes.

There is the command which is basically no suffix, which is just a side effect. There is a test which is a suffix ending with question mark which is basically a read. And then there is a write where you can give parameters. If you squint really hard. It is a little bit similar to URL queries. So when receiving one of these commands, it is very simple. You just validate the string which could be as simple as checking that it begins with the letters AT. After that you find the name of the command which appears after the AT and before the equal sign. This is a key to look up the handler in a table of function pointers. Then if there are parameters, then they will be parsed out of the suffix. Then you simply call the function and pass the parameters.

Implementation

This is very simple of course, but the thing is this is being implemented on a bare metal target in C/C++. The legacy implementation had no abstraction. In other words, it was just a giant if else block with tons of duplication on the validation and extracting of query parameters. And there was no function table. The handling of commands was done in place at the point of parsing. So the approach I took is very obvious. I'm sure we've all seen a similar pattern.

I'm not sure what to call it, but basically I defined a struct to represent an AT Command and all of its suffix types. So for example, AT Command for LED control would allow you to set or get an LED brightness. So what I would define is what I call a command template, which is a string that can be used to uniquely match the prefix of the command and associate it with handler functions. Then there's also a description which would be useful for auto generating a help message. And then there are up to three function pointer fields or members for a write read and command. Some of these command definitions will define all three command types and others will only define one. The feature or value gained by doing this is that the logic for extracting arguments can be factored out. So for example, if a command is going to write a value, then that determines that arguments need to be parsed out as well as determines that a certain function handler pointer needs to be called with those arguments.

So that is the data structure which I call ATCommandHandler.

Then there is ATCommandParser, which takes a line, meaning an input string such as from a serial port. It tries to match the line with a struct from a set of structs that is defined at initialization. Initialization is done by defining all of the ATCommandHandler structs that are part of the command set. Then a main application simply waits for lines, then takes each line, tries to match it with a handler struct. Then if there is a match, it may extract arguments out and then will call the appropriate function. And as I mentioned before, another advantage of this framework is that a help message can be generated automatically by scanning through all of the defined at command handlers. So, quite simple and straightforward. This is actually also a good exercise in writing good quality software with unit tests, end to end tests and an exercise in portability.