Odd behavior when communicating with RM520NGL over serial

Hello,

I have a simple C program im using to establish a serial connection to my modem.. Im using ttyUSB2 @ 115200 baud. My commands end with \r

Its hard to explain this behavior.. I’m having to send commands twice to get the response.. it first echos back the last command i sent.. Here’s an example:
root@OpenWrt:/usr/bin# ./atcmd /dev/ttyUSB2 at
MODEM REPLY:
ati ← this was the command sent before the above at command. Lets try again, new command
root@OpenWrt:/usr/bin# ./atcmd /dev/ttyUSB2 at+qcainfo
MODEM REPLY:
Quectel
RM520N-GL
Revision: RM520NGLAAR03A04M4G
OK
at
OK

Does anyone have any idea whats going on? I’m seeing the same behavior with another application that also sends commands via serial to the modem..

example input: ./atcmd /dev/ttyUSB2 at
Program:

char buf[256];
memset(buf, 0, sizeof(buf));
strncpy(buf, argv[2],strlen(argv[2]));
strncat(buf,“\r”,2);
write(serial_port, buf, strlen(buf));

char buffer[512];
memset(buffer, 0, sizeof(buffer));
int n = read(serial_port, buffer, sizeof(buffer) - 1);
if (n > 0) {
printf(“%s”, buffer);
}

Before you send the AT command
You should

  1. Disable the echo with AT command ATE0.
    2.Initialize the serial port

    stty -F /dev/ttyUSB2 115200 cs8 -parenb -cstopb -echo -icanon raw

 #include <sys/types.h>
 #include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char*argv[]){


        char buf[256];
        memset(buf, 0, sizeof(buf));

            if (argc != 3){
                printf("Usage: %s <device> <command>\n", argv[0]);
                return 1;
          }

        int serial_port = open(argv[1], O_RDWR | O_NOCTTY | O_SYNC);

        strncpy(buf, argv[2],strlen(argv[2]));

        strncat(buf,"\r",1);

        write(serial_port,buf,strlen(buf));

        char buffer[512];

        memset(buffer, 0, sizeof(buffer));

        int n = read(serial_port, buffer, sizeof(buffer) - 1);
        if (n > 0) {
                printf("%s\r", buffer);
        }

        return 0;
}

Thanks, i’m setting those parameters when I open the serial port.

I did try your suggestion, I was seeing the same result. What did work was this:
where argv[1] is “/dev/ttyUSB2”

char purge[256];
sprintf(purge,"cat %s & kill -9 $!",argv[1]);
system(purge);

int serial_port = open(argv[1], O_RDWR | O_NOCTTY | O_SYNC);
...

This basically reads whatever is on the modems end and discards it before I connect..
I’m not sure whats going on.. tcflush(serial_port, TCIOFLUSH); had zero effect..

Normally we would like to use the termios API to initialize the serial device.
I think you didn’t try the
stty -F /dev/ttyUSB2 115200 cs8 -parenb -cstopb -echo -icanon raw

Or you can the example

gcc test_AT.c -o test_AT -lpthread

// test_AT.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/select.h>
#include <termios.h>
#include <string.h>
#include <semaphore.h>

static int timeoutVal = 10;

static int waitsecond = 1;

static char Version[100] = "Q-v0.1";

sem_t my_semaphore; // 定义一个信号量

int xget1(int fd, struct termios *tio, struct termios *tiosfd) {
    if (tcgetattr(fd, tio) < 0) {
        perror("tcgetattr failed");
        return -1;
    }
    *tiosfd = *tio;  // Save the current settings
    return 0;
}

int xset1(int fd, struct termios *tio, const char *dev) {
    if (tcsetattr(fd, TCSANOW, tio) < 0) {
        perror("tcsetattr failed");
        return -1;
    }
    return 0;
}

int main(int argc, char **argv)
{
    int i;
    int fd;
    int ret;
    char buffer[409600] = {0};
    int rate;
    char* sendbuffer;
    int totallen = 0;
    fd_set readfds;
    struct timeval timeout;
    struct termios tio0, tiosfd, tio;
    (void)tio0;

   for (i = 1; i < argc; i++) {
        printf("argv[%d]: %s\n",i, argv[i]);
   }

    for (i = 1; i < argc; i++)
    {
        if (argc > 2 && !strcmp(argv[i], "-version"))
        {
            printf("%s Version is %s\n", argv[0], Version);
            printf("Usage: %s <dev> <baudrate> [timeout [waitsecond]] <atcmd>\n", argv[0]);
            printf("For example:\n (1)%s /dev/ttyUSB2 115200 \"ATI\"\n (2)%s -version\n", argv[0], argv[0]);
            exit(0);
        }
    }

    if (argc == 2 && !strcmp(argv[1], "-version"))
    {
        printf("%s Version is %s\n", argv[0], Version);
        exit(0);
    }

    if (argc != 4 && argc != 5 && argc != 6)
    {
        printf("Usage: %s <dev> <boundrate> [timeout [waitsecond]] <atcmd>\n", argv[0]);
        printf("For example:\n (1)%s /dev/ttyUSB2 115200 \"ATI\"\n (2)%s -version\n", argv[0], argv[0]);
        exit(1);
    }

    char *dev = argv[1];
    rate = atoi(argv[2]);


    if (argc == 4)
        sendbuffer = argv[3]; 
    else if (argc == 5)
    {
        timeoutVal = atoi(argv[3]);
        sendbuffer = argv[4];
    }
    else
    {
        timeoutVal = atoi(argv[3]);
        waitsecond = atoi(argv[4]);
        sendbuffer = argv[5];
    }

    // 初始化信号量(如果未初始化)
    if (sem_init(&my_semaphore, 0, 1) != 0)
    {
        perror("sem_init failed");
        exit(1);
    }

    // 等待信号量
    if (sem_wait(&my_semaphore) != 0)
    {
        perror("sem_wait failed");
        exit(1);
    }

   printf("%d %d\n", timeoutVal, waitsecond);

    fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (fd < 0)
        goto ERR;
    fcntl(fd, F_SETFL, O_RDWR);

    // put device to "raw mode"
    xget1(fd, &tio, &tiosfd);

    cfsetspeed(&tio, 115200);
    if (xset1(fd, &tio, dev))
        goto ERR;

    tcflush(fd, TCIOFLUSH);

    // printf("### %d  waitseconnd : %d###\n",__LINE__, waitsecond);
    if (waitsecond > 0)
        sleep(waitsecond);

    sprintf(buffer, "%s\r", sendbuffer);
    ret = write(fd, buffer, strlen(buffer));
    if (ret < 0)
    {
        printf("write failed\n");
        goto ERR;
    }

    FD_ZERO(&readfds);
    FD_SET(fd, &readfds);

    while (1)
    {
        timeout.tv_sec = timeoutVal;
        timeout.tv_usec = 0;

        ret = select(fd + 1, &readfds, NULL, NULL, &timeout);
        if (ret > 0)
        {
            ret = read(fd, buffer + totallen, sizeof(buffer) - totallen - 1);
            if (ret < 0)
            {
                printf("read failed\n");
                goto ERR;
            }

            if (ret == 0)
            {
                goto ERR;
            }

            totallen += ret;
            buffer[totallen] = '\0';

            if (strstr(buffer, "\nOK") || strstr(buffer, "\nERROR") || strstr(buffer, "\n+CME ERROR:") || strstr(buffer, "\n+CMS ERROR:"))
            {
                break;
            }
        }
        else
        {
            printf("select timeout\n");
            goto ERR;
        }
    }

    tcsetattr(fd, TCSAFLUSH, &tiosfd);
    printf("%s\n", buffer);

    // 释放信号量
    if (sem_post(&my_semaphore) != 0)
    {
        perror("sem_post failed");
        exit(1);
    }

    close(fd);
    exit(0);

ERR:
    if (fd > 0)
        close(fd);

    // 释放信号量
    if (sem_post(&my_semaphore) != 0)
    {
        perror("sem_post failed");
        exit(1);
    }

    exit(1);
}