Parser for AT commands and similar protocols

Dependencies:   BufferedSerial

ATParser.cpp

Committer:
geky
Date:
2015-07-15
Revision:
0:c741e144517c
Child:
1:66a14afe650a

File content as of revision 0:c741e144517c:

/* 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;
}