Fundamentals 9 min read

Mastering AT Command Parsing: Build Bare‑Metal and OS‑Based Communication Modules

This article introduces an AT‑command communication parsing module that supports both bare‑metal (at_chat) and OS‑based versions, explains its software architecture, core data structures, key interfaces, and provides step‑by‑step usage examples with complete C code snippets for Wi‑Fi, Bluetooth, and modem integration.

Open Source Linux
Open Source Linux
Open Source Linux
Mastering AT Command Parsing: Build Bare‑Metal and OS‑Based Communication Modules

Introduction

A versatile AT‑command communication parsing module that supports a bare‑metal version (at_chat) and an OS‑based version (at). It is suitable for modems, Wi‑Fi modules, and Bluetooth communication.

Software Architecture

at_chat.c, at_chat.h, list.h

The bare‑metal version uses a chained queue and asynchronous callbacks to handle AT command transmission and reception, supporting URC handling and custom command parsing.

at.c, at.h, at_util.h, comdef.h

The OS version requires porting of OS‑specific interfaces defined in at_util.h, such as semaphore operations and task delays.

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:

/*AT job item*/
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;

Jobs are statically allocated; by default, ten job items are available, allowing up to ten AT commands to be queued simultaneously.

Basic Interfaces

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

at_send_multiline – send multi‑line command, same default behavior.

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 detailed usage.

Usage Steps

Define the AT controller and communication adapter interfaces.

/* @brief   Define AT controller */
static at_obj_t at;

const at_adapter_t adap = {
    // write and read functions for the GPRS module's UART
    .write = uart_write,
    .read  = uart_read,
    // ... other fields
};

Initialize the AT controller and register a polling task (e.g., every 20 ms).

/* @brief wifi initialization */
void wifi_init(void) {
    at_obj_init(&at, &adap);
    /* ... */
}

driver_init("wifi", wifi_init);

/* @brief wifi task (10 ms polling) */
void wifi_task(void) {
    at_poll_task(&at);
}

task_register("wifi", wifi_task, 10);

Example Command

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

<= OK
/**
 * @brief AT execution callback handler
 */
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 is complex in non‑OS environments, this module is recommended for scenarios where blocking is not allowed; it relies on state machines and callbacks.

Basic Interfaces

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

at_split_respond_lines – splits command responses.

at_do_work – suitable for composite commands such as sending SMS or socket data that require waiting for prompts like "CONNECT".

Usage Steps

Define the AT controller and adapter, including URC callback table and buffers.

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,
};

Create the AT controller and start a polling thread.

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 signal quality */
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 – send data via TCP */
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 MetalCommunication ProtocolAT commandsOS 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.