Committer:
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4
Date:
Tue Jun 14 09:21:18 2022 +0000
Revision:
0:bdf663c61a82
lib

Who changed what in which revision?

UserRevisionLine numberNew contents of line
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 1 /* Copyright (c) 2017 ARM Limited
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 2 *
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 3 * Licensed under the Apache License, Version 2.0 (the "License");
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 4 * you may not use this file except in compliance with the License.
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 5 * You may obtain a copy of the License at
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 6 *
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 7 * http://www.apache.org/licenses/LICENSE-2.0
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 8 *
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 9 * Unless required by applicable law or agreed to in writing, software
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 10 * distributed under the License is distributed on an "AS IS" BASIS,
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 12 * See the License for the specific language governing permissions and
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 13 * limitations under the License.
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 14 *
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 15 * @section DESCRIPTION
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 16 *
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 17 * Parser for the AT command syntax
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 18 *
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 19 */
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 20
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 21 #include "ATCmdParser.h"
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 22 #include "mbed_poll.h"
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 23 #include "mbed_debug.h"
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 24
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 25 #ifdef LF
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 26 #undef LF
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 27 #define LF 10
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 28 #else
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 29 #define LF 10
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 30 #endif
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 31
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 32 #ifdef CR
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 33 #undef CR
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 34 #define CR 13
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 35 #else
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 36 #define CR 13
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 37 #endif
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 38
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 39 // getc/putc handling with timeouts
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 40 int ATCmdParser::putc(char c)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 41 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 42 pollfh fhs;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 43 fhs.fh = _fh;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 44 fhs.events = POLLOUT;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 45
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 46 int count = poll(&fhs, 1, _timeout);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 47 if (count > 0 && (fhs.revents & POLLOUT)) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 48 return _fh->write(&c, 1) == 1 ? 0 : -1;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 49 } else {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 50 return -1;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 51 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 52 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 53
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 54 int ATCmdParser::getc()
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 55 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 56 pollfh fhs;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 57 fhs.fh = _fh;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 58 fhs.events = POLLIN;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 59
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 60 int count = poll(&fhs, 1, _timeout);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 61 if (count > 0 && (fhs.revents & POLLIN)) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 62 unsigned char ch;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 63 return _fh->read(&ch, 1) == 1 ? ch : -1;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 64 } else {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 65 return -1;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 66 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 67 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 68
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 69 void ATCmdParser::flush()
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 70 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 71 while (_fh->readable()) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 72 unsigned char ch;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 73 _fh->read(&ch, 1);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 74 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 75 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 76
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 77
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 78 // read/write handling with timeouts
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 79 int ATCmdParser::write(const char *data, int size)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 80 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 81 int i = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 82 for ( ; i < size; i++) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 83 if (putc(data[i]) < 0) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 84 return -1;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 85 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 86 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 87 return i;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 88 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 89
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 90 int ATCmdParser::read(char *data, int size)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 91 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 92 int i = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 93 for ( ; i < size; i++) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 94 int c = getc();
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 95 if (c < 0) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 96 return -1;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 97 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 98 data[i] = c;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 99 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 100 return i;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 101 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 102
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 103
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 104 // printf/scanf handling
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 105 int ATCmdParser::vprintf(const char *format, va_list args)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 106 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 107
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 108 if (vsprintf(_buffer, format, args) < 0) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 109 return false;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 110 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 111
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 112 int i = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 113 for ( ; _buffer[i]; i++) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 114 if (putc(_buffer[i]) < 0) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 115 return -1;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 116 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 117 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 118 return i;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 119 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 120
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 121 int ATCmdParser::vscanf(const char *format, va_list args)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 122 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 123 // Since format is const, we need to copy it into our buffer to
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 124 // add the line's null terminator and clobber value-matches with asterisks.
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 125 //
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 126 // We just use the beginning of the buffer to avoid unnecessary allocations.
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 127 int i = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 128 int offset = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 129
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 130 while (format[i]) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 131 if (format[i] == '%' && format[i+1] != '%' && format[i+1] != '*') {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 132 _buffer[offset++] = '%';
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 133 _buffer[offset++] = '*';
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 134 i++;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 135 } else {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 136 _buffer[offset++] = format[i++];
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 137 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 138 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 139
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 140 // Scanf has very poor support for catching errors
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 141 // fortunately, we can abuse the %n specifier to determine
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 142 // if the entire string was matched.
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 143 _buffer[offset++] = '%';
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 144 _buffer[offset++] = 'n';
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 145 _buffer[offset++] = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 146
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 147 // To workaround scanf's lack of error reporting, we actually
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 148 // make two passes. One checks the validity with the modified
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 149 // format string that only stores the matched characters (%n).
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 150 // The other reads in the actual matched values.
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 151 //
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 152 // We keep trying the match until we succeed or some other error
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 153 // derails us.
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 154 int j = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 155
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 156 while (true) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 157 // Ran out of space
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 158 if (j+1 >= _buffer_size - offset) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 159 return false;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 160 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 161 // Recieve next character
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 162 int c = getc();
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 163 if (c < 0) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 164 return -1;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 165 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 166 _buffer[offset + j++] = c;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 167 _buffer[offset + j] = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 168
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 169 // Check for match
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 170 int count = -1;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 171 sscanf(_buffer+offset, _buffer, &count);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 172
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 173 // We only succeed if all characters in the response are matched
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 174 if (count == j) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 175 // Store the found results
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 176 vsscanf(_buffer+offset, format, args);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 177 return j;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 178 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 179 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 180 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 181
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 182
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 183 // Command parsing with line handling
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 184 bool ATCmdParser::vsend(const char *command, va_list args)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 185 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 186 // Create and send command
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 187 if (vsprintf(_buffer, command, args) < 0) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 188 return false;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 189 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 190
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 191 for (int i = 0; _buffer[i]; i++) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 192 if (putc(_buffer[i]) < 0) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 193 return false;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 194 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 195 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 196
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 197 // Finish with newline
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 198 for (size_t i = 0; _output_delimiter[i]; i++) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 199 if (putc(_output_delimiter[i]) < 0) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 200 return false;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 201 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 202 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 203
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 204 debug_if(_dbg_on, "AT> %s\n", _buffer);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 205 return true;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 206 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 207
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 208 bool ATCmdParser::vrecv(const char *response, va_list args)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 209 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 210 restart:
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 211 _aborted = false;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 212 // Iterate through each line in the expected response
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 213 while (response[0]) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 214 // Since response is const, we need to copy it into our buffer to
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 215 // add the line's null terminator and clobber value-matches with asterisks.
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 216 //
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 217 // We just use the beginning of the buffer to avoid unnecessary allocations.
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 218 int i = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 219 int offset = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 220 bool whole_line_wanted = false;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 221
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 222 while (response[i]) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 223 if (response[i] == '%' && response[i+1] != '%' && response[i+1] != '*') {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 224 _buffer[offset++] = '%';
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 225 _buffer[offset++] = '*';
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 226 i++;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 227 } else {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 228 _buffer[offset++] = response[i++];
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 229 // Find linebreaks, taking care not to be fooled if they're in a %[^\n] conversion specification
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 230 if (response[i - 1] == '\n' && !(i >= 3 && response[i-3] == '[' && response[i-2] == '^')) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 231 whole_line_wanted = true;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 232 break;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 233 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 234 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 235 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 236
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 237 // Scanf has very poor support for catching errors
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 238 // fortunately, we can abuse the %n specifier to determine
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 239 // if the entire string was matched.
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 240 _buffer[offset++] = '%';
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 241 _buffer[offset++] = 'n';
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 242 _buffer[offset++] = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 243
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 244 debug_if(_dbg_on, "AT? %s\n", _buffer);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 245 // To workaround scanf's lack of error reporting, we actually
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 246 // make two passes. One checks the validity with the modified
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 247 // format string that only stores the matched characters (%n).
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 248 // The other reads in the actual matched values.
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 249 //
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 250 // We keep trying the match until we succeed or some other error
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 251 // derails us.
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 252 int j = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 253
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 254 while (true) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 255 // Receive next character
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 256 int c = getc();
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 257 if (c < 0) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 258 debug_if(_dbg_on, "AT(Timeout)\n");
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 259 return false;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 260 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 261 // Simplify newlines (borrowed from retarget.cpp)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 262 if ((c == CR && _in_prev != LF) ||
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 263 (c == LF && _in_prev != CR)) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 264 _in_prev = c;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 265 c = '\n';
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 266 } else if ((c == CR && _in_prev == LF) ||
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 267 (c == LF && _in_prev == CR)) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 268 _in_prev = c;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 269 // onto next character
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 270 continue;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 271 } else {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 272 _in_prev = c;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 273 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 274 _buffer[offset + j++] = c;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 275 _buffer[offset + j] = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 276
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 277 // Check for oob data
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 278 for (struct oob *oob = _oobs; oob; oob = oob->next) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 279 if ((unsigned)j == oob->len && memcmp(
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 280 oob->prefix, _buffer+offset, oob->len) == 0) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 281 debug_if(_dbg_on, "AT! %s\n", oob->prefix);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 282 oob->cb();
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 283
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 284 if (_aborted) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 285 debug_if(_dbg_on, "AT(Aborted)\n");
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 286 return false;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 287 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 288 // oob may have corrupted non-reentrant buffer,
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 289 // so we need to set it up again
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 290 goto restart;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 291 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 292 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 293
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 294 // Check for match
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 295 int count = -1;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 296 if (whole_line_wanted && c != '\n') {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 297 // Don't attempt scanning until we get delimiter if they included it in format
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 298 // This allows recv("Foo: %s\n") to work, and not match with just the first character of a string
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 299 // (scanf does not itself match whitespace in its format string, so \n is not significant to it)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 300 } else {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 301 sscanf(_buffer+offset, _buffer, &count);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 302 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 303
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 304 // We only succeed if all characters in the response are matched
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 305 if (count == j) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 306 debug_if(_dbg_on, "AT= %s\n", _buffer+offset);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 307 // Reuse the front end of the buffer
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 308 memcpy(_buffer, response, i);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 309 _buffer[i] = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 310
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 311 // Store the found results
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 312 vsscanf(_buffer+offset, _buffer, args);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 313
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 314 // Jump to next line and continue parsing
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 315 response += i;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 316 break;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 317 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 318
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 319 // Clear the buffer when we hit a newline or ran out of space
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 320 // running out of space usually means we ran into binary data
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 321 if (c == '\n' || j+1 >= _buffer_size - offset) {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 322 debug_if(_dbg_on, "AT< %s", _buffer+offset);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 323 j = 0;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 324 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 325 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 326 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 327
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 328 return true;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 329 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 330
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 331 // Mapping to vararg functions
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 332 int ATCmdParser::printf(const char *format, ...)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 333 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 334 va_list args;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 335 va_start(args, format);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 336 int res = vprintf(format, args);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 337 va_end(args);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 338 return res;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 339 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 340
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 341 int ATCmdParser::scanf(const char *format, ...)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 342 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 343 va_list args;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 344 va_start(args, format);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 345 int res = vscanf(format, args);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 346 va_end(args);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 347 return res;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 348 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 349
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 350 bool ATCmdParser::send(const char *command, ...)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 351 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 352 va_list args;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 353 va_start(args, command);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 354 bool res = vsend(command, args);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 355 va_end(args);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 356 return res;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 357 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 358
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 359 bool ATCmdParser::recv(const char *response, ...)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 360 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 361 va_list args;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 362 va_start(args, response);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 363 bool res = vrecv(response, args);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 364 va_end(args);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 365 return res;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 366 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 367
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 368 // oob registration
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 369 void ATCmdParser::oob(const char *prefix, Callback<void()> cb)
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 370 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 371 struct oob *oob = new struct oob;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 372 oob->len = strlen(prefix);
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 373 oob->prefix = prefix;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 374 oob->cb = cb;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 375 oob->next = _oobs;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 376 _oobs = oob;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 377 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 378
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 379 void ATCmdParser::abort()
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 380 {
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 381 _aborted = true;
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 382 }
abe5b02d-a2d4-4fe9-818e-c4e57c809ea4 0:bdf663c61a82 383