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)
|
, historyPosn(0)
|
||||||
, prom("> ")
|
, prom("> ")
|
||||||
, hideChars(false)
|
, hideChars(false)
|
||||||
|
, isClient(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +153,7 @@ Shell::~Shell()
|
|||||||
* \param maxHistory The number of commands to allocate in the history
|
* \param maxHistory The number of commands to allocate in the history
|
||||||
* stack for scrolling back through using Up/Down arrow keys.
|
* stack for scrolling back through using Up/Down arrow keys.
|
||||||
* \param mode The terminal mode to operate in, Terminal::Serial or
|
* \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
|
* \return Returns true if the shell was initialized, or false if there
|
||||||
* is insufficient memory for the history stack.
|
* is insufficient memory for the history stack.
|
||||||
*
|
*
|
||||||
@ -169,6 +170,44 @@ Shell::~Shell()
|
|||||||
* \sa end(), setPrompt()
|
* \sa end(), setPrompt()
|
||||||
*/
|
*/
|
||||||
bool Shell::begin(Stream &stream, size_t maxHistory, Terminal::Mode mode)
|
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.
|
// Initialize the Terminal base class with the underlying stream.
|
||||||
Terminal::begin(stream, mode);
|
Terminal::begin(stream, mode);
|
||||||
@ -217,6 +256,7 @@ void Shell::end()
|
|||||||
historyWrite = 0;
|
historyWrite = 0;
|
||||||
historyPosn = 0;
|
historyPosn = 0;
|
||||||
hideChars = false;
|
hideChars = false;
|
||||||
|
isClient = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @cond */
|
/** @cond */
|
||||||
@ -236,6 +276,12 @@ static char const builtin_cmd_help_alt[] PROGMEM = "?";
|
|||||||
*/
|
*/
|
||||||
void Shell::loop()
|
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
|
// 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
|
// key each time we enter this function to prevent other tasks in the
|
||||||
// system from becoming starved of time resources if the bytes are
|
// 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.
|
* \brief Executes the command in the buffer.
|
||||||
*/
|
*/
|
||||||
@ -538,6 +599,8 @@ void Shell::execute()
|
|||||||
if (!strcmp_P(argv0, builtin_cmd_help) ||
|
if (!strcmp_P(argv0, builtin_cmd_help) ||
|
||||||
!strcmp_P(argv0, builtin_cmd_help_alt)) {
|
!strcmp_P(argv0, builtin_cmd_help_alt)) {
|
||||||
help();
|
help();
|
||||||
|
} else if (!strcmp_P(argv0, builtin_cmd_exit)) {
|
||||||
|
exit();
|
||||||
} else {
|
} else {
|
||||||
static char const unknown_cmd[] PROGMEM = "Unknown command: ";
|
static char const unknown_cmd[] PROGMEM = "Unknown command: ";
|
||||||
writeProgMem(unknown_cmd);
|
writeProgMem(unknown_cmd);
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
#define SHELL_h
|
#define SHELL_h
|
||||||
|
|
||||||
#include "Terminal.h"
|
#include "Terminal.h"
|
||||||
|
#include <Client.h>
|
||||||
|
|
||||||
class Shell;
|
class Shell;
|
||||||
class ShellArguments;
|
class ShellArguments;
|
||||||
@ -65,6 +66,7 @@ public:
|
|||||||
virtual ~Shell();
|
virtual ~Shell();
|
||||||
|
|
||||||
bool begin(Stream &stream, size_t maxHistory = 0, Terminal::Mode mode = Serial);
|
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 end();
|
||||||
|
|
||||||
void loop();
|
void loop();
|
||||||
@ -78,6 +80,7 @@ public:
|
|||||||
void setHideCharacters(bool hide);
|
void setHideCharacters(bool hide);
|
||||||
|
|
||||||
void help();
|
void help();
|
||||||
|
void exit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char buffer[SHELL_MAX_CMD_LEN];
|
char buffer[SHELL_MAX_CMD_LEN];
|
||||||
@ -88,11 +91,13 @@ private:
|
|||||||
size_t historyPosn;
|
size_t historyPosn;
|
||||||
const char *prom;
|
const char *prom;
|
||||||
bool hideChars;
|
bool hideChars;
|
||||||
|
bool isClient;
|
||||||
|
|
||||||
// Disable copy constructor and operator=().
|
// Disable copy constructor and operator=().
|
||||||
Shell(const Shell &other) {}
|
Shell(const Shell &other) {}
|
||||||
Shell &operator=(const Shell &) { return *this; }
|
Shell &operator=(const Shell &) { return *this; }
|
||||||
|
|
||||||
|
bool beginShell(Stream &stream, size_t maxHistory, Terminal::Mode mode);
|
||||||
void execute();
|
void execute();
|
||||||
bool execute(const ShellArguments &argv);
|
bool execute(const ShellArguments &argv);
|
||||||
void executeBuiltin(const char *cmd);
|
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
|
* 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.
|
* 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)
|
void Terminal::begin(Stream &stream, Mode mode)
|
||||||
{
|
{
|
||||||
@ -200,6 +200,14 @@ void Terminal::end()
|
|||||||
_stream = 0;
|
_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
|
* \fn Terminal::Mode Terminal::mode() const
|
||||||
* \brief Returns the mode this terminal is operating in, Serial or Telnet.
|
* \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 begin(Stream &stream, Mode mode = Serial);
|
||||||
void end();
|
void end();
|
||||||
|
|
||||||
|
Stream *stream() const { return _stream; }
|
||||||
Terminal::Mode mode() const { return (Terminal::Mode)mod; }
|
Terminal::Mode mode() const { return (Terminal::Mode)mod; }
|
||||||
|
|
||||||
virtual int available();
|
virtual int available();
|
||||||
|
@ -29,13 +29,7 @@ void cmdLed(Shell &shell, int argc, const ShellArguments &argv)
|
|||||||
digitalWrite(ledPin, LOW);
|
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(led, "Turns the status LED on or off", cmdLed);
|
||||||
ShellCommand(exit, "Exit and log out", cmdExit);
|
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
@ -72,7 +66,7 @@ void loop()
|
|||||||
client = server.available();
|
client = server.available();
|
||||||
if (client) {
|
if (client) {
|
||||||
haveClient = true;
|
haveClient = true;
|
||||||
shell.begin(client, 5, Terminal::Telnet);
|
shell.begin(client, 5);
|
||||||
}
|
}
|
||||||
} else if (!client.connected()) {
|
} else if (!client.connected()) {
|
||||||
// The current client has been disconnected. Shut down the shell.
|
// The current client has been disconnected. Shut down the shell.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user