Parser for AT commands and similar protocols

Dependencies:   BufferedSerial

Revision:
0:c741e144517c
Child:
1:66a14afe650a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ATParser.cpp	Wed Jul 15 22:39:25 2015 +0000
@@ -0,0 +1,136 @@
+/* Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @section DESCRIPTION
+ *
+ * Parser for the AT command syntax
+ *
+ */
+ 
+#include "ATParser.h"
+#include <cstdarg>
+
+// This can be defined to assist in debugging
+#define AT_ECHO 1
+
+
+// getc/putc handling with timeouts
+int ATParser::_putc(char c) {
+    Timer timer;
+    timer.start();
+    
+    while (true) {
+        if (_serial->writeable())
+            return _serial->putc(c);
+            
+        if (timer.read_ms() > _timeout)
+            return -1;
+    }
+}
+
+int ATParser::_getc() {
+    Timer timer;
+    timer.start();
+    
+    while (true) {
+        if (_serial->readable())
+            return _serial->getc();
+            
+        if (timer.read_ms() > _timeout)
+            return -1;
+    }
+}
+
+void ATParser::_flush() {
+    while (_serial->readable())
+        _serial->getc();
+}
+
+// getline/putline handling with timeouts/bounds checking
+bool ATParser::_putline(const char *line) {
+    for (int i = 0; line[i]; i++) {
+        if (_putc(line[i]) < 0)
+            return false;
+    }
+    
+    // Finish with newline
+    if (_putc('\r') < 0 ||
+        _putc('\n') < 0)
+        return false;
+    
+#ifdef AT_ECHO
+    printf("AT> %s\r\n", line);
+#endif
+
+    return true;
+}
+
+bool ATParser::_getline(int size, char *line) {
+    for (int i = 0; i < size; i++) {
+        int c = _getc();
+            
+                if (c < 0)
+                        return false;
+        
+        // Finish if newline
+        if (c == '\r') {
+            if (_getc() != '\n')
+                return false;
+            
+            line[i] = 0;      
+#ifdef AT_ECHO
+            printf("AT< %s\r\n", line);
+#endif
+            return true;
+        }
+        
+        line[i] = c;
+    }
+    
+    // Ran out of space
+    return false;
+}      
+
+ 
+bool ATParser::command(const char *command, const char *response, ...) {
+    va_list args;
+    va_start(args, response);
+    
+    _flush();
+    
+    // Create and send command
+    if (vsprintf(_buffer, command, args) < 0 ||
+        !_putline(_buffer)) {
+        va_end(args);
+        return false;
+    }
+       
+    // Determine number of parameters
+    // this is needed for scanf's funky error signaling
+    int params = 0;
+    for (int i = 0; response[i]; i++) {
+        if (response[i] == '%' && response[i+1] != '%')
+            params++;
+    }
+    
+    // Recieve and parse response
+    if (!_getline(_buffer_size, _buffer) ||
+        vsscanf(_buffer, response, args) < params) {
+        va_end(args);
+        return false;
+    }
+ 
+    va_end(args);
+    return true;
+}