Fundamentals 8 min read

Mastering AT Command Parsing: A Comprehensive Guide to Embedded Communication Modules

This guide details a lightweight AT command parsing module supporting both bare‑metal and OS versions, explains its architecture, core data structures, key APIs, and provides step‑by‑step usage examples—including GPIO testing, signal‑quality queries, and TCP data transmission—for modems, Wi‑Fi and Bluetooth communication.

Open Source Linux
Open Source Linux
Open Source Linux
Mastering AT Command Parsing: A Comprehensive Guide to Embedded Communication Modules

Introduction

A lightweight AT command communication parsing module that supports both bare‑metal (at_chat) and OS‑based (at) versions, suitable for modems, Wi‑Fi and Bluetooth communication.

Software Architecture

at_chat.c, at_chat.h, list.h – for the no‑OS version, using a chained queue and asynchronous callbacks to handle AT command transmission, URC processing, and custom command jobs.

at.c, at.h, at_util.h, comdef.h – for the OS version; requires porting of OS‑specific interfaces such as semaphores and task delays as defined in at_util.h.

Usage Instructions – at_chat Module (No‑OS)

Basic Concept

The at_chat module manages two linked lists: a free list and a ready list. Each job item is defined as follows:

typedef struct {
    unsigned int state : 3;
    unsigned int type  : 3; /* job type */
    unsigned int abort : 1;
    void *param;            /* generic parameter */
    void *info;             /* generic info pointer */
    struct list_head node;  /* list node */
} at_item_t;

The module pre‑allocates ten job items, allowing up to ten AT commands to be queued simultaneously.

Basic Interfaces

at_send_singlline – send a single‑line command, waits for “OK”, timeout 3 s.

at_send_multiline – send multi‑line command, waits for “OK”, timeout 3 s.

at_do_cmd – custom send format with response matching.

at_do_work – custom send and receive parsing.

Demo

Refer to the demo program wifi_task.c for a complete usage example.

Example: Send GPIO Test Command

//WIFI IO configuration command
=> AT+GPIO_TEST_EN=1

<= OK
static void test_gpio_callback(at_response_t *r)
{
    if (r->ret == AT_RET_OK) {
        printf("Execute successfully
");
    } else {
        printf("Execute failure
");
    }
}
at_send_singlline(&at, test_gpio_callback, "AT+GPIO_TEST_EN=1");

at Module (OS Version)

Because AT command communication can be complex in a non‑OS environment, this module is recommended for scenarios where blocking is not allowed.

Basic Interfaces

at_do_cmd – execute an AT command; can be wrapped for common single‑line or multi‑line commands.

at_split_respond_lines – split command responses.

at_do_work – handle composite commands such as SMS sending or socket data transmission that require waiting for prompts like “CONNECT”.

Usage Steps

Define the AT controller and communication adapter (including URC callback table and buffer).

Create the AT controller and start a polling thread.

static at_obj_t at;          // AT controller object
static char urc_buf[128];    // URC buffer
utc_item_t utc_tbl[] = {
    "+CSQ: ", csq_updated_handler
};
const at_adapter_t adap = {
    .urc_buf = urc_buf,
    .urc_bufsize = sizeof(urc_buf),
    .utc_tbl = utc_tbl,
    .urc_tbl_count = sizeof(utc_tbl) / sizeof(utc_item_t),
    .debug = at_debug,
    .write = uart_write,
    .read = uart_read
};
void at_thread(void)
{
    at_obj_create(&at, &adap);
    while (1) {
        at_process(&at);
    }
}

Example 1 – Query Signal Quality

/** at_do_cmd usage demo
    Query GPRS module signal quality
    => AT+CSQ
    <= +CSQ: 24,0
    <= OK
*/
bool read_csq_value(at_obj_t *at, int *rssi, int *error_rate)
{
    unsigned char recvbuf[32];
    at_respond_t r = {"OK", recvbuf, sizeof(recvbuf), 3000};
    if (at_do_cmd(at, &r, "AT+CSQ") != AT_RET_OK)
        return false;
    return (sscanf(recv, "%*[^+]+CSQ: %d,%d", rssi, error_rate) == 2);
}

Example 2 – Send TCP Data

/** at_do_work usage demo – HL8518 module socket data send
    => AT+KTCPSND=<session_id>,<ndata>
    <= CONNECT
    => <data>
    <= OK
*/
static bool socket_send_handler(at_work_ctx_t *e)
{
    struct socket_info *i = (struct socket_info *)e->params;
    struct ril_sock *s = i->s;
    if (s->type == SOCK_TYPE_TCP)
        e->printf(e, "AT+KTCPSND=%d,%d", s->session, i->bufsize);
    else
        e->printf(e, "AT+KUDPSND=%d,%s,%d,%d", s->session, s->host,
                  s->port, i->bufsize);
    if (e->wait_resp(e, "CONNECT", 5000) != AT_RET_OK)
        goto Error;
    e->write(i->buf, i->bufsize);
    e->write("--EOF--Pattern--", strlen("--EOF--Pattern--"));
    if (e->wait_resp(e, "OK", 5000) == AT_RET_OK)
        return true;
Error:
    e->write("--EOF--Pattern--", strlen("--EOF--Pattern--"));
    return false;
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

C programmingembedded systemsBare MetalAT commandscommunication moduleOS integration
Open Source Linux
Written by

Open Source Linux

Focused on sharing Linux/Unix content, covering fundamentals, system development, network programming, automation/operations, cloud computing, and related professional knowledge.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.