mirror of
https://github.com/taigrr/arduinolibs
synced 2025-01-18 04:33:12 -08:00
Special handling for TCP clients in the shell
This commit is contained in:
parent
6f03fa2cfc
commit
9221104977
@ -133,6 +133,7 @@ Shell::Shell()
|
||||
, historyPosn(0)
|
||||
, prom("> ")
|
||||
, hideChars(false)
|
||||
, isClient(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -152,7 +153,7 @@ Shell::~Shell()
|
||||
* \param maxHistory The number of commands to allocate in the history
|
||||
* stack for scrolling back through using Up/Down arrow keys.
|
||||
* \param mode The terminal mode to operate in, Terminal::Serial or
|
||||
* Terminal::Telnet.
|
||||
* Terminal::Telnet. Default is Terminal::Serial.
|
||||
* \return Returns true if the shell was initialized, or false if there
|
||||
* is insufficient memory for the history stack.
|
||||
*
|
||||
@ -169,6 +170,44 @@ Shell::~Shell()
|
||||
* \sa end(), setPrompt()
|
||||
*/
|
||||
bool Shell::begin(Stream &stream, size_t maxHistory, Terminal::Mode mode)
|
||||
{
|
||||
if (!beginShell(stream, maxHistory, mode))
|
||||
return false;
|
||||
isClient = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Begin shell handling on a connected TCP client.
|
||||
*
|
||||
* \param client The client to apply the shell to. This must be a
|
||||
* connected TCP client.
|
||||
* \param maxHistory The number of commands to allocate in the history
|
||||
* stack for scrolling back through using Up/Down arrow keys.
|
||||
* \param mode The terminal mode to operate in, Terminal::Serial or
|
||||
* Terminal::Telnet. Default is Terminal::Telnet.
|
||||
* \return Returns true if the shell was initialized, or false if there
|
||||
* is insufficient memory for the history stack.
|
||||
*
|
||||
* This override is provided as a convenience for starting a shell on a
|
||||
* TCP connection. This function also modifies the behaviour of the
|
||||
* builtin "exit" command to forcibly stop the TCP connection rather
|
||||
* than returning to the login prompt.
|
||||
*
|
||||
* \sa end(), setPrompt()
|
||||
*/
|
||||
bool Shell::begin(Client &client, size_t maxHistory, Terminal::Mode mode)
|
||||
{
|
||||
if (!beginShell(client, maxHistory, mode))
|
||||
return false;
|
||||
isClient = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Internal implementation of begin().
|
||||
*/
|
||||
bool Shell::beginShell(Stream &stream, size_t maxHistory, Terminal::Mode mode)
|
||||
{
|
||||
// Initialize the Terminal base class with the underlying stream.
|
||||
Terminal::begin(stream, mode);
|
||||
@ -217,6 +256,7 @@ void Shell::end()
|
||||
historyWrite = 0;
|
||||
historyPosn = 0;
|
||||
hideChars = false;
|
||||
isClient = false;
|
||||
}
|
||||
|
||||
/** @cond */
|
||||
@ -236,6 +276,12 @@ static char const builtin_cmd_help_alt[] PROGMEM = "?";
|
||||
*/
|
||||
void Shell::loop()
|
||||
{
|
||||
// If the stream is a TCP client, then check for disconnection.
|
||||
if (isClient && !((Client *)stream())->connected()) {
|
||||
end();
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the next key and bail out if none. We only process a single
|
||||
// key each time we enter this function to prevent other tasks in the
|
||||
// system from becoming starved of time resources if the bytes are
|
||||
@ -499,6 +545,21 @@ void Shell::help()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Exit from the shell back to the login prompt.
|
||||
*
|
||||
* If the underlying stream is a TCP client, then this function will
|
||||
* stop the client, causing disconnection.
|
||||
*/
|
||||
void Shell::exit()
|
||||
{
|
||||
Stream *stream = this->stream();
|
||||
if (isClient) {
|
||||
end();
|
||||
((Client *)stream)->stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Executes the command in the buffer.
|
||||
*/
|
||||
@ -538,6 +599,8 @@ void Shell::execute()
|
||||
if (!strcmp_P(argv0, builtin_cmd_help) ||
|
||||
!strcmp_P(argv0, builtin_cmd_help_alt)) {
|
||||
help();
|
||||
} else if (!strcmp_P(argv0, builtin_cmd_exit)) {
|
||||
exit();
|
||||
} else {
|
||||
static char const unknown_cmd[] PROGMEM = "Unknown command: ";
|
||||
writeProgMem(unknown_cmd);
|
||||
|
@ -24,6 +24,7 @@
|
||||
#define SHELL_h
|
||||
|
||||
#include "Terminal.h"
|
||||
#include <Client.h>
|
||||
|
||||
class Shell;
|
||||
class ShellArguments;
|
||||
@ -65,6 +66,7 @@ public:
|
||||
virtual ~Shell();
|
||||
|
||||
bool begin(Stream &stream, size_t maxHistory = 0, Terminal::Mode mode = Serial);
|
||||
bool begin(Client &client, size_t maxHistory = 0, Terminal::Mode mode = Telnet);
|
||||
void end();
|
||||
|
||||
void loop();
|
||||
@ -78,6 +80,7 @@ public:
|
||||
void setHideCharacters(bool hide);
|
||||
|
||||
void help();
|
||||
void exit();
|
||||
|
||||
private:
|
||||
char buffer[SHELL_MAX_CMD_LEN];
|
||||
@ -88,11 +91,13 @@ private:
|
||||
size_t historyPosn;
|
||||
const char *prom;
|
||||
bool hideChars;
|
||||
bool isClient;
|
||||
|
||||
// Disable copy constructor and operator=().
|
||||
Shell(const Shell &other) {}
|
||||
Shell &operator=(const Shell &) { return *this; }
|
||||
|
||||
bool beginShell(Stream &stream, size_t maxHistory, Terminal::Mode mode);
|
||||
void execute();
|
||||
bool execute(const ShellArguments &argv);
|
||||
void executeBuiltin(const char *cmd);
|
||||
|
@ -178,7 +178,7 @@ Terminal::~Terminal()
|
||||
* will be interpreted. This is useful if the underlying \a stream is a TCP
|
||||
* connection on port 23. The mode operates as a telnet server.
|
||||
*
|
||||
* \sa end(), mode()
|
||||
* \sa end(), stream(), mode()
|
||||
*/
|
||||
void Terminal::begin(Stream &stream, Mode mode)
|
||||
{
|
||||
@ -200,6 +200,14 @@ void Terminal::end()
|
||||
_stream = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \fn Stream *Terminal::stream() const
|
||||
* \brief Returns a pointer to the underlying Stream, or NULL if the
|
||||
* stream has not been set with begin() yet.
|
||||
*
|
||||
* \sa begin()
|
||||
*/
|
||||
|
||||
/**
|
||||
* \fn Terminal::Mode Terminal::mode() const
|
||||
* \brief Returns the mode this terminal is operating in, Serial or Telnet.
|
||||
|
@ -48,6 +48,7 @@ public:
|
||||
void begin(Stream &stream, Mode mode = Serial);
|
||||
void end();
|
||||
|
||||
Stream *stream() const { return _stream; }
|
||||
Terminal::Mode mode() const { return (Terminal::Mode)mod; }
|
||||
|
||||
virtual int available();
|
||||
|
@ -29,13 +29,7 @@ void cmdLed(Shell &shell, int argc, const ShellArguments &argv)
|
||||
digitalWrite(ledPin, LOW);
|
||||
}
|
||||
|
||||
void cmdExit(Shell &shell, int argc, const ShellArguments &argv)
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
ShellCommand(led, "Turns the status LED on or off", cmdLed);
|
||||
ShellCommand(exit, "Exit and log out", cmdExit);
|
||||
|
||||
void setup()
|
||||
{
|
||||
@ -72,7 +66,7 @@ void loop()
|
||||
client = server.available();
|
||||
if (client) {
|
||||
haveClient = true;
|
||||
shell.begin(client, 5, Terminal::Telnet);
|
||||
shell.begin(client, 5);
|
||||
}
|
||||
} else if (!client.connected()) {
|
||||
// The current client has been disconnected. Shut down the shell.
|
||||
|
Loading…
x
Reference in New Issue
Block a user