Parser for AT commands and similar protocols

Dependencies:   BufferedSerial

Committer:
geky
Date:
Wed Jul 15 22:39:25 2015 +0000
Revision:
0:c741e144517c
Child:
1:66a14afe650a
Initial Commit

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 #include <cstdarg>
geky 0:c741e144517c 23
geky 0:c741e144517c 24 // This can be defined to assist in debugging
geky 0:c741e144517c 25 #define AT_ECHO 1
geky 0:c741e144517c 26
geky 0:c741e144517c 27
geky 0:c741e144517c 28 // getc/putc handling with timeouts
geky 0:c741e144517c 29 int ATParser::_putc(char c) {
geky 0:c741e144517c 30 Timer timer;
geky 0:c741e144517c 31 timer.start();
geky 0:c741e144517c 32
geky 0:c741e144517c 33 while (true) {
geky 0:c741e144517c 34 if (_serial->writeable())
geky 0:c741e144517c 35 return _serial->putc(c);
geky 0:c741e144517c 36
geky 0:c741e144517c 37 if (timer.read_ms() > _timeout)
geky 0:c741e144517c 38 return -1;
geky 0:c741e144517c 39 }
geky 0:c741e144517c 40 }
geky 0:c741e144517c 41
geky 0:c741e144517c 42 int ATParser::_getc() {
geky 0:c741e144517c 43 Timer timer;
geky 0:c741e144517c 44 timer.start();
geky 0:c741e144517c 45
geky 0:c741e144517c 46 while (true) {
geky 0:c741e144517c 47 if (_serial->readable())
geky 0:c741e144517c 48 return _serial->getc();
geky 0:c741e144517c 49
geky 0:c741e144517c 50 if (timer.read_ms() > _timeout)
geky 0:c741e144517c 51 return -1;
geky 0:c741e144517c 52 }
geky 0:c741e144517c 53 }
geky 0:c741e144517c 54
geky 0:c741e144517c 55 void ATParser::_flush() {
geky 0:c741e144517c 56 while (_serial->readable())
geky 0:c741e144517c 57 _serial->getc();
geky 0:c741e144517c 58 }
geky 0:c741e144517c 59
geky 0:c741e144517c 60 // getline/putline handling with timeouts/bounds checking
geky 0:c741e144517c 61 bool ATParser::_putline(const char *line) {
geky 0:c741e144517c 62 for (int i = 0; line[i]; i++) {
geky 0:c741e144517c 63 if (_putc(line[i]) < 0)
geky 0:c741e144517c 64 return false;
geky 0:c741e144517c 65 }
geky 0:c741e144517c 66
geky 0:c741e144517c 67 // Finish with newline
geky 0:c741e144517c 68 if (_putc('\r') < 0 ||
geky 0:c741e144517c 69 _putc('\n') < 0)
geky 0:c741e144517c 70 return false;
geky 0:c741e144517c 71
geky 0:c741e144517c 72 #ifdef AT_ECHO
geky 0:c741e144517c 73 printf("AT> %s\r\n", line);
geky 0:c741e144517c 74 #endif
geky 0:c741e144517c 75
geky 0:c741e144517c 76 return true;
geky 0:c741e144517c 77 }
geky 0:c741e144517c 78
geky 0:c741e144517c 79 bool ATParser::_getline(int size, char *line) {
geky 0:c741e144517c 80 for (int i = 0; i < size; i++) {
geky 0:c741e144517c 81 int c = _getc();
geky 0:c741e144517c 82
geky 0:c741e144517c 83 if (c < 0)
geky 0:c741e144517c 84 return false;
geky 0:c741e144517c 85
geky 0:c741e144517c 86 // Finish if newline
geky 0:c741e144517c 87 if (c == '\r') {
geky 0:c741e144517c 88 if (_getc() != '\n')
geky 0:c741e144517c 89 return false;
geky 0:c741e144517c 90
geky 0:c741e144517c 91 line[i] = 0;
geky 0:c741e144517c 92 #ifdef AT_ECHO
geky 0:c741e144517c 93 printf("AT< %s\r\n", line);
geky 0:c741e144517c 94 #endif
geky 0:c741e144517c 95 return true;
geky 0:c741e144517c 96 }
geky 0:c741e144517c 97
geky 0:c741e144517c 98 line[i] = c;
geky 0:c741e144517c 99 }
geky 0:c741e144517c 100
geky 0:c741e144517c 101 // Ran out of space
geky 0:c741e144517c 102 return false;
geky 0:c741e144517c 103 }
geky 0:c741e144517c 104
geky 0:c741e144517c 105
geky 0:c741e144517c 106 bool ATParser::command(const char *command, const char *response, ...) {
geky 0:c741e144517c 107 va_list args;
geky 0:c741e144517c 108 va_start(args, response);
geky 0:c741e144517c 109
geky 0:c741e144517c 110 _flush();
geky 0:c741e144517c 111
geky 0:c741e144517c 112 // Create and send command
geky 0:c741e144517c 113 if (vsprintf(_buffer, command, args) < 0 ||
geky 0:c741e144517c 114 !_putline(_buffer)) {
geky 0:c741e144517c 115 va_end(args);
geky 0:c741e144517c 116 return false;
geky 0:c741e144517c 117 }
geky 0:c741e144517c 118
geky 0:c741e144517c 119 // Determine number of parameters
geky 0:c741e144517c 120 // this is needed for scanf's funky error signaling
geky 0:c741e144517c 121 int params = 0;
geky 0:c741e144517c 122 for (int i = 0; response[i]; i++) {
geky 0:c741e144517c 123 if (response[i] == '%' && response[i+1] != '%')
geky 0:c741e144517c 124 params++;
geky 0:c741e144517c 125 }
geky 0:c741e144517c 126
geky 0:c741e144517c 127 // Recieve and parse response
geky 0:c741e144517c 128 if (!_getline(_buffer_size, _buffer) ||
geky 0:c741e144517c 129 vsscanf(_buffer, response, args) < params) {
geky 0:c741e144517c 130 va_end(args);
geky 0:c741e144517c 131 return false;
geky 0:c741e144517c 132 }
geky 0:c741e144517c 133
geky 0:c741e144517c 134 va_end(args);
geky 0:c741e144517c 135 return true;
geky 0:c741e144517c 136 }