uTerminal is a simple AT-command style terminal processor, simplifying the work to send and parse COMMAND=value pairs to a microcontroller.
uTerminal.cpp@3:39fb12e8a2a3, 2019-02-21 (annotated)
- Committer:
- fbcosentino
- Date:
- Thu Feb 21 14:51:43 2019 +0000
- Revision:
- 3:39fb12e8a2a3
- Parent:
- 2:8029cce18e1a
bug fixes
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
fbcosentino | 0:1655adb3a46e | 1 | #include "uTerminal.h" |
fbcosentino | 0:1655adb3a46e | 2 | |
fbcosentino | 1:4e304b58f597 | 3 | uTerminal::uTerminal(PinName PinTX, PinName PinRX) { |
fbcosentino | 1:4e304b58f597 | 4 | is_usb = 0; |
fbcosentino | 1:4e304b58f597 | 5 | _serial = new Serial(PinTX, PinRX); |
fbcosentino | 1:4e304b58f597 | 6 | _serial->attach(this, &uTerminal::_rx_irq, Serial::RxIrq); |
fbcosentino | 1:4e304b58f597 | 7 | init(); |
fbcosentino | 1:4e304b58f597 | 8 | } |
fbcosentino | 1:4e304b58f597 | 9 | |
fbcosentino | 1:4e304b58f597 | 10 | uTerminal::uTerminal(Serial * serial_object) { |
fbcosentino | 1:4e304b58f597 | 11 | is_usb = 0; |
fbcosentino | 1:4e304b58f597 | 12 | _serial = serial_object; |
fbcosentino | 1:4e304b58f597 | 13 | _serial->attach(this, &uTerminal::_rx_irq, Serial::RxIrq); |
fbcosentino | 1:4e304b58f597 | 14 | init(); |
fbcosentino | 1:4e304b58f597 | 15 | } |
fbcosentino | 1:4e304b58f597 | 16 | |
fbcosentino | 1:4e304b58f597 | 17 | uTerminal::uTerminal(USBSerial * usbserial_object) { |
fbcosentino | 1:4e304b58f597 | 18 | is_usb = 1; |
fbcosentino | 1:4e304b58f597 | 19 | _usbserial = usbserial_object; |
fbcosentino | 1:4e304b58f597 | 20 | _usbserial->attach(this, &uTerminal::_rx_irq); |
fbcosentino | 1:4e304b58f597 | 21 | init(); |
fbcosentino | 1:4e304b58f597 | 22 | } |
fbcosentino | 1:4e304b58f597 | 23 | |
fbcosentino | 1:4e304b58f597 | 24 | void uTerminal::init() { |
fbcosentino | 0:1655adb3a46e | 25 | _callback = 0; |
fbcosentino | 0:1655adb3a46e | 26 | cursor = 0; |
fbcosentino | 0:1655adb3a46e | 27 | param_cursor = 0; |
fbcosentino | 0:1655adb3a46e | 28 | buffer_len = 0; |
fbcosentino | 0:1655adb3a46e | 29 | params_len = 0; |
fbcosentino | 0:1655adb3a46e | 30 | has_command = 0; |
fbcosentino | 0:1655adb3a46e | 31 | NumParams = 0; |
fbcosentino | 0:1655adb3a46e | 32 | ParamLen = 0; |
fbcosentino | 0:1655adb3a46e | 33 | auto_mode = 0; |
fbcosentino | 0:1655adb3a46e | 34 | } |
fbcosentino | 0:1655adb3a46e | 35 | |
fbcosentino | 1:4e304b58f597 | 36 | bool uTerminal::readable() { |
fbcosentino | 1:4e304b58f597 | 37 | if (is_usb) { |
fbcosentino | 1:4e304b58f597 | 38 | if (_usbserial->connected()) return _usbserial->readable(); |
fbcosentino | 1:4e304b58f597 | 39 | else return 0; |
fbcosentino | 1:4e304b58f597 | 40 | } |
fbcosentino | 1:4e304b58f597 | 41 | else return _serial->readable(); |
fbcosentino | 1:4e304b58f597 | 42 | } |
fbcosentino | 1:4e304b58f597 | 43 | unsigned char uTerminal::getc() { |
fbcosentino | 1:4e304b58f597 | 44 | if (is_usb) { |
fbcosentino | 1:4e304b58f597 | 45 | if (_usbserial->connected()) return _usbserial->getc(); |
fbcosentino | 1:4e304b58f597 | 46 | else return 0; |
fbcosentino | 1:4e304b58f597 | 47 | } |
fbcosentino | 1:4e304b58f597 | 48 | else return _serial->getc(); |
fbcosentino | 1:4e304b58f597 | 49 | } |
fbcosentino | 1:4e304b58f597 | 50 | |
fbcosentino | 0:1655adb3a46e | 51 | void uTerminal::ModeAuto() { |
fbcosentino | 0:1655adb3a46e | 52 | auto_mode = 1; |
fbcosentino | 0:1655adb3a46e | 53 | } |
fbcosentino | 0:1655adb3a46e | 54 | |
fbcosentino | 0:1655adb3a46e | 55 | void uTerminal::ModeManual() { |
fbcosentino | 0:1655adb3a46e | 56 | auto_mode = 0; |
fbcosentino | 0:1655adb3a46e | 57 | } |
fbcosentino | 0:1655adb3a46e | 58 | |
fbcosentino | 0:1655adb3a46e | 59 | void uTerminal::attach( void (*callback)() ) { |
fbcosentino | 0:1655adb3a46e | 60 | _callback = callback; |
fbcosentino | 0:1655adb3a46e | 61 | } |
fbcosentino | 0:1655adb3a46e | 62 | |
fbcosentino | 0:1655adb3a46e | 63 | void uTerminal::_rx_irq() { |
fbcosentino | 0:1655adb3a46e | 64 | unsigned char val; |
fbcosentino | 1:4e304b58f597 | 65 | if(readable()) { |
fbcosentino | 1:4e304b58f597 | 66 | val = getc(); |
fbcosentino | 0:1655adb3a46e | 67 | if ((val == 10) || (val == 13)) { |
fbcosentino | 0:1655adb3a46e | 68 | // Received a return character (Linux = 10, Windows = 13,10) |
fbcosentino | 0:1655adb3a46e | 69 | // When #13#10 is received, the #10 will trigger this "if" with empty command. Ignore it. |
fbcosentino | 0:1655adb3a46e | 70 | if (cursor > 0) { |
fbcosentino | 0:1655adb3a46e | 71 | // Ok, we indeed have a command. |
fbcosentino | 0:1655adb3a46e | 72 | has_command = 1; // 1-> Successful command (return). 2->Buffer full |
fbcosentino | 3:39fb12e8a2a3 | 73 | _buffer[cursor++] = 0x00; // make a null-terminated safe string |
fbcosentino | 3:39fb12e8a2a3 | 74 | buffer_len = cursor; // Includes terminating null |
fbcosentino | 0:1655adb3a46e | 75 | cursor = 0; |
fbcosentino | 0:1655adb3a46e | 76 | transfer_buffers(); // prepare the Command and Value buffers |
fbcosentino | 0:1655adb3a46e | 77 | } |
fbcosentino | 0:1655adb3a46e | 78 | } |
fbcosentino | 0:1655adb3a46e | 79 | else { |
fbcosentino | 0:1655adb3a46e | 80 | has_command = 0; // If had unread command in buffer, cancel it. Sorry, you lost it. |
fbcosentino | 3:39fb12e8a2a3 | 81 | _buffer[cursor++] = val; |
fbcosentino | 0:1655adb3a46e | 82 | if (cursor >= UTERMINAL_BUF_SIZE) { |
fbcosentino | 0:1655adb3a46e | 83 | // Even if it's not a return, we must not continue since buffer is full |
fbcosentino | 0:1655adb3a46e | 84 | // Consider input done, but with result=2 instead of 1, to tell it's buffer size |
fbcosentino | 0:1655adb3a46e | 85 | has_command = 2; |
fbcosentino | 0:1655adb3a46e | 86 | buffer_len = UTERMINAL_BUF_SIZE; // all valid characters |
fbcosentino | 0:1655adb3a46e | 87 | _buffer[cursor] = 0x00; // make a null-terminated safe string |
fbcosentino | 0:1655adb3a46e | 88 | cursor = 0; // reset cursor to avoid overflow |
fbcosentino | 0:1655adb3a46e | 89 | transfer_buffers(); // prepare the Command and Value buffers |
fbcosentino | 0:1655adb3a46e | 90 | } |
fbcosentino | 0:1655adb3a46e | 91 | } |
fbcosentino | 0:1655adb3a46e | 92 | } |
fbcosentino | 0:1655adb3a46e | 93 | } |
fbcosentino | 0:1655adb3a46e | 94 | |
fbcosentino | 0:1655adb3a46e | 95 | void uTerminal::transfer_buffers() { |
fbcosentino | 0:1655adb3a46e | 96 | int i; |
fbcosentino | 0:1655adb3a46e | 97 | int j; |
fbcosentino | 0:1655adb3a46e | 98 | char c; |
fbcosentino | 0:1655adb3a46e | 99 | |
fbcosentino | 0:1655adb3a46e | 100 | // transfer cmd buffer |
fbcosentino | 0:1655adb3a46e | 101 | i = 0; |
fbcosentino | 0:1655adb3a46e | 102 | j = 0; |
fbcosentino | 0:1655adb3a46e | 103 | while (i < buffer_len) { |
fbcosentino | 0:1655adb3a46e | 104 | c = _buffer[i++]; |
fbcosentino | 0:1655adb3a46e | 105 | if ((c == '=') || (c == 0)) { |
fbcosentino | 0:1655adb3a46e | 106 | Command[j] = 0; // null-terminated string |
fbcosentino | 0:1655adb3a46e | 107 | break; |
fbcosentino | 0:1655adb3a46e | 108 | } |
fbcosentino | 0:1655adb3a46e | 109 | else { |
fbcosentino | 0:1655adb3a46e | 110 | Command[j++] = c; |
fbcosentino | 0:1655adb3a46e | 111 | } |
fbcosentino | 0:1655adb3a46e | 112 | } |
fbcosentino | 3:39fb12e8a2a3 | 113 | if (i >= buffer_len) Command[j] = 0; // null-terminated safe |
fbcosentino | 0:1655adb3a46e | 114 | |
fbcosentino | 0:1655adb3a46e | 115 | // transfer param buffer |
fbcosentino | 0:1655adb3a46e | 116 | if (c == '=') { // if we have parameters |
fbcosentino | 0:1655adb3a46e | 117 | NumParams = 1; |
fbcosentino | 0:1655adb3a46e | 118 | j = 0; |
fbcosentino | 0:1655adb3a46e | 119 | while (i < buffer_len) { |
fbcosentino | 0:1655adb3a46e | 120 | c = _buffer[i++]; |
fbcosentino | 0:1655adb3a46e | 121 | Value[j++] = c; |
fbcosentino | 0:1655adb3a46e | 122 | if (c == ',') NumParams++; |
fbcosentino | 0:1655adb3a46e | 123 | if (c == 0) break; |
fbcosentino | 0:1655adb3a46e | 124 | } |
fbcosentino | 3:39fb12e8a2a3 | 125 | params_len = j; // length includes terminating null |
fbcosentino | 0:1655adb3a46e | 126 | } |
fbcosentino | 0:1655adb3a46e | 127 | else { |
fbcosentino | 0:1655adb3a46e | 128 | Value[0] = 0; // empty string |
fbcosentino | 0:1655adb3a46e | 129 | NumParams = 0; |
fbcosentino | 0:1655adb3a46e | 130 | params_len = 0; |
fbcosentino | 0:1655adb3a46e | 131 | } |
fbcosentino | 0:1655adb3a46e | 132 | |
fbcosentino | 0:1655adb3a46e | 133 | Param[0] = 0; // Param always begins as empty string |
fbcosentino | 0:1655adb3a46e | 134 | ParamLen = 0; |
fbcosentino | 0:1655adb3a46e | 135 | |
fbcosentino | 0:1655adb3a46e | 136 | param_cursor = 0; |
fbcosentino | 0:1655adb3a46e | 137 | |
fbcosentino | 0:1655adb3a46e | 138 | // If in auto-mode, invoke the callback |
fbcosentino | 0:1655adb3a46e | 139 | if (auto_mode) Process(); |
fbcosentino | 0:1655adb3a46e | 140 | } |
fbcosentino | 0:1655adb3a46e | 141 | |
fbcosentino | 0:1655adb3a46e | 142 | char* uTerminal::GetParam() { |
fbcosentino | 0:1655adb3a46e | 143 | int i; |
fbcosentino | 0:1655adb3a46e | 144 | char c; |
fbcosentino | 0:1655adb3a46e | 145 | |
fbcosentino | 0:1655adb3a46e | 146 | i = 0; |
fbcosentino | 0:1655adb3a46e | 147 | while (param_cursor < params_len) { |
fbcosentino | 0:1655adb3a46e | 148 | c = Value[param_cursor]; |
fbcosentino | 0:1655adb3a46e | 149 | if (c == ',') { |
fbcosentino | 0:1655adb3a46e | 150 | Param[i] = 0; |
fbcosentino | 0:1655adb3a46e | 151 | param_cursor++; |
fbcosentino | 0:1655adb3a46e | 152 | break; |
fbcosentino | 0:1655adb3a46e | 153 | } |
fbcosentino | 0:1655adb3a46e | 154 | if (c == 0) { |
fbcosentino | 0:1655adb3a46e | 155 | Param[i] = 0; |
fbcosentino | 0:1655adb3a46e | 156 | break; |
fbcosentino | 0:1655adb3a46e | 157 | } |
fbcosentino | 0:1655adb3a46e | 158 | else { |
fbcosentino | 0:1655adb3a46e | 159 | Param[i++] = c; |
fbcosentino | 0:1655adb3a46e | 160 | param_cursor++; |
fbcosentino | 0:1655adb3a46e | 161 | } |
fbcosentino | 0:1655adb3a46e | 162 | } |
fbcosentino | 0:1655adb3a46e | 163 | if (param_cursor >= params_len) Param[i] = 0; // null-terminated safe |
fbcosentino | 0:1655adb3a46e | 164 | |
fbcosentino | 0:1655adb3a46e | 165 | ParamLen = i; // does not include terminating null |
fbcosentino | 0:1655adb3a46e | 166 | |
fbcosentino | 0:1655adb3a46e | 167 | return Param; |
fbcosentino | 0:1655adb3a46e | 168 | } |
fbcosentino | 0:1655adb3a46e | 169 | |
fbcosentino | 0:1655adb3a46e | 170 | |
fbcosentino | 0:1655adb3a46e | 171 | int uTerminal::Process() { |
fbcosentino | 0:1655adb3a46e | 172 | // Be ready for next message in the background |
fbcosentino | 0:1655adb3a46e | 173 | int _has_cmd = has_command; |
fbcosentino | 0:1655adb3a46e | 174 | has_command = 0; |
fbcosentino | 0:1655adb3a46e | 175 | |
fbcosentino | 0:1655adb3a46e | 176 | // invoke the callback |
fbcosentino | 0:1655adb3a46e | 177 | if ((_has_cmd > 0) && (_callback != 0)) _callback(); |
fbcosentino | 0:1655adb3a46e | 178 | |
fbcosentino | 0:1655adb3a46e | 179 | // Return status |
fbcosentino | 0:1655adb3a46e | 180 | return _has_cmd; |
fbcosentino | 0:1655adb3a46e | 181 | } |
fbcosentino | 0:1655adb3a46e | 182 | |
fbcosentino | 0:1655adb3a46e | 183 | void uTerminal::print(char* str) { |
fbcosentino | 1:4e304b58f597 | 184 | if (is_usb) { |
fbcosentino | 1:4e304b58f597 | 185 | while (!_usbserial->connected()); // block until connected |
fbcosentino | 1:4e304b58f597 | 186 | _usbserial->printf(str); |
fbcosentino | 1:4e304b58f597 | 187 | } |
fbcosentino | 1:4e304b58f597 | 188 | else _serial->printf(str); |
fbcosentino | 0:1655adb3a46e | 189 | } |
fbcosentino | 0:1655adb3a46e | 190 | |
fbcosentino | 0:1655adb3a46e | 191 | void uTerminal::print(const char* str) { |
fbcosentino | 1:4e304b58f597 | 192 | print((char*)str); |
fbcosentino | 0:1655adb3a46e | 193 | } |
fbcosentino | 0:1655adb3a46e | 194 |