GSM-AT Lib  Version v0.1
Advanced AT parser for SIMCOM modules
Application note

Clone repository and getting started

Library development is fully hosted on Github and there is no future plans to move to any other platform.

There are 2 repositories

  • GSM_AT_Lib: Source code of library itself.
    • Repository is required when developing final project
  • GSM_AT_Lib_res: Resources, development code, documentation sources, examples, code snippets, etc.
    • This repository uses GSM_AT_Lib repository as submodule
    • Repository is used to evaluate library using prepared examples

Clone resources repository with examples

Easiest way to test the library is to clone resources repository.

  • Download and install git if not already
  • Open console and navigate to path in the system to clone repository to. Use command cd your_path
  • Run git clone command to clone repository
  • Enter into newly cloned folder using cd GSM_AT_Lib_res. Now we are inside working git directory
  • Run command git submodule update --init --recursive to download and update all submodules
  • Navigate to examples directory and run favourite example

Clone library only

If you are already familiar with library and you wish to include it in existing project, easiest way is to clone library repository only.

  • Download and install git if not already
  • Open console and navigate to path in the system to clone repository to. Use command cd your_path
  • Run git clone command to clone repository

Example projects

Examples are part of GSM_AT_Lib_res repository. Refer to Clone resources repository with examples

Several examples are available to show application use cases. These are split and can be tested on different systems.

WIN32 examples

Library is developed under WIN32 system. That is, all examples are first developed and tested under WIN32, later ported to embedded application. Examples come with Visual Studio project. You may open project and directly run the example from there.

It may happen that Visual Studio sets different configuration on first project load and this may lead to wrong build and possible errors. Active configuration must be Debug and Win32 or x86. Default active build can be set in project settings.
SIM800 development board

For development purposes, SIM800 board is used with external battery + virtual COM port device (such as FTDI)

System functions for WIN32

Required system functions are based on "windows.h" file, available on windows operating system. Natively, there is support for:

  • Timing functions
  • Semaphores
  • Mutexes
  • Threads

The last part are message queues which are not implemented in Windows OS. Message queues were developed with help of semaphores and dynamic memory allocatations. System port for WIN32 is available in src/system/gsm_sys_win32.c file.

Low-level communication between SIM800 board and WIN32

Communication with SIM800 board hardware is using virtual files for COM ports. Implementation of low-level part (together with memory allocation for library) is available in src/system/gsm_ll_win32.c file.

In order to start using this port, user must set the appropriate COM port name when opening a virtual file. Please check implementation file for details.

ARM Cortex-M examples

Library is independant from CPU architecture, meaning we can also run it on embedded systems. Different ports for FreeRTOS operating system and STM32 based microcontrollers are available too.

STM32 boards and pinouts for tests
GSM target settings Debug settings
STM32F429ZI-Nucleo USART6 PC6 PC7 PC5 USART3 PD8 PD9 921600 OBSTL
  • MTX: MCU TX pin, other device RX pin
  • MRX: MCU RX pin, other device TX pin
  • RST: Reset pin from GSM device, connected to MCU
  • MDTX: MCU Debug TX pin, other device RX pin
  • MDRX: MCU Debug RX pin, other device TX pin
  • DBD: Debug UART baudrate
  • OBSTL: On-Board ST-Link USB virtual COM port
All examples for STM32 come with ST's official free development studio.

Porting guide

System structure

System structure organization

We can describe library structure in 4 different layers:

  • User application: User application is highest layer where entire code is implemented by user and where GSM AT library API functions are called from
  • GSM AT middleware: GSM AT middleware layer consists of API functions, thread management functions and all utilities necessary for smooth operation.
  • System functions: Layer where system dependant functions must be implemented, such as current time in milliseconds and all OS dependant functions for:

    • Managing threads
    • Managing semaphores
    • Managing mutexes
    • Managing message queues

    More about this part can be found in System functions section.

  • AT port communication functions or GSM LL: Part of code where user must take care of sending and receiving data from/to GSM AT lib to properly handle communication between host device and GSM device.

    More about this part can be found in Low-level functions section.

    Together with this section, user must implement part to input the received data from AT port.

  • GSM physical device: Actual ESP8266 or ESP32 device

Implementation specific part

Before usage, user must implement all functions in Low-level functions section as well as take care of proper communication with GSM device in Low-level functions section.

For more information about how to port, check sections accordingly

Library configuration

To make library as efficient as possible, different configuration parameters are available to make sure all the requirements are met for different purposes as possible.

A list of all configurations can be found in Configuration section.

Project configuration file

Library comes with 2 configuration files:

When project is started, user has to rename template file to gsm_config.h and if required, it should override default settings in this file.

Default template file comes with something like this:

/* Rename this file to "gsm_config.h" for your application */
* Open "include/gsm/gsm_config_default.h" and
* copy & replace settings you want to change here
/* After user configuration, call default config to merge config together */
#include "gsm/gsm_config_default.h"
#endif /* GSM_HDR_CONFIG_H */

In case user wants to increase default buffer size_t for received data, a file should be modified to something similar like code below:

/* Rename this file to "gsm_config.h" for your application */
/* Increase default receive buffer length */
#define GSM_RCV_BUFF_SIZE 0x800
/* After user configuration, call default config to merge config together */
#include "gsm/gsm_config_default.h"
#endif /* GSM_HDR_CONFIG_H */
Always modify default settings by overriding them in user's custom gsm_config.h file which was previously renamed from gsm_config_template.h

Inter-thread communication

In order to have very effective library from resources point of view, an inter-thread communication was introduced.

Inter-Thread communication between user and library.

Library consists of 2 threads working in parallel and bunch of different user threads.

User thread(s)

User thread is a place where user communicates with GSM AT library. When a new command wants to be executed to GSM device, user calls appropriate API function which will do following steps:

  • Allocate memory for command message from memory manager
  • Assign command type to message
  • Set other parameters, related or required to command
  • If user wants to wait for response (blocking mode), then create system semaphore sem and lock it immediatelly
  • Send everything to producing message queue which is later read in producing thread
  • If user don't want blocking mode, return from function with status OK otherwise wait for semaphore sem to be released from producing thread
    • When sem semaphore is locked, user thread may sleep and release resources for other threads this time
  • If user selects blocking mode, wait for response, free command memory in memory manager and return command response status

User may use different threads to communicate with GSM AT lib at the same time since memory manager is natively protected by mutex and producing queue is protected from multiple accesses by OS natively.

Producer thread

Producer threads reads message queue with user commands and sends initial AT command to AT port. When there is no commands from user, thread can sleep waiting for new command from user.

Once there is a command read from message queue, these steps are performed:

  • Check if processing function is set and if command is valid
  • Locks sync_sem semaphore for synchronization between processing and producing threads
  • Sends initial AT command to AT port according to command type
  • Waits for sync_sem to be ready again (released in processing thread)
  • If command was blocking, set result and unlock command sem semaphore
  • If command was not blocking, free command memory from memory manager

Process thread

Processing thread reads received data from AT port and processes them.

If command is active and received data belongs to command, they are processed according to command. If received data are not related to command (such as received network data +RECEIVE), they are also processed and callback function is immediatelly called to notify user about received data.

Here is a list of some URC (Unsolicited Result Code) messages:

  • Received network data +RECEIVE
  • Connection just active x, CONNECT OK
  • New SMS received, +CMTI
  • ...

All these commands must be reported to user. To do this, callback is triggered to notify user.

Events and callback functions

To make library very efficient, events and callback functions are implemented. They are separated in different groups.

Global event function

This is a callback function for all implemented major events, except events related to Connection API. User may implement all cases from gsm_evt_type_t enumeration except those which start with GSM_CONN_.

This callback is set on first stack init using gsm_init function. If later application needs more event functions to receive all events, user may register/unregister new functions using gsm_evt_register and gsm_evt_unregister respectively.

Events which can be implemented:

  • Received network data +RECEIVE
  • Connection just active x, CONNECT OK
  • New SMS received, +CMTI
  • ...

Connection event function

To optimize application related to connections and to allow easier implementation of different modules, each connection has an option to implement custom callback function for connection related events.

User may implement all cases from gsm_evt_type_t enumeration which start with GSM_CONN_.

Callback function is set when connection is started as client using gsm_conn_start

Events which can be implemented:

  • Connection active
  • Connection data received
  • Connection data sent
  • Connection closed
  • ...

Temporary event for API functions

When API function (ex. gsm_sms_send) directly interacts with device using AT commands, user has an option to set callback function and argument when command finishes.

This feature allows application to optimize upper layer implementation when needed or when command is executed as non-blocking API call. Read sect_block_nonblock_commands section for more information

Blocking and non-blocking commands

When API function needs to interact with device directly before valid data on return, user has an option to execute it in blocking or non-blocking mode.

Blocking mode

In blocking mode, function will block thread execution until response is received and ready for further processing. When the function returns, user has known result from GSM device.

  • Linear programming style may be applied when in thread
  • User may need to use multiple threads to execute multiple features in real-time
Example code
/* Somewhere in thread function */
/* Get device hostname in blocking mode */
/* Function returns actual result */
if (gsm_sms_send("+0123456789", "text", NULL, NULL, 1 /* 1 means blocking call */) == gsmOK) {
/* At this point we have valid result from device */
printf("SMS sent successfully\r\n");
} else {
printf("Error trying to send SMS..\r\n");
It is not allowed to call API function in blocking mode from other GSM event functions. Any attempt to do so will result in function returning gsmERRBLOCKING.

Non-blocking mode

In non-blocking mode, command is created, sent to producing message queue and function returns without waiting for response from device. This mode does not allow linear programming style, because after non-blocking command, callback function is called.

Full example for connections API can be found in Connection API section.

Example code
/* Hostname event function, called when gsm_sms_send() function finishes */
sms_send_fn(gsmr_t res, void* arg) {
/* Check actual result from device */
if (res == gsmOK) {
printf("SMS sent successfully\r\n", hostname);
} else {
printf("Error trying to send SMS..\r\n");
/* Somewhere in thread and/or other GSM event function */
/* Send SMS in non-blocking mode */
/* Function now returns if command has been sent to internal message queue */
if (gsm_sms_send(hostname, sizeof(hostname), sms_send_fn, NULL, 0 /* 0 means non-blocking call */) == gsmOK) {
/* At this point we only know that command has been sent to queue */
printf("SMS send message sent to queue.\r\n");
} else {
/* Error writing message to queue */
printf("Cannot send SMS send message to queue. Maybe out of memory? Check result from function\r\n");
When calling API functions from any event function, it is not allowed to use blocking mode. Any attempt to do so will result in function returning gsmERRBLOCKING.