uTerminal is a simple AT-command style terminal processor, simplifying the work to send and parse COMMAND=value pairs to a microcontroller.

Dependencies:   USBDevice

Dependents:   uTerminal_Example

uTerminal.cpp

Committer:
fbcosentino
Date:
2019-02-21
Revision:
3:39fb12e8a2a3
Parent:
2:8029cce18e1a

File content as of revision 3:39fb12e8a2a3:

#include "uTerminal.h"

uTerminal::uTerminal(PinName PinTX, PinName PinRX) {
    is_usb = 0;
    _serial = new Serial(PinTX, PinRX);
    _serial->attach(this, &uTerminal::_rx_irq, Serial::RxIrq);
    init();
}

uTerminal::uTerminal(Serial * serial_object) {
    is_usb = 0;
    _serial = serial_object;
    _serial->attach(this, &uTerminal::_rx_irq, Serial::RxIrq);
    init();
}

uTerminal::uTerminal(USBSerial * usbserial_object) {
    is_usb = 1;
    _usbserial = usbserial_object;
    _usbserial->attach(this, &uTerminal::_rx_irq);
    init();
}
    
void uTerminal::init() {
    _callback = 0;
    cursor = 0;
    param_cursor = 0;
    buffer_len = 0;
    params_len = 0;
    has_command = 0;
    NumParams = 0;
    ParamLen = 0;
    auto_mode = 0;
}

bool uTerminal::readable() {
    if (is_usb) {
        if (_usbserial->connected()) return _usbserial->readable();
        else return 0;
    }
    else return _serial->readable();
}
unsigned char uTerminal::getc() {
    if (is_usb) {
        if (_usbserial->connected()) return _usbserial->getc();
        else return 0;
    }
    else return _serial->getc();
}

void uTerminal::ModeAuto() {
    auto_mode = 1;
}

void uTerminal::ModeManual() {
    auto_mode = 0;
}

void uTerminal::attach( void (*callback)() ) {
    _callback = callback;
}

void uTerminal::_rx_irq() {
    unsigned char val;
    if(readable()) {
        val = getc();
        if ((val == 10) || (val == 13)) {
            // Received a return character (Linux = 10, Windows = 13,10)
            // When #13#10 is received, the #10 will trigger this "if" with empty command. Ignore it.
            if (cursor > 0) {
                // Ok, we indeed have a command.
                has_command = 1; // 1-> Successful command (return). 2->Buffer full
                _buffer[cursor++] = 0x00; // make a null-terminated safe string
                buffer_len = cursor; // Includes terminating null
                cursor = 0;
                transfer_buffers(); // prepare the Command and Value buffers
            }
        }
        else {
            has_command = 0; // If had unread command in buffer, cancel it. Sorry, you lost it.
            _buffer[cursor++] = val;
            if (cursor >= UTERMINAL_BUF_SIZE) {
                // Even if it's not a return, we must not continue since buffer is full
                // Consider input done, but with result=2 instead of 1, to tell it's buffer size
                has_command = 2;
                buffer_len = UTERMINAL_BUF_SIZE; // all valid characters
                _buffer[cursor] = 0x00; // make a null-terminated safe string
                cursor = 0; // reset cursor to avoid overflow
                transfer_buffers(); // prepare the Command and Value buffers
            }
        }
    }
}

void uTerminal::transfer_buffers() {
    int i;
    int j;
    char c;
    
    // transfer cmd buffer
    i = 0;
    j = 0;
    while (i < buffer_len) {
        c = _buffer[i++];
        if ((c == '=') || (c == 0)) {
            Command[j] = 0; // null-terminated string
            break;
        }
        else {
            Command[j++] = c;
        }
    }
    if (i >= buffer_len) Command[j] = 0; // null-terminated safe
    
    // transfer param buffer
    if (c == '=') { // if we have parameters
        NumParams = 1;
        j = 0;
        while (i < buffer_len) {
            c = _buffer[i++];
            Value[j++] = c;
            if (c == ',') NumParams++;
            if (c == 0) break;
        }
        params_len = j; // length includes terminating null
    }
    else {
        Value[0] = 0; // empty string
        NumParams = 0;
        params_len = 0;
    }
    
    Param[0] = 0; // Param always begins as empty string
    ParamLen = 0;
    
    param_cursor = 0;
    
    // If in auto-mode, invoke the callback
    if (auto_mode) Process();
}

char* uTerminal::GetParam() {
    int i;
    char c;
    
    i = 0;
    while (param_cursor < params_len) {
        c = Value[param_cursor];
        if (c == ',') {
            Param[i] = 0;
            param_cursor++;
            break;
        }
        if (c == 0) {
            Param[i] = 0;
            break;
        }
        else {
            Param[i++] = c;
            param_cursor++;
        }
    }
    if (param_cursor >= params_len) Param[i] = 0; // null-terminated safe
    
    ParamLen = i; // does not include terminating null
    
    return Param;
}


int uTerminal::Process() {
    // Be ready for next message in the background
    int _has_cmd = has_command;
    has_command = 0;

    // invoke the callback
    if ((_has_cmd > 0) && (_callback != 0)) _callback();
    
    // Return status
    return _has_cmd;
}

void uTerminal::print(char* str) {
    if (is_usb) {
        while (!_usbserial->connected()); // block until connected
        _usbserial->printf(str);
    }
    else _serial->printf(str);
}

void uTerminal::print(const char* str) {
    print((char*)str);
}