arissajonny
arissajonny

Reputation: 33

How to create AT Commands Parser in C to get the incoming string from USART1?

I want to get the string from USART1 of STM32VLDiscovery (STM32F100X4) and write an AT Command Parser from the string received from USART1.

Below are the concept that I have developed but I am not sure whether it's correct or not.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "dosomethinga.h"

void dosomethingB();
void GET_AT_COMMAND(char*);
void takecommand(char *, char *);
int quit;


int main()
{   char buff[15];
    char command = '\0';
    quit = 0;

    while(!quit)
    {
        printf("Enter your command: ");
        scanf("%s", &buff);

        if (buff[0] == 'A' && buff[1] == 'T' && buff[2] == '+')
        {
            GET_AT_COMMAND(buff);
        }

    }
}

void dosomethingB()
{
    printf("dosomethingB called \n");
}

void GET_AT_COMMAND(char *text)
{
    int command;
    char temp[10] = "";

    /*if(text[3] == 'A')
          command = 1;

    else if(text[3] == 'B')
        command = 2;

    else if(text[3] == 'Z')
        command = 3;
    */

    takecommand(text,temp);

    if (strcmp(temp, "CALLA") == 0)
        command = 1;

    if (strcmp(temp, "CALLB") == 0)
        command = 2;

    if (strcmp(temp, "Z") == 0)
        command = 3;

    switch(command)
    {
        case 1:
            dosomethingA();
            break;

        case 2:
            printf("herehere.... \n");
            dosomethingB();
            break;

        case 3:
            printf("Exiting program.... \n");
            quit = 1;
            break;


        default:
            printf("Nothing to do here \n");
     }
}

void takecommand(char *mycmd, char *hold)
{
    int i;
    for(i = 0; i < 10 ; i++)
    {
         hold[i] = mycmd[i+3];
    }
}

Can anyone explain on the steps that I should do? Thanks.

Upvotes: 2

Views: 18121

Answers (2)

Tim
Tim

Reputation: 3803

I have developed this AT command parser, this could be use for reference.

When you get data from UART1 just call this method at_wait_msg() to parse the AT message

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

static const char *AT_HEADER = "AT";
static const char *AT_DEVICE_PROFILE = "DR";
static const char *AT_SET_DEVICE = "SD";

static const char AT_EOF = '\r';

typedef enum {
    DeviceProfile,
    SetDevice,
    Error
} AT_Msg_Type;

typedef struct {
    char header[3];
    char command[3];
    char data[128];
} AT_Msg_Data;

static void at_wait_msg(char text);
static void at_wait_msg_complete(char *text);
static void at_parse_msg(AT_Msg_Data *data);
static AT_Msg_Type at_check_format(AT_Msg_Data *data);

static char _rx_data[512];
static uint16_t _rx_index = 0;

int main()
{
    //example data getting from UART1
    char text[] = "ATDR\rATSD123456abchelloworld\r1123ATssa\r";

    for (int i = 0; i < strlen(text) + 1; i++) {
        //to simulate getting data from UART1 byte per byte
        at_wait_msg(text[i]);
    }

    return 0;
}

static void at_wait_msg(char text)
{
    _rx_data[_rx_index++] = text;

    if (text == AT_EOF) {
        at_wait_msg_complete(_rx_data);

        _rx_index = 0;      
    }
}

static void at_wait_msg_complete(char *text)
{
    AT_Msg_Data data;

    int result = sscanf_s(_rx_data, "%2s%2s%s\r",
        data.header, sizeof(data.header),
        data.command, sizeof(data.command),
        data.data, sizeof(data.data));

    if (result >= 2) {
        at_parse_msg(&data);
    }
}

static void at_parse_msg(AT_Msg_Data *data)
{
    AT_Msg_Type type = at_check_format(data);

    switch (type) {
    case DeviceProfile:
        printf("device profile\r\n");
        break;
    case SetDevice:
        printf("settings %s\r\n", data->data);
        break;
    case Error:
    default:
        printf("Error\r\n");
        break;
    }
}

static AT_Msg_Type at_check_format(AT_Msg_Data *data)
{
    if (strcmp(data->header, AT_HEADER) != 0) {
        return Error;
    }

    if (strcmp(data->command, AT_DEVICE_PROFILE) == 0) {
        return DeviceProfile;
    }

    if (strcmp(data->command, AT_SET_DEVICE) == 0) {
        return SetDevice;
    }

    return Error;
}

Upvotes: 2

SKi
SKi

Reputation: 8466

Basicly you should wait an attention "AT" from the input and ignore anything before it. For example inputs "XYZATZ\r" and "AaatZ\r" should be both handled as a "ATZ" command. There can also be short pause between 'A' and 'T' (and all other chars of commands too), because human may type those commands.

By the default all commands end to "\r" character.

See more about AT commands from ITU-T documentation. For example from V.250 standard.

There are probably many alternative ways to implement that. The best alternative depends on your needs. If you are going to implement all AT-commands of mobile-terminal, then you should spend more time for the parser. If you want make some test application for few commands, then your implementation could be simple as your provided one.

Upvotes: 2

Related Questions