/********************************************************************** * Copyright: (C)2023 LingYun IoT System Studio * Author: GuoWenxue QQ: 281143292 * Description: AT command send/receive low level API * * ChangeLog: * Version Date Author Description * V1.0.0 2023.04.3 GuoWenxue Release initial version ***********************************************************************/ #include #include #include "atcmd.h" /* Description: this function used to send an AT command from serial port and wait for reply message from * the communication module, and it will return once get expet/error string or timeout. * * Arugments: * $comport: the serial port which connected to GPRS/3G/4G/NB-IoT/WiFi/BLE/Zigbee/LoRa... * $at: the AT command need to be sent, without "\r\n" * $timeout: wait for module reply for AT command timeout value, unit micro seconds(ms) * $exepct: the expect string reply from communication module * $error: the error string reply from communication module * $reply: the module reply message output buffer * $size: the output buffer ($reply) size * * Return value: <0: Function error 0: Got expect string 1: Got error string 2: Receive until timeout * */ int send_atcmd(comport_t *comport, char *at, unsigned long timeout, char *expect, char *error, char *reply, int size) { int rv = 0; int res = ATRES_TIMEOUT; int bytes = 0; char buf[ATCMD_REPLY_LEN] = {'\0'}; char atcmd[ATCMD_LEN] = {'\0'}; if( !comport || !at ) { log_error("Invalid input arguments\n"); return -1; } if( comport->fd <= 0 ) { log_error("comport[%s] not opened\n", comport->devname); return -2; } /* flushes receive stream buffer */ //xStreamBufferReset(comport->xRxStreamBuffer); snprintf(atcmd, sizeof(atcmd), "%s%s", at, AT_SUFFIX); rv=comport_send( comport, atcmd, strlen(atcmd) ); if(rv < 0) { log_error("send command \"%s\" to \"%s\" failed, rv=%d\n", at, comport->devname, rv); return -3; } memset( buf, 0, sizeof(buf) ); rv=comport_recv( comport, buf, sizeof(buf), timeout); if(rv < 0) { log_error("Wait for command \'%s\' reply failed, rv=%d\n", at, rv); return -4; } else if(rv == 0) { log_error("Wait for command \'%s\' reply timeout\n", at); return ATRES_TIMEOUT; } if( error && strstr(buf, error) ) { log_debug("send command \"%s\" and got reply \"ERROR\"\n", at); return ATRES_ERROR; } if( expect && strstr(buf, expect) ) { log_debug("send command \"%s\" and got reply \"OK\"\n", at); res = ATRES_EXPECT; } if( reply && size>0 ) { bytes = strlen(buf)>size ? size : strlen(buf); memset(reply, 0, size); strncpy(reply, buf, bytes); log_debug("copy out command \"%s\" reply message: \n%s", at, reply); } return res; } /* * Description: Send AT command which will only reply by "OK" or "ERROR", such as AT: * Reply: \r\nOK\r\n * Return Value: 0: OK -X: Failure */ int send_atcmd_check_ok(comport_t *comport, char *at, unsigned long timeout) { int rv; if( !comport || !at ) { log_error("Invalid input arguments\n"); return -1; } rv=send_atcmd(comport, at, timeout, AT_OKSTR, AT_ERRSTR, NULL, 0); if( ATRES_EXPECT == rv ) { return 0; } else { return -2; } } /* * Description: Send AT command which will reply by a value directly in a single line, such as AT+CGMM: * Reply: \r\nEC20F\r\nOK\r\n * * Return Value: 0: OK -X: Failure */ int send_atcmd_check_value(comport_t *comport, char *at, unsigned long timeout, char *reply, int size) { int rv, len; char buf[ATCMD_REPLY_LEN]; char *ptr_start = buf; char *ptr_end; if( !comport || !at || !reply || size<=0 ) { log_error("Invalid input arguments\n"); return -1; } rv = send_atcmd(comport, at, timeout, AT_OKSTR, AT_ERRSTR, buf, ATCMD_REPLY_LEN); if( ATRES_EXPECT != rv ) { log_error("send AT command \"%s\" failed, rv=%d\n", at, rv); return -2; } /* Skip the echo back command line */ if( !strncmp(buf, at, strlen(at)) ) { ptr_start=strchr(buf, '\n'); if( !ptr_start ) { log_error("reply message got wrong\n"); return -3; } ptr_start++; /* skip '\n' */ } /* find end reply string "\r\nOK\r\n" */ ptr_end = strstr(ptr_start, AT_OKSTR); if( ptr_end ) { len = ptr_end - ptr_start; } else { len = strlen(buf) - (ptr_start-buf); } memset(reply, 0, size); len = len>size ? size : len; memcpy(reply, ptr_start, len); return 0; } /* * Description: Parser the $value from $key like "xxx: " line, such as AT+CSQ: * Reply: \r\n+CSQ: 26,99\r\nOK\r\n * * Return Value: 0: OK -X: Failure */ int parser_request_value(char *buf, char *key, char *value, int size) { char *ptr; int i = 0; if( !buf || !key || !value || size<=0 ) { log_error("Invalid input arguments\n"); return -1; } ptr = strstr(buf, key); if( !ptr ) { log_debug("Not found key \"%s\" in %s\n", key, buf); return -2; } ptr=strchr(ptr, ':'); /* found ':' before the value */ if( !ptr ) { log_debug("Not found ':' before value\n"); return -3; } ptr++; /* skip ':' */ if( *ptr == '\"' ) /* skip " */ ptr++; memset(value, 0, size); while(*ptr!='\r' && i