ATParser for X-NUCLEO-IDW01M1 module

Dependencies:   BufferedSerial

Dependents:   SPWF01SA-lapi-1 SPWF01SA Nucleo-AWS-IoT-mbed

Fork of ATParser by ST Expansion SW Team

Committer:
geky
Date:
Mon Jul 20 20:56:30 2015 +0000
Revision:
8:91515b168c70
Parent:
7:d1b193880af1
Child:
9:9bcb87c27208
Removed broken command method. Command calls can be replaced by anded send/recv calls.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
geky 0:c741e144517c 1 /* Copyright (c) 2015 ARM Limited
geky 0:c741e144517c 2 *
geky 0:c741e144517c 3 * Licensed under the Apache License, Version 2.0 (the "License");
geky 0:c741e144517c 4 * you may not use this file except in compliance with the License.
geky 0:c741e144517c 5 * You may obtain a copy of the License at
geky 0:c741e144517c 6 *
geky 0:c741e144517c 7 * http://www.apache.org/licenses/LICENSE-2.0
geky 0:c741e144517c 8 *
geky 0:c741e144517c 9 * Unless required by applicable law or agreed to in writing, software
geky 0:c741e144517c 10 * distributed under the License is distributed on an "AS IS" BASIS,
geky 0:c741e144517c 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
geky 0:c741e144517c 12 * See the License for the specific language governing permissions and
geky 0:c741e144517c 13 * limitations under the License.
geky 0:c741e144517c 14 *
geky 0:c741e144517c 15 * @section DESCRIPTION
geky 0:c741e144517c 16 *
geky 0:c741e144517c 17 * Parser for the AT command syntax
geky 0:c741e144517c 18 *
geky 0:c741e144517c 19 */
geky 0:c741e144517c 20
geky 0:c741e144517c 21 #include "ATParser.h"
geky 0:c741e144517c 22
geky 0:c741e144517c 23 // This can be defined to assist in debugging
geky 2:4d68f546861c 24 #define AT_ECHO 1
geky 0:c741e144517c 25
geky 0:c741e144517c 26
geky 0:c741e144517c 27 // getc/putc handling with timeouts
geky 4:38acbd6f9d9e 28 int ATParser::putc(char c) {
geky 0:c741e144517c 29 Timer timer;
geky 0:c741e144517c 30 timer.start();
geky 0:c741e144517c 31
geky 0:c741e144517c 32 while (true) {
geky 0:c741e144517c 33 if (_serial->writeable())
geky 0:c741e144517c 34 return _serial->putc(c);
geky 0:c741e144517c 35
geky 0:c741e144517c 36 if (timer.read_ms() > _timeout)
geky 0:c741e144517c 37 return -1;
geky 0:c741e144517c 38 }
geky 0:c741e144517c 39 }
geky 0:c741e144517c 40
geky 4:38acbd6f9d9e 41 int ATParser::getc() {
geky 0:c741e144517c 42 Timer timer;
geky 0:c741e144517c 43 timer.start();
geky 0:c741e144517c 44
geky 0:c741e144517c 45 while (true) {
geky 0:c741e144517c 46 if (_serial->readable())
geky 0:c741e144517c 47 return _serial->getc();
geky 0:c741e144517c 48
geky 0:c741e144517c 49 if (timer.read_ms() > _timeout)
geky 0:c741e144517c 50 return -1;
geky 0:c741e144517c 51 }
geky 0:c741e144517c 52 }
geky 0:c741e144517c 53
geky 4:38acbd6f9d9e 54 void ATParser::flush() {
geky 0:c741e144517c 55 while (_serial->readable())
geky 0:c741e144517c 56 _serial->getc();
geky 0:c741e144517c 57 }
geky 0:c741e144517c 58
geky 7:d1b193880af1 59
geky 6:51f1171b5ebc 60 // read/write handling with timeouts
geky 6:51f1171b5ebc 61 int ATParser::write(const char *data, int size) {
geky 6:51f1171b5ebc 62 int i;
geky 6:51f1171b5ebc 63
geky 6:51f1171b5ebc 64 for (i = 0; i < size; i++) {
geky 6:51f1171b5ebc 65 if (putc(data[i]) < 0)
geky 6:51f1171b5ebc 66 return i;
geky 6:51f1171b5ebc 67 }
geky 6:51f1171b5ebc 68
geky 6:51f1171b5ebc 69 return i;
geky 6:51f1171b5ebc 70 }
geky 6:51f1171b5ebc 71
geky 6:51f1171b5ebc 72 int ATParser::read(char *data, int size) {
geky 6:51f1171b5ebc 73 int i;
geky 6:51f1171b5ebc 74
geky 6:51f1171b5ebc 75 for (i = 0; i < size; i++) {
geky 6:51f1171b5ebc 76 int c = getc();
geky 6:51f1171b5ebc 77
geky 6:51f1171b5ebc 78 if (c < 0)
geky 6:51f1171b5ebc 79 return i;
geky 6:51f1171b5ebc 80
geky 6:51f1171b5ebc 81 data[i] = c;
geky 6:51f1171b5ebc 82 }
geky 6:51f1171b5ebc 83
geky 6:51f1171b5ebc 84 return i;
geky 6:51f1171b5ebc 85 }
geky 6:51f1171b5ebc 86
geky 1:66a14afe650a 87
geky 7:d1b193880af1 88 // Command parsing with line handling
geky 7:d1b193880af1 89 bool ATParser::vsend(const char *command, va_list args) {
geky 7:d1b193880af1 90 flush();
geky 7:d1b193880af1 91
geky 7:d1b193880af1 92 // Create and send command
geky 7:d1b193880af1 93 if (vsprintf(_buffer, command, args) < 0)
geky 7:d1b193880af1 94 return false;
geky 7:d1b193880af1 95
geky 7:d1b193880af1 96 for (int i = 0; _buffer[i]; i++) {
geky 7:d1b193880af1 97 if (putc(_buffer[i]) < 0)
geky 0:c741e144517c 98 return false;
geky 0:c741e144517c 99 }
geky 0:c741e144517c 100
geky 0:c741e144517c 101 // Finish with newline
geky 3:32915b9467d2 102 for (int i = 0; _delimiter[i]; i++) {
geky 4:38acbd6f9d9e 103 if (putc(_delimiter[i]) < 0)
geky 3:32915b9467d2 104 return false;
geky 3:32915b9467d2 105 }
geky 0:c741e144517c 106
geky 0:c741e144517c 107 #ifdef AT_ECHO
geky 7:d1b193880af1 108 printf("AT> %s\r\n", _buffer);
geky 0:c741e144517c 109 #endif
geky 5:26bc9255b751 110
geky 5:26bc9255b751 111 return true;
geky 5:26bc9255b751 112 }
geky 5:26bc9255b751 113
geky 5:26bc9255b751 114 bool ATParser::vrecv(const char *response, va_list args) {
geky 1:66a14afe650a 115 // Iterate through each line in the expected response
geky 5:26bc9255b751 116 while (response[0]) {
geky 1:66a14afe650a 117 // Since response is const, we need to copy it into our buffer to
geky 7:d1b193880af1 118 // add the line's null terminator and clobber value-matches with asterisks.
geky 1:66a14afe650a 119 //
geky 7:d1b193880af1 120 // We just use the beginning of the buffer to avoid unnecessary allocations.
geky 1:66a14afe650a 121 int i = 0;
geky 1:66a14afe650a 122 int offset = 0;
geky 1:66a14afe650a 123
geky 1:66a14afe650a 124 while (response[i]) {
geky 5:26bc9255b751 125 if (memcmp(&response[i+1-_delim_size], _delimiter, _delim_size) == 0) {
geky 5:26bc9255b751 126 i++;
geky 1:66a14afe650a 127 break;
geky 1:66a14afe650a 128 } else if (response[i] == '%' &&
geky 1:66a14afe650a 129 response[i+1] != '%' &&
geky 1:66a14afe650a 130 response[i+1] != '*') {
geky 1:66a14afe650a 131 _buffer[offset++] = '%';
geky 1:66a14afe650a 132 _buffer[offset++] = '*';
geky 3:32915b9467d2 133 i++;
geky 1:66a14afe650a 134 } else {
geky 1:66a14afe650a 135 _buffer[offset++] = response[i++];
geky 1:66a14afe650a 136 }
geky 1:66a14afe650a 137 }
geky 1:66a14afe650a 138
geky 1:66a14afe650a 139 // Scanf has very poor support for catching errors
geky 1:66a14afe650a 140 // fortunately, we can abuse the %n specifier to determine
geky 1:66a14afe650a 141 // if the entire string was matched.
geky 1:66a14afe650a 142 _buffer[offset++] = '%';
geky 1:66a14afe650a 143 _buffer[offset++] = 'n';
geky 1:66a14afe650a 144 _buffer[offset++] = 0;
geky 1:66a14afe650a 145
geky 1:66a14afe650a 146 // To workaround scanf's lack of error reporting, we actually
geky 1:66a14afe650a 147 // make two passes. One checks the validity with the modified
geky 1:66a14afe650a 148 // format string that only stores the matched characters (%n).
geky 1:66a14afe650a 149 // The other reads in the actual matched values.
geky 1:66a14afe650a 150 //
geky 1:66a14afe650a 151 // We keep trying the match until we succeed or some other error
geky 1:66a14afe650a 152 // derails us.
geky 7:d1b193880af1 153 int j = 0;
geky 7:d1b193880af1 154
geky 7:d1b193880af1 155 while (j+1 < _buffer_size - offset) {
geky 7:d1b193880af1 156 // Recieve next character
geky 7:d1b193880af1 157 int c = getc();
geky 7:d1b193880af1 158 if (c < 0)
geky 1:66a14afe650a 159 return false;
geky 7:d1b193880af1 160
geky 7:d1b193880af1 161 _buffer[offset + j++] = c;
geky 7:d1b193880af1 162 _buffer[offset + j] = 0;
geky 7:d1b193880af1 163
geky 7:d1b193880af1 164 // Check for match
geky 2:4d68f546861c 165 int count = -1;
geky 1:66a14afe650a 166 sscanf(_buffer+offset, _buffer, &count);
geky 1:66a14afe650a 167
geky 7:d1b193880af1 168 // We only succeed if all characters in the response are matched
geky 7:d1b193880af1 169 if (count == j) {
geky 7:d1b193880af1 170 #ifdef AT_ECHO
geky 7:d1b193880af1 171 printf("AT= %s\r\n", _buffer+offset);
geky 7:d1b193880af1 172 #endif
geky 1:66a14afe650a 173 // Reuse the front end of the buffer
geky 6:51f1171b5ebc 174 memcpy(_buffer, response, i);
geky 6:51f1171b5ebc 175 _buffer[i] = 0;
geky 1:66a14afe650a 176
geky 1:66a14afe650a 177 // Store the found results
geky 1:66a14afe650a 178 vsscanf(_buffer+offset, _buffer, args);
geky 1:66a14afe650a 179
geky 1:66a14afe650a 180 // Jump to next line and continue parsing
geky 1:66a14afe650a 181 response += i;
geky 1:66a14afe650a 182 break;
geky 1:66a14afe650a 183 }
geky 7:d1b193880af1 184
geky 7:d1b193880af1 185 // Clear the buffer when we hit a newline
geky 7:d1b193880af1 186 if (strcmp(&_buffer[offset + j-_delim_size], _delimiter) == 0) {
geky 7:d1b193880af1 187 #ifdef AT_ECHO
geky 7:d1b193880af1 188 printf("AT< %s", _buffer+offset);
geky 7:d1b193880af1 189 #endif
geky 7:d1b193880af1 190 j = 0;
geky 7:d1b193880af1 191 }
geky 1:66a14afe650a 192 }
geky 0:c741e144517c 193 }
geky 5:26bc9255b751 194
geky 5:26bc9255b751 195 return true;
geky 5:26bc9255b751 196 }
geky 5:26bc9255b751 197
geky 7:d1b193880af1 198
geky 5:26bc9255b751 199 // Mapping to vararg functions
geky 5:26bc9255b751 200 bool ATParser::send(const char *command, ...) {
geky 5:26bc9255b751 201 va_list args;
geky 5:26bc9255b751 202 va_start(args, command);
geky 5:26bc9255b751 203 bool res = vsend(command, args);
geky 5:26bc9255b751 204 va_end(args);
geky 5:26bc9255b751 205 return res;
geky 5:26bc9255b751 206 }
geky 5:26bc9255b751 207
geky 5:26bc9255b751 208 bool ATParser::recv(const char *response, ...) {
geky 5:26bc9255b751 209 va_list args;
geky 5:26bc9255b751 210 va_start(args, response);
geky 5:26bc9255b751 211 bool res = vrecv(response, args);
geky 5:26bc9255b751 212 va_end(args);
geky 5:26bc9255b751 213 return res;
geky 5:26bc9255b751 214 }