RaspberrPi project source code
guowenxue
2023-09-07 13d8a8696ac5b5b505be20f428fe64e22a134016
commit | author | age
d6b4a7 1 /*********************************************************************************
G 2  *      Copyright:  (C) 2023 LingYun IoT System Studio.
3  *                  All rights reserved.
4  *
5  *       Filename:  atcmd.c
6  *    Description:  This file is lowlevel AT command send and parser API functions
7  *                 
8  *        Version:  1.0.0(11/08/23)
9  *         Author:  Guo Wenxue <guowenxue@gmail.com>
10  *      ChangeLog:  1, Release initial version on "11/08/23 16:18:43"
11  *                 
12  ********************************************************************************/
13
14 #include <ctype.h>
15 #include "logger.h"
16 #include "atcmd.h"
17
18 /*  Description: this function used to send an AT command from serial port and wait for reply message from
19  *               the communication module, and it will return once get expet/error string or timeout.
20  *
21  *    Arugments:
22  *         $comport: the serial port which connected to GPRS/3G/4G/NB-IoT/WiFi/BLE/Zigbee/LoRa...
23  *              $at: the AT command need to be sent, without "\r\n"
24  *         $timeout: wait for module reply for AT command timeout value, unit micro seconds(ms)
25  *          $exepct: the expect string reply from communication module
26  *           $error: the error string reply from communication module
27  *           $reply: the module reply message output buffer
28  *            $size: the output buffer ($reply) size
29  *
30  * Return value: <0: Function error   0: Got error string   1: Got expect string 2: Receive util timeout
31  *
32  */
33
34 int send_atcmd(comport_t *comport, char *at, unsigned long timeout, char *expect, char *error, char *reply, int size)
35 {
36     int                    i, rv = 0;
37     int                    res = ATRES_TIMEOUT;
38     int                    bytes = 0;
39     char                   buf[ATCMD_REPLY_LEN] = {'\0'};
40     char                   atcmd[ATCMD_LEN] = {'\0'};
41
42     if( !comport || !at )
43     {
44         log_error("Invalid input arguments\n");
45         return -1;
46     }
47
48     if( comport->fd <= 0 )
49     {
50         log_error("comport[%s] not opened\n");
51         return -2;
52     }
53
54     /* flushes both data received but not read, and data written but not transmitted in serial port */
55     tcflush(comport->fd, TCIOFLUSH);
56
57     snprintf(atcmd, sizeof(atcmd), "%s%s", at, AT_SUFFIX);
58     rv=comport_send( comport, atcmd, strlen(atcmd) );
59     if(rv < 0)
60     {
61         log_error("send AT command \"%s\" to \"%s\" failed, rv=%d\n", at, comport->devname, rv);
62         return -3;
63     }
64
65     res = ATRES_TIMEOUT;
66     memset( buf, 0, sizeof(buf) );
67
68     for(i=0; i<timeout/10; i++)
69     {
70         if( bytes >= sizeof(buf) )
71             break;
72
73         rv=comport_recv( comport, buf+bytes, sizeof(buf)-bytes, 10);
74         if(rv < 0)
75         {
76             log_error("send AT command \'%s\' to \'%s\' failed, rv=%d\n", at, comport->devname, rv);
77             return -3;
78         }
79
80         bytes += rv;
81
82         if( expect && strstr(buf, expect) )
83         {
84             log_debug("send AT command \"%s\" and got reply \"OK\"\n", at);
85             res = ATRES_EXPECT;
86             break;
87         }
88
89         if( error && strstr(buf, error) )
90         {
91             log_debug("send AT command \"%s\" and got reply \"ERROR\"\n", at);
92             res = ATRES_ERROR;
93             break;
94         }
95     }
96
97     if( bytes > 0 )
98         log_trace("AT command reply:%s", buf);
99
100     if( reply && size>0 )
101     {
102         bytes = strlen(buf)>size ? size : strlen(buf);
103         memset(reply, 0, size);
104         strncpy(reply, buf, bytes);
105
106         log_debug("copy out AT command \"%s\" reply message: \n%s", at, reply);
107     }
108
109     return res;
110 }
111
112
113 /*
114  *  Description: Send AT command which will only reply by "OK" or "ERROR", such as AT:
115  *                 Reply:   \r\nOK\r\n
116  * Return Value: 0: OK     -X: Failure
117  */
118 int send_atcmd_check_ok(comport_t *comport, char *at, unsigned long timeout)
119 {
120     int                     rv;
121
122     if( !comport || !at )
123     {
124         log_error("Invalid input arguments\n");
125         return -1;
126     }
127
128     rv=send_atcmd(comport, at, timeout, AT_OKSTR, AT_ERRSTR, NULL, 0);
129     if( ATRES_EXPECT == rv )
130     {
131         return 0;
132     }
133     else
134     {
135         return -2;
136     }
137 }
138
139
140 /*
141  *  Description: Send AT command which will reply by a value directly in a single line, such as AT+CGMM:
142  *                  Reply:   \r\nEC20F\r\nOK\r\n
143  *
144  * Return Value: 0: OK     -X: Failure
145  */
146 int send_atcmd_check_value(comport_t *comport, char *at, unsigned long timeout, char *reply, int size)
147 {
148     int                     rv, len;
149     char                    buf[ATCMD_REPLY_LEN];
150     char                   *ptr_start = buf;
151     char                   *ptr_end;
152
153     if( !comport || !at || !reply || size<=0 )
154     {
155         log_error("Invalid input arguments\n");
156         return -1;
157     }
158
159     rv = send_atcmd(comport, at, timeout, AT_OKSTR, AT_ERRSTR, buf, ATCMD_REPLY_LEN);
160     if( rv <= 0 )
161     {
162         return -2;
163     }
164
165     /* Skip the echo back command line */
166     if( !strncmp(buf, at, strlen(at)) )
167     {
168         ptr_start=strchr(buf, '\n');
169         if( !ptr_start )
170         {
171             log_error("reply message got wrong\n");
172             return -3;
173         }
174
175         ptr_start++;   /* skip '\n'  */
176     }
177
178     /* find end reply string "\r\nOK\r\n"  */
179     ptr_end = strstr(ptr_start, AT_OKSTR);
180     if( ptr_end )
181     {
182         len = ptr_end - ptr_start;
183     }
184     else
185     {
186         len = strlen(buf) - (ptr_start-buf);
187     }
188
189     memset(reply, 0, size);
190
191     len = len>size ? size : len;
192     memcpy(reply, ptr_start, len);
193
194     return 0;
195 }
196
197 /*
198  *  Description: Parser the $value from $key like "xxx: " line, such as AT+CSQ:
199  *                  Reply:   \r\n+CSQ: 26,99\r\nOK\r\n
200  *
201  * Return Value: 0: OK     -X: Failure
202  */
203 int parser_request_value(char *buf, char *key, char *value, int size)
204 {
205     char                   *ptr;
206     int                    i = 0;
207
208     if( !buf || !key || !value || size<=0 )
209     {
210         log_error("Invalid input arguments\n");
211         return -1;
212     }
213
214     ptr = strstr(buf, key);
215     if( !ptr )
216     {
217         log_debug("Not found key \"%s\" in %s\n", key, buf);
218         return -2;
219     }
220
221     ptr=strchr(ptr, ':');  /* found ':' before the value */
222     if( !ptr )
223     {
224         log_debug("Not found ':' before value\n");
225         return -3;
226     }
227     ptr++;   /* skip ':'  */
228
229     if( *ptr == '\"' ) /* skip " */
230         ptr++;
231
232     memset(value, 0, size);
233     while(*ptr!='\r' && i<size-1)
234     {
235         if( !isspace(*ptr) && *ptr!='\"') /* skip space,\r,\n ...  */
236             value[i++] = *ptr;
237         ptr ++;
238     }
239
240     ptr++; /* skip  */
241
242     return 0;
243 }
244
245 /*
246  *  Description: Send AT command which will reply by the value  with a prefix "+CMD: " line, such as AT+CSQ:
247  *                  Reply:   \r\n+CSQ: 26,99\r\nOK\r\n
248  *
249  * Return Value: 0: OK     -X: Failure
250  */
251 int send_atcmd_check_request(comport_t *comport, char *at, unsigned long timeout, char *reply, int size)
252 {
253     int                     i = 0;
254     int                     rv;
255     char                    buf[ATCMD_REPLY_LEN];
256     char                   *ptr;
257
258     if( !comport || !at || !reply || size<=0 )
259     {
260         log_error("Invalid input arguments\n");
261         return -1;
262     }
263
264     rv = send_atcmd(comport, at, timeout, AT_OKSTR, AT_ERRSTR, buf, ATCMD_REPLY_LEN);
265     if( rv <= 0 )
266     {
267         return -2;
268     }
269
270     ptr=strchr(buf, '+');  /* found '+' before the value */
271     if( !ptr )
272     {
273         log_error("reply message got wrong\n");
274         return -3;
275     }
276     ptr++;   /* skip '+'  */
277
278
279     ptr=strchr(buf, ':');  /* found ':' before the value */
280     if( !ptr )
281     {
282         log_error("reply message got wrong\n");
283         return -3;
284     }
285     ptr++;   /* skip ':'  */
286
287     if( *ptr == '\"' ) /* skip " */
288         ptr++;
289
290     memset(reply, 0, size);
291     while(*ptr!='\r' && i<size-1)
292     {
293         if( !isspace(*ptr) && *ptr!='\"') /* skip space,\r,\n ...  */
294             reply[i++] = *ptr;
295         ptr ++;
296     }
297
298     return 0;
299 }
300