MikroElektronika Learn

RF Technologies & IOT

GSM – Part 2 : AT Parser

18 Apr , 2016  

The basic idea of a GSM engine is to make something that will control a modem’s behavior. Like an engine for a car that can be used inside another car the parsing engine is for AT commands. For that kind of job, we need to focus on creating the basic core. The core provides the lower level workings which allow us to work at a higher level. There are many types of devices that use AT commands in order to control the modem and communication with other devices. This library was built in this manner, and can be used with other radios not only GSM modems.

GSM Engine

As we said at the introduction of this series about the GSM devices, AT commands are the most common method of controlling modems. Creating the parser for AT commands can be a good starting point but the parser alone can not be enough to control every aspect of communication.




Modems usually use serial communication and inside the embedded world it is known as UART protocol. The second thing we need is the HAL (hardware access layer) for UART access. This will make our library independent to the platform or compiler used. Hardware flow control is a part of serial communication, although it is not required, it can bring a lot of freedom to operations that can take large amounts of time – for example – string comparisons.

The third and most important part of communication is to ensure functionality in unusual circumstances. Sometimes, there might be an error in data transfer, so the modem does not recognize a command and will not respond to a request. For that kind of job, we need a timer that will count the time from our request. If the amount of time is larger than we have specified for the modem to respond, we want to stop excepting responses.

Finally, there are differences between modems, so we also must make some adaptations to our library that will ensure the functionality for those varying type of devices. We want place of of the adaptive operations in one separate file so something like an adapter is needed as well.

We will not go through the creation of HAL layer or timer but will pay attention to the  at_parser.c as most vital and important part of our library.  The  gsm_adapter.c is the part that should be adapted to the specific GSM module will be explained in the next part of our tutorial.

AT Parser

The main job for the AT parser is to analyze the responses from the module. Depending on the returning response, it can be important to the user or intended to execute some type of task.  That task can even be a callback function defined by the user. Actually that is the job for the engine, but we want our parser to return information as to what the engine should execute.

The idea is to store all AT commands that can be valuable for those module response by placing some of the responses in the MCU storage as well as the callback specified for what response will be executed. When we reviewed the chapter about AT commands, the conclusion was that there are 4 different types of commands that can be easy recognized by reading the string. So our type of data that will be stored could be type that have command string that will be used for comparison and 4 callbacks for each of the four different types commands.

We have declared the function pointer of type callback – so every of our callbacks must have exact same definition. Our function pointer will have string arguments that will be used to provide the response to the callback.

We declared the type for storage with four callbacks in addition with hash and timeout, and have declared it in the storage area. Remember the previous section where we was discussing about the unusual occurrences where we might need a timeout after which we are not excepting response from the module anymore? So the member timeout is going to be used for storing that value.

You may be wondering where is the command string used for comparison – well, we replaced it with a hash. Every command will be converted to a  uint32_t  re-presenter. If you are asking why we are doing that there are at least two good reasons. First reason, in case of MCUs with a small amount of RAM space, we save it in this way because we need only 4 bytes for any command. The second, and more important reason, is the improvement of performance. It is much faster to compare two uint32_t numbers than two strings even if the string are shorter than 4 bytes.

This function is used for hash calculation. Of course you can create your own formula but test it before real usage just to see does it work the way you want.

Next step is to create the function that will store the our types to the storage we created.

The parts of function which might be interesting is the function _at_search( command ) that is actually searching the same command on the storage, for example to avoid saving of the same command. Variable  at_cmd_storage_used is a static variable used to provide the current number of saved commands. Constant  AT_HEADER_SIZE represents the maximum size of the command including the AT which is part of almost every AT command.

Next step is to make the function that is going to recognize the string and return the command type. For that kind of job we can involve a enum that will represent all types of command. Solutions might look like this:

The function accepts raw input that will be our response from the module. Second parameter will be a clean command string – without any characters that not belong to the command and of course our function will return the type of the command – that was the primary goal.

Finally we have the most important function, the parser. This function provides all responses and functions to parse. It also returns the exact function pointer and the proper timeout for the associated command.

This function assigns the callback and timeout from the first member in our storage. If the function is not recognized, or can not be parsed we have  a default callback and default timeout for the functions that are not saved. This means that we have to assign something to the first member inside the our storage and that is the job for the initialization function. In this case, that will be done at a higher level or in  at_engine.c because our parser doesn’t need to know anything about default timeouts or callbacks.


We have passed through the AT command parser. Some improvements and changes can be made, for example if you want  your parser to avoid trying to parse commands that doesn’t start with AT string you can involve that check inside, but keep in mind that not all command starts with the AT string.

Part 3 >>


Products mentioned

, , , ,

Firmware developer in MikroElektronika with a passion for telemetry in the field of IoT. Low level is for the true modern day warriors.