This is a console for interacting with Vodafone dongles.

Dependencies:   mbed-rtos VodafoneUSBModem mbed

This is a bridge between a serial driven console and a serial driven cellular modem or modem interface. This was written to complement our collaboration with mbed: See https://mbed.org/users/mbed_official/code/VodafoneUSBModem/ for further information.

For example, one can use GNU screen or PuTTY (two popular consoles) to interact with a Vodafone K3770 USB dongle. In the image below I used the UNIX version of PuTTY:

/media/uploads/ashleymills/atcons.png

Support is provided for line-based consoles, which send one line at a time, and for character based consoles.

For character based consoles, the following line-editing features are provided:

  • In-line editing (deletion, left/right arrow keys, insertion)
  • Command history (via up/down arrow keys)

Line buffer length, and command history depth, are compile-time options.

--

How to use:

Compile and save to mbed.

Connect PuTTY or GNU screen to serial port.

If you use GNU screen you probably already know what you are doing.

If you use PuTTY, you need to set the options to specify the serial device and, set the baud rate, and set the "Connection Type" to "Serial":

/media/uploads/ashleymills/putty0.png

You need to set the keyboard to send Control-H for backspace, and use "Linux" function keys and keypad:

/media/uploads/ashleymills/putty1.png

Console.cpp

Committer:
ashleymills
Date:
2013-09-25
Revision:
14:3f5fd1d95f5f
Parent:
6:93003e18889c

File content as of revision 14:3f5fd1d95f5f:

#include "Console.h"
//#define DEBUG

Console::Console(Serial *terminal, int lineLength, int numLines, bool characterBased)
    : _terminal(terminal), _lineLength(lineLength), _numLines(numLines), _characterBased(characterBased) {
    
    _terminal->printf("Console ready!\r\n");
    
    // set the buffer timeout
    _bufferWaitTimeout_ms = BUFFER_WAIT_TIMEOUT_MS;
     
    // allocate space for current line
    _lineBuffer = (char*)malloc((_lineLength+1)*sizeof(char));
    
    // character based consoles need a history
    if(_characterBased) {
       _lines = (char**)malloc(_numLines*sizeof(char*));
       for(int i=0; i<_numLines; i++) {
          _lines[i] = (char*)malloc((_lineLength+1)*sizeof(char));
       }
    
       // blank out current line with NULLs
       for(int i=0; i<=_lineLength; i++)
          _lineBuffer[i] = 0x00;
    }
    
    // set line position, number of used lines, and line buffer pointer to 0    
    _linePos     = 0;
    _prevLinePos = 0;
    _usedLines   = 0;
    _currentLine = 0;
}

// destructor
Console::~Console() {
    free(_lineBuffer);
}

// store the current lineBuffer in the history
void Console::storeBuffer() {
    // only do so if history specified
    if(_numLines==0)
        return;
    
    // imagine the command history as a FILO buffer
    // here we rightshift the command history    
    if(_usedLines==_numLines-1) {
        char* p = _lines[0];
        for(int i=0; i<_numLines-1; i++) {
            _lines[i] = _lines[i+1];
        }
        _lines[_numLines-1] = p;
    }
    
    // and insert the current line in the newest position
    strncpy(_lines[_usedLines],_lineBuffer,_lineLength+1);
    
    // this just deals with the filling up stage
    if(_usedLines<_numLines-1) {
        _usedLines++;
        if(_currentLine<_usedLines)
            _currentLine = _usedLines;
    } else {
        _currentLine = _usedLines+1;
    }
}

// clear the current-line buffer
void Console::clearBuffer() {
    _linePos=0;
    for(int i=0; i<=_lineLength; i++)
        _lineBuffer[i] = 0x00;
}

// load the next buffer in the line history (activated by DOWN key)
void Console::loadNextBuffer() {
    if(_currentLine<_usedLines) {
        _currentLine++;
    } else {
        _linePos=0;
        for(int i=0; i<=_lineLength; i++)
            _lineBuffer[i] = 0x00;
        return;
    }
    strncpy(_lineBuffer,_lines[_currentLine],_lineLength+1);
    _prevLinePos = _linePos;
    _linePos=0;
    while(_lineBuffer[_linePos]!=0x00)
        _linePos++;
}

// load the previous buffer in the line history (activated by UP key)
void Console::loadPreviousBuffer() {
    if(_currentLine>0) {
        _currentLine--;
    }
    strncpy(_lineBuffer,_lines[_currentLine],_lineLength+1);
    _prevLinePos = _linePos;
    _linePos=0;
    while(_lineBuffer[_linePos]!=0x00)
        _linePos++;
}

// process a command entered (received by CRLF)
void Console::processCommand() {
    _terminal->printf("Command: \"%s\"\r\n",_lineBuffer);
}

// wait on the console for input, returns false on timeout
// this is useful for processing escape chars
bool Console::waitForInput() {
    Timer timer;
    timer.start();
    while(!_terminal->readable()&&timer.read_ms()<_bufferWaitTimeout_ms);
    return _terminal->readable();
}

// print the entire command history
void Console::printHistory() {
    for(int i=0; i<_numLines; i++)
        printBuffer(i);
}

// print the command at index in the history
void Console::printBuffer(int index) {
    if(index==_currentLine)
        _terminal->printf("> ");
    else
        _terminal->printf("  ");
    _terminal->printf("%d) \"%s\"\r\n",index,_lines[index]);
}


void Console::reprintBuffer() {
    _terminal->putc('\r');
    for(int i=0; i<_lineLength; i++) {;
        _terminal->putc(' ');
    }
    
    _terminal->putc('\r');
    if(_linePos>0) {
       _terminal->printf("%s",_lineBuffer);
       _terminal->putc('\r');
       for(int i=0; i<_linePos; i++) {;
            _terminal->putc(0x1b);
            _terminal->putc('[');
            _terminal->putc('C');
       }
    }
}

// print the current-line buffer including debugging stuff
void Console::printLineBuffer() {
    printHistory();
    _terminal->printf("C) \"%s\"\r\n",_lineBuffer);
    _terminal->printf("   \"");
    for(int i=0; i<_linePos; i++) {
        _terminal->printf(" ");
    }
    _terminal->printf("^");
    for(int i=_linePos+1; i<_lineLength; i++) {
        _terminal->printf(" ");
    }
    _terminal->printf("\"\r\n");
    for(int i=0; i<=_lineLength; i++) {
        _terminal->printf("%x ",_lineBuffer[i]);
    }
    _terminal->printf("\r\n");
}

void Console::updateLineBased() {
   //_terminal->printf("line based\r\n");
   // save until a line is read and then dump to the modem
   while(_terminal->readable()) {
      int c = _terminal->getc();
      if(_linePos<_lineLength) {
         
         _lineBuffer[_linePos++] = c;
         _terminal->printf("%c",c);
         // activate process command when
         if(c==0x0a) {
            processCommand();
            clearBuffer();
            return;
         }
      } else {
         _terminal->printf("WARNING, max line length exceeded!!!");
      }
      
   }      
}

void Console::updateCharacterBased() {
// process console input
    while(_terminal->readable()) {
        int c = _terminal->getc();
        switch(c) {
            // backspace
            case 0x08:
                if(_linePos>0) {
                    // case where pointer is at end of line
                    if(_lineBuffer[_linePos]==0x00) {
                        _lineBuffer[--_linePos] = 0x00;
                    } else {
                        // case where pointer is somewhere in the middle of the line
                        int copyPointer = --_linePos;
                        while(_lineBuffer[copyPointer]!=0x00) {
                            _lineBuffer[copyPointer] = _lineBuffer[copyPointer+1];
                            copyPointer++;
                        }
                    }
                    
                    reprintBuffer();
                }           
            break;
                
            // escape sequence 0x1b 0x5b
            case 0x1b:
                // check that escape sequence exists
                if(waitForInput()&&_terminal->getc()==0x5b) {
                        
                    // process escape characters
                    if(waitForInput()) {
                        c = _terminal->getc();
                        switch(c) {
                            // up
                            case 0x41:
                                loadPreviousBuffer();
                                reprintBuffer();
                            break;
                                
                            // down
                            case 0x42:
                                loadNextBuffer();
                                reprintBuffer();
                            break;
                                
                            // left
                            case 0x44:
                                if(_linePos>0) {
                                    _linePos--;
                                    _terminal->putc('\b');
                                }
                            break;
                                
                            // right
                            case 0x43:
                                // only move right within a string upto its end
                                if(_lineBuffer[_linePos]!=0x00) {
                                    _linePos++;
                                    _terminal->putc(0x1b);
                                    _terminal->putc('[');
                                    _terminal->putc('C');
                                }
                            break;
                        }
                    }
                }
            break;
                
            // carriage return
            case 0x0d:
                storeBuffer();
                processCommand();
                clearBuffer();
            break;
                
            default:
                if(_linePos<_lineLength) {
                    // INS mode
                    if(false) {
                        _lineBuffer[_linePos++] = c;
                        _terminal->printf("%c",c);
                    } else {    
                        if(_lineBuffer[_linePos]==0x00) {
                            _lineBuffer[_linePos++] = c;
                        } else {
                            // move everything to the right
                            // so long as string end isn't at end of buffer
                            int strEnd = _linePos;
                            while(_lineBuffer[++strEnd]!=0x00);
                            if(strEnd!=_lineLength) {
                                int copyPointer = _lineLength;
                                while(--copyPointer!=_linePos) {
                                    _lineBuffer[copyPointer] = _lineBuffer[copyPointer-1];
                                }
                                
                                // insert character
                                _lineBuffer[_linePos++] = c;
                            }
                        }  
                        reprintBuffer();
                    }
                    
                }
                  
            break;
        }
            
        #ifdef DEBUG
        printLineBuffer();
        #endif
    }
}

// process the console
void Console::update() {
   if(_characterBased) {
      updateCharacterBased();
   } else {
      updateLineBased();
   }
}