diff --git a/Sming/Components/CommandProcessing/README.rst b/Sming/Components/CommandProcessing/README.rst new file mode 100644 index 0000000000..bdaad7ee9c --- /dev/null +++ b/Sming/Components/CommandProcessing/README.rst @@ -0,0 +1,62 @@ +Command Processing +================== + +.. highlight:: c++ + +Introduction +------------ + +Command handler provides a common command line interface (CLI). Command line must be text. Commands should be separated with a single character. +CLI can be used with: + +- Serial +- Network (Websockets, Telnet) + +and all communication protocols that are exchanging text data. + +Commands can be added to and removed from the command handler. Each command will trigger a defined Delegate. + +A welcome message may be shown when a user connects and end-of-line (EOL) character may be defined. An automatic "help" display is available. + +For more examples take a look at the +:sample:`CommandLine`, +:sample:`TelnetServer` +and :sample:`HttpServer_WebSockets` +samples. + + +Using +----- + +1. Add these lines to your application componenent.mk file:: + + COMPONENT_DEPENDS += CommandProcessing + +2. Add these lines to your application:: + + #include + +3. Basic example:: + + #include + + CommandProcessing::Handler commandHandler; + + void processShutdownCommand(String commandLine, ReadWriteStream& commandOutput) + { + // ... + } + + void init() + { + commandHandler.registerSystemCommands(); + commandHandler.registerCommand(CommandProcessing::Command("shutdown", "Shutdown Server Command", "Application", processShutdownCommand)); + } + +API Documentation +----------------- + +.. doxygengroup:: commandhandler + :content-only: + :members: + diff --git a/Sming/Components/CommandProcessing/component.mk b/Sming/Components/CommandProcessing/component.mk new file mode 100644 index 0000000000..71c9f17265 --- /dev/null +++ b/Sming/Components/CommandProcessing/component.mk @@ -0,0 +1,10 @@ +COMPONENT_SRCDIRS := \ + src \ + $(call ListAllSubDirs,$(COMPONENT_PATH)/src) \ + +COMPONENT_INCDIRS := $(COMPONENT_SRCDIRS) + +COMPONENT_DOXYGEN_INPUT := src + +COMPONENT_DOCFILES := \ + docs/* \ No newline at end of file diff --git a/Sming/Components/CommandProcessing/samples/.cs b/Sming/Components/CommandProcessing/samples/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/Arducam/Makefile b/Sming/Components/CommandProcessing/samples/Arducam/Makefile similarity index 100% rename from samples/Arducam/Makefile rename to Sming/Components/CommandProcessing/samples/Arducam/Makefile diff --git a/samples/Arducam/README.rst b/Sming/Components/CommandProcessing/samples/Arducam/README.rst similarity index 100% rename from samples/Arducam/README.rst rename to Sming/Components/CommandProcessing/samples/Arducam/README.rst diff --git a/Sming/Components/CommandProcessing/samples/Arducam/app/ArduCamCommand.cpp b/Sming/Components/CommandProcessing/samples/Arducam/app/ArduCamCommand.cpp new file mode 100644 index 0000000000..c4bd3cddb3 --- /dev/null +++ b/Sming/Components/CommandProcessing/samples/Arducam/app/ArduCamCommand.cpp @@ -0,0 +1,226 @@ + +#include +#include +#include + +ArduCamCommand::ArduCamCommand(ArduCAM& CAM, CommandProcessing::Handler& commandHandler) + : myCAM(CAM), commandHandler(&commandHandler), imgSize(OV2640_320x240), imgType(JPEG) +{ + debug_d("ArduCamCommand Instantiating"); +} + +ArduCamCommand::~ArduCamCommand() +{ +} + +void ArduCamCommand::initCommand() +{ + commandHandler->registerCommand( + CommandProcessing::Command("set", "ArduCAM config commands", "Application", + CommandProcessing::Command::Callback(&ArduCamCommand::processSetCommands, this))); +} + +void ArduCamCommand::showSettings(ReadWriteStream& commandOutput) +{ + // review settings + commandOutput << _F("ArduCam Settings:") << endl + << _F(" img Type: [") << getImageType() << ']' << endl + << _F(" img Size: [") << getImageSize() << ']' << endl; +}; + +void ArduCamCommand::processSetCommands(String commandLine, ReadWriteStream& commandOutput) +{ + Vector commandToken; + int numToken = splitString(commandLine, ' ', commandToken); + + if(numToken == 1) { + // review settings + showSettings(commandOutput); + } + // handle command -> set + else if(commandToken[1] == "help") { + commandOutput << _F("set img [bmp|jpeg]") << endl; + commandOutput << _F("set size [160|176|320|352|640|800|1024|1280|1600]") << endl; + } + + // handle command -> set + else if(commandToken[1] == "img") { + if(numToken == 3) { + if(commandToken[2] == "bmp") { + // TODO: set image size and init cam + // settings->setImageType(BMP); + setFormat(BMP); + } else if(commandToken[2] == "jpg") { + setFormat(JPEG); + } else { + commandOutput << _F("invalid image format [") << commandToken[2] << ']' << endl; + } + } else { + commandOutput << _F("Syntax: set img [bmp|jpeg]") << endl; + } + showSettings(commandOutput); + } + + else if(commandToken[1] == "size") { + if(numToken == 3) { + if(commandToken[2] == "160") { + imgSize = OV2640_160x120; + myCAM.OV2640_set_JPEG_size(OV2640_160x120); + setFormat(JPEG); + } else if(commandToken[2] == "176") { + imgSize = OV2640_176x144; + myCAM.OV2640_set_JPEG_size(OV2640_176x144); + setFormat(JPEG); + } else if(commandToken[2] == "320") { + imgSize = OV2640_320x240; + myCAM.OV2640_set_JPEG_size(OV2640_320x240); + } else if(commandToken[2] == "352") { + imgSize = OV2640_352x288; + myCAM.OV2640_set_JPEG_size(OV2640_352x288); + setFormat(JPEG); + } else if(commandToken[2] == "640") { + imgSize = OV2640_640x480; + myCAM.OV2640_set_JPEG_size(OV2640_640x480); + setFormat(JPEG); + } else if(commandToken[2] == "800") { + imgSize = OV2640_800x600; + myCAM.OV2640_set_JPEG_size(OV2640_800x600); + setFormat(JPEG); + } else if(commandToken[2] == "1024") { + imgSize = OV2640_1024x768; + myCAM.OV2640_set_JPEG_size(OV2640_1024x768); + setFormat(JPEG); + } else if(commandToken[2] == "1280") { + imgSize = OV2640_1280x1024; + myCAM.OV2640_set_JPEG_size(OV2640_1280x1024); + setFormat(JPEG); + } else if(commandToken[2] == "1600") { + imgSize = OV2640_1600x1200; + myCAM.OV2640_set_JPEG_size(OV2640_1600x1200); + setFormat(JPEG); + } else { + commandOutput << _F("invalid size definition[") << commandToken[2] << ']' << endl; + } + } else { + commandOutput << _F("Syntax: set size [160|176|320|352|640|800|1024|1280|1600]") << endl; + } + showSettings(commandOutput); + } +} + +void ArduCamCommand::setSize(const String& size) +{ + if(size == "160x120") { + imgSize = OV2640_160x120; + myCAM.OV2640_set_JPEG_size(OV2640_160x120); + setFormat(JPEG); + } else if(size == "176x144") { + imgSize = OV2640_176x144; + myCAM.OV2640_set_JPEG_size(OV2640_176x144); + setFormat(JPEG); + } else if(size == "320x240") { + imgSize = OV2640_320x240; + myCAM.OV2640_set_JPEG_size(OV2640_320x240); + } else if(size == "352x288") { + imgSize = OV2640_352x288; + myCAM.OV2640_set_JPEG_size(OV2640_352x288); + setFormat(JPEG); + } else if(size == "640x480") { + imgSize = OV2640_640x480; + myCAM.OV2640_set_JPEG_size(OV2640_640x480); + setFormat(JPEG); + } else if(size == "800x600") { + imgSize = OV2640_800x600; + myCAM.OV2640_set_JPEG_size(OV2640_800x600); + setFormat(JPEG); + } else if(size == "1024x768") { + imgSize = OV2640_1024x768; + myCAM.OV2640_set_JPEG_size(OV2640_1024x768); + setFormat(JPEG); + } else if(size == "1280x1024") { + imgSize = OV2640_1280x1024; + myCAM.OV2640_set_JPEG_size(OV2640_1280x1024); + setFormat(JPEG); + } else if(size == "1600x1200") { + imgSize = OV2640_1600x1200; + myCAM.OV2640_set_JPEG_size(OV2640_1600x1200); + setFormat(JPEG); + } else { + debugf("ERROR: invalid size definition[%s]\r\n", size.c_str()); + } +} + +void ArduCamCommand::setType(const String& type) +{ + setFormat(type == "BMP" ? BMP : JPEG); +} + +void ArduCamCommand::setFormat(uint8 type) +{ + if(type == BMP) { + myCAM.set_format(BMP); + if(imgType != BMP) { + // reset the cam + myCAM.InitCAM(); + imgType = BMP; + imgSize = OV2640_320x240; + } + } else { + myCAM.set_format(JPEG); + // reset the cam + if(imgType != JPEG) { + // reset the cam + myCAM.InitCAM(); + myCAM.OV2640_set_JPEG_size(imgSize); + imgType = JPEG; + } + } +} + +const char* ArduCamCommand::getImageType() +{ + switch(imgType) { + case JPEG: + return "JPEG"; + case BMP: + default: + return "BMP"; + } +} + +const char* ArduCamCommand::getContentType() +{ + switch(imgType) { + case JPEG: + return "image/jpeg"; + case BMP: + default: + return "image/x-ms-bmp"; + } +} + +const char* ArduCamCommand::getImageSize() +{ + switch(imgSize) { + case OV2640_1600x1200: + return "1600x1200"; + case OV2640_1280x1024: + return "1280x1024"; + case OV2640_1024x768: + return "1024x768"; + case OV2640_800x600: + return "800x600"; + case OV2640_640x480: + return "640x480"; + case OV2640_352x288: + return "352x288"; + case OV2640_320x240: + return "320x240"; + case OV2640_176x144: + return "176x144"; + case OV2640_160x120: + return "160x120"; + default: + return "320x240"; + } +} diff --git a/samples/Arducam/app/application.cpp b/Sming/Components/CommandProcessing/samples/Arducam/app/application.cpp similarity index 91% rename from samples/Arducam/app/application.cpp rename to Sming/Components/CommandProcessing/samples/Arducam/app/application.cpp index 228601605b..fdc8ca2ac3 100644 --- a/samples/Arducam/app/application.cpp +++ b/Sming/Components/CommandProcessing/samples/Arducam/app/application.cpp @@ -1,8 +1,6 @@ #include -#include -#include +#include -//#include "CamSettings.h" #include #include @@ -37,14 +35,14 @@ #define CAM_CS 16 // this pins are free to change -TelnetServer telnet; +namespace +{ HttpServer server; -HexDump hdump; +CommandProcessing::Handler commandHandler; ArduCAM myCAM(OV2640, CAM_CS); - -ArduCamCommand arduCamCommand(&myCAM); +ArduCamCommand arduCamCommand(myCAM, commandHandler); SPISettings spiSettings(20000000, MSBFIRST, SPI_MODE0); @@ -56,6 +54,13 @@ void startApplicationCommand() arduCamCommand.initCommand(); } +bool processTelnetInput(TcpClient& client, char* data, int size) +{ + return client.sendString(commandHandler.processNow(data, size)); +} + +TcpServer telnetServer(processTelnetInput); + /* * initCam() * @@ -143,11 +148,11 @@ void onCamSetup(HttpRequest& request, HttpResponse& response) if(request.method == HTTP_POST) { type = request.getPostParameter("type"); debugf("set type %s", type.c_str()); - arduCamCommand.set_type(type); + arduCamCommand.setType(type); size = request.getPostParameter("size"); debugf("set size %s", size.c_str()); - arduCamCommand.set_size(size); + arduCamCommand.setSize(size); } response.sendString("OK"); @@ -220,7 +225,7 @@ void onFavicon(HttpRequest& request, HttpResponse& response) * telnet can be used to configure camera settings * using ArdCammCommand handler */ -void StartServers() +void startServers() { server.listen(80); server.paths.set("/", onIndex); @@ -234,9 +239,7 @@ void StartServers() Serial.println(WifiStation.getIP()); Serial.println(_F("==============================\r\n")); - telnet.listen(23); - telnet.enableDebug(true); - + telnetServer.listen(23); Serial.println(_F("\r\n=== TelnetServer SERVER STARTED ===")); Serial.println(_F("==============================\r\n")); } @@ -244,20 +247,21 @@ void StartServers() // Will be called when station is fully operational void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway) { - StartServers(); + startServers(); } +} // namespace + void init() { spiffs_mount(); // Mount file system, in order to work with files Serial.begin(SERIAL_BAUD_RATE); // 115200 by default - Serial.systemDebugOutput(true); // Allow debug output to serial - - Debug.setDebug(Serial); - Serial.systemDebugOutput(true); // Enable debug output to serial - Serial.commandProcessing(true); + + // Process commands from serial + commandHandler.setVerbose(true); + CommandProcessing::enable(commandHandler, Serial); WifiStation.enable(true); WifiStation.config(WIFI_SSID, WIFI_PWD); diff --git a/Sming/Components/CommandProcessing/samples/Arducam/component.mk b/Sming/Components/CommandProcessing/samples/Arducam/component.mk new file mode 100644 index 0000000000..cdae913e95 --- /dev/null +++ b/Sming/Components/CommandProcessing/samples/Arducam/component.mk @@ -0,0 +1,3 @@ +ARDUINO_LIBRARIES := ArduCAM CommandProcessing +HWCONFIG = spiffs-2m +SPIFF_FILES = web/build diff --git a/Sming/Components/CommandProcessing/samples/Arducam/include/ArduCamCommand.h b/Sming/Components/CommandProcessing/samples/Arducam/include/ArduCamCommand.h new file mode 100644 index 0000000000..e3f3ffc1c9 --- /dev/null +++ b/Sming/Components/CommandProcessing/samples/Arducam/include/ArduCamCommand.h @@ -0,0 +1,35 @@ +/* + * ArduCamCommand.h + * + */ + +#pragma once + +#include "WString.h" +#include +#include + +class ArduCamCommand +{ +public: + ArduCamCommand(ArduCAM& CAM, CommandProcessing::Handler& commandHandler); + virtual ~ArduCamCommand(); + void initCommand(); + const char* getContentType(); + void setSize(const String& size); + void setType(const String& type); + +private: + bool status = true; + ArduCAM myCAM; + CommandProcessing::Handler* commandHandler{nullptr}; + uint8 imgType; + uint8 imgSize; + void processSetCommands(String commandLine, ReadWriteStream& commandOutput); + + void setFormat(uint8 type); + void showSettings(ReadWriteStream& commandOutput); + + const char* getImageType(); + const char* getImageSize(); +}; diff --git a/samples/Arducam/web/build/Sming.png b/Sming/Components/CommandProcessing/samples/Arducam/web/build/Sming.png similarity index 100% rename from samples/Arducam/web/build/Sming.png rename to Sming/Components/CommandProcessing/samples/Arducam/web/build/Sming.png diff --git a/samples/Arducam/web/build/grids-responsive-min.css b/Sming/Components/CommandProcessing/samples/Arducam/web/build/grids-responsive-min.css similarity index 100% rename from samples/Arducam/web/build/grids-responsive-min.css rename to Sming/Components/CommandProcessing/samples/Arducam/web/build/grids-responsive-min.css diff --git a/samples/Arducam/web/build/index.html b/Sming/Components/CommandProcessing/samples/Arducam/web/build/index.html similarity index 100% rename from samples/Arducam/web/build/index.html rename to Sming/Components/CommandProcessing/samples/Arducam/web/build/index.html diff --git a/samples/Arducam/web/build/layout.css b/Sming/Components/CommandProcessing/samples/Arducam/web/build/layout.css similarity index 100% rename from samples/Arducam/web/build/layout.css rename to Sming/Components/CommandProcessing/samples/Arducam/web/build/layout.css diff --git a/samples/Arducam/web/build/minified.js b/Sming/Components/CommandProcessing/samples/Arducam/web/build/minified.js similarity index 100% rename from samples/Arducam/web/build/minified.js rename to Sming/Components/CommandProcessing/samples/Arducam/web/build/minified.js diff --git a/samples/Arducam/web/build/pure-min.css b/Sming/Components/CommandProcessing/samples/Arducam/web/build/pure-min.css similarity index 100% rename from samples/Arducam/web/build/pure-min.css rename to Sming/Components/CommandProcessing/samples/Arducam/web/build/pure-min.css diff --git a/samples/CommandProcessing_Debug/Makefile b/Sming/Components/CommandProcessing/samples/CommandLine/Makefile similarity index 100% rename from samples/CommandProcessing_Debug/Makefile rename to Sming/Components/CommandProcessing/samples/CommandLine/Makefile diff --git a/Sming/Components/CommandProcessing/samples/CommandLine/README.rst b/Sming/Components/CommandProcessing/samples/CommandLine/README.rst new file mode 100644 index 0000000000..29324f136a --- /dev/null +++ b/Sming/Components/CommandProcessing/samples/CommandLine/README.rst @@ -0,0 +1,4 @@ +CommandLine +=========== + +Demonstrates Sming's CommandProcessing capability via serial interface. diff --git a/Sming/Components/CommandProcessing/samples/CommandLine/app/application.cpp b/Sming/Components/CommandProcessing/samples/CommandLine/app/application.cpp new file mode 100644 index 0000000000..c91c116de1 --- /dev/null +++ b/Sming/Components/CommandProcessing/samples/CommandLine/app/application.cpp @@ -0,0 +1,52 @@ +#include +#include + +CommandProcessing::Handler commandHandler; + +namespace +{ +bool exampleStatus = true; + +// Example Command + +void processExampleCommand(String commandLine, ReadWriteStream& commandOutput) +{ + Vector commandToken; + int numToken = splitString(commandLine, ' ', commandToken); + + // First token is "example" + if(numToken == 1) { + commandOutput << _F("Example Commands available :") << endl; + commandOutput << _F("on : Set example status ON") << endl; + commandOutput << _F("off : Set example status OFF") << endl; + commandOutput << _F("status : Show example status") << endl; + } else if(commandToken[1] == "on") { + exampleStatus = true; + commandOutput << _F("Status ON") << endl; + } else if(commandToken[1] == "off") { + exampleStatus = false; + commandOutput << _F("Status OFF") << endl; + } else if(commandToken[1] == "status") { + commandOutput << _F("Example Status is ") << (exampleStatus ? "ON" : "OFF") << endl; + } else { + commandOutput << _F("Bad command") << endl; + } +} + +} // namespace + +void init() +{ + Serial.begin(SERIAL_BAUD_RATE); // Begin serial output + + // Set verbosity + Serial.systemDebugOutput(true); // Enable debug output to serial + commandHandler.setVerbose(true); + + // Register Input/Output streams + CommandProcessing::enable(commandHandler, Serial); + + commandHandler.registerSystemCommands(); + commandHandler.registerCommand( + CommandProcessing::Command("example", "Example Command", "Application", processExampleCommand)); +} diff --git a/Sming/Components/CommandProcessing/samples/CommandLine/component.mk b/Sming/Components/CommandProcessing/samples/CommandLine/component.mk new file mode 100644 index 0000000000..e9d588c3b4 --- /dev/null +++ b/Sming/Components/CommandProcessing/samples/CommandLine/component.mk @@ -0,0 +1,2 @@ +COMPONENT_DEPENDS := CommandProcessing +HWCONFIG := spiffs-2m diff --git a/samples/CommandProcessing_Debug/files/index.html b/Sming/Components/CommandProcessing/samples/CommandLine/files/index.html similarity index 100% rename from samples/CommandProcessing_Debug/files/index.html rename to Sming/Components/CommandProcessing/samples/CommandLine/files/index.html diff --git a/samples/CommandProcessing_Debug/web/build/bootstrap.css.gz b/Sming/Components/CommandProcessing/samples/CommandLine/web/build/bootstrap.css.gz similarity index 100% rename from samples/CommandProcessing_Debug/web/build/bootstrap.css.gz rename to Sming/Components/CommandProcessing/samples/CommandLine/web/build/bootstrap.css.gz diff --git a/samples/CommandProcessing_Debug/web/build/index.html b/Sming/Components/CommandProcessing/samples/CommandLine/web/build/index.html similarity index 100% rename from samples/CommandProcessing_Debug/web/build/index.html rename to Sming/Components/CommandProcessing/samples/CommandLine/web/build/index.html diff --git a/samples/CommandProcessing_Debug/web/build/jquery.js.gz b/Sming/Components/CommandProcessing/samples/CommandLine/web/build/jquery.js.gz similarity index 100% rename from samples/CommandProcessing_Debug/web/build/jquery.js.gz rename to Sming/Components/CommandProcessing/samples/CommandLine/web/build/jquery.js.gz diff --git a/samples/CommandProcessing_Debug/web/dev/bootstrap.css b/Sming/Components/CommandProcessing/samples/CommandLine/web/dev/bootstrap.css similarity index 100% rename from samples/CommandProcessing_Debug/web/dev/bootstrap.css rename to Sming/Components/CommandProcessing/samples/CommandLine/web/dev/bootstrap.css diff --git a/samples/CommandProcessing_Debug/web/dev/index.html b/Sming/Components/CommandProcessing/samples/CommandLine/web/dev/index.html similarity index 100% rename from samples/CommandProcessing_Debug/web/dev/index.html rename to Sming/Components/CommandProcessing/samples/CommandLine/web/dev/index.html diff --git a/samples/CommandProcessing_Debug/web/dev/jquery.js b/Sming/Components/CommandProcessing/samples/CommandLine/web/dev/jquery.js similarity index 100% rename from samples/CommandProcessing_Debug/web/dev/jquery.js rename to Sming/Components/CommandProcessing/samples/CommandLine/web/dev/jquery.js diff --git a/samples/Telnet_Server/Makefile b/Sming/Components/CommandProcessing/samples/TelnetServer/Makefile similarity index 100% rename from samples/Telnet_Server/Makefile rename to Sming/Components/CommandProcessing/samples/TelnetServer/Makefile diff --git a/Sming/Components/CommandProcessing/samples/TelnetServer/README.rst b/Sming/Components/CommandProcessing/samples/TelnetServer/README.rst new file mode 100644 index 0000000000..0a80ec3087 --- /dev/null +++ b/Sming/Components/CommandProcessing/samples/TelnetServer/README.rst @@ -0,0 +1,4 @@ +TelnetServer +============ + +A demonstration of a telnet server built using ``CommandProcessing``. diff --git a/Sming/Components/CommandProcessing/samples/TelnetServer/app/application.cpp b/Sming/Components/CommandProcessing/samples/TelnetServer/app/application.cpp new file mode 100644 index 0000000000..4c339ff3b7 --- /dev/null +++ b/Sming/Components/CommandProcessing/samples/TelnetServer/app/application.cpp @@ -0,0 +1,68 @@ +#include +#include + +// If you want, you can define WiFi settings globally in Eclipse Environment Variables +#ifndef WIFI_SSID +#define WIFI_SSID "PleaseEnterSSID" // Put your SSID and password here +#define WIFI_PWD "PleaseEnterPass" +#endif + +namespace +{ +CommandProcessing::Handler commandHandler; + +bool processTelnetInput(TcpClient& client, char* data, int size) +{ + return client.sendString(commandHandler.processNow(data, size)); +} + +void processExampleCommand(String commandLine, ReadWriteStream& commandOutput) +{ + Vector commandToken; + int numToken = splitString(commandLine, ' ', commandToken); + + if(numToken == 1) { + commandOutput.println("example: No parameters provided"); + return; + } + + commandOutput.printf("example: %d parameters provided\r\n", numToken); +} + +void initCommands() +{ + commandHandler.registerSystemCommands(); + commandHandler.registerCommand( + CommandProcessing::Command("example", "Example Command", "Application", processExampleCommand)); +} + +TcpServer telnetServer(processTelnetInput); + +// Will be called when station is fully operational +void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway) +{ + telnetServer.listen(23); + Serial.println(_F("\r\n=== TelnetServer SERVER STARTED ===")); + Serial.println(_F("==============================\r\n")); +} + +} // namespace + +void init() +{ + Serial.begin(SERIAL_BAUD_RATE); // 115200 by default + Serial.systemDebugOutput(true); // Enable debug output to serial + + // Process commands from serial + commandHandler.setVerbose(true); + CommandProcessing::enable(commandHandler, Serial); + + WifiStation.enable(true); + WifiStation.config(WIFI_SSID, WIFI_PWD); + WifiAccessPoint.enable(false); + + WifiEvents.onStationGotIP(gotIP); + + // set command handlers for cam + initCommands(); +} diff --git a/Sming/Components/CommandProcessing/samples/TelnetServer/component.mk b/Sming/Components/CommandProcessing/samples/TelnetServer/component.mk new file mode 100644 index 0000000000..f65c7f99ec --- /dev/null +++ b/Sming/Components/CommandProcessing/samples/TelnetServer/component.mk @@ -0,0 +1 @@ +COMPONENT_DEPENDS := CommandProcessing Network diff --git a/Sming/Components/CommandProcessing/src/.cs b/Sming/Components/CommandProcessing/src/.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Sming/Components/CommandProcessing/src/CommandProcessing/Command.h b/Sming/Components/CommandProcessing/src/CommandProcessing/Command.h new file mode 100644 index 0000000000..9c40fee95f --- /dev/null +++ b/Sming/Components/CommandProcessing/src/CommandProcessing/Command.h @@ -0,0 +1,53 @@ +/* + * CommandDelegate.h + * + * Created on: 2 jul. 2015 + * Author: Herman + */ +/** @addtogroup commandhandler + * @{ + */ + +#pragma once + +#include +#include + +namespace CommandProcessing +{ +/** @brief Command delegate class */ +class Command +{ +public: + /** @brief Command delegate function + * @param commandLine Command line entered by user at CLI, including command and parameters + * @param commandOutput Pointer to the CLI print stream + * @note CommandFunctionDelegate defines the structure of a function that handles individual commands + * @note Can use standard print functions on commandOutput + */ + using Callback = Delegate; + + /** Instantiate a command delegate + * @param reqName Command name - the text a user types to invoke the command + * @param reqHelp Help message shown by CLI "help" command + * @param reqGroup The command group to which this command belongs + * @param reqFunction Delegate that should be invoked (triggered) when the command is entered by a user + */ + Command(String reqName, String reqHelp, String reqGroup, Callback reqFunction) + : name(reqName), description(reqHelp), group(reqGroup), callback(reqFunction) + { + } + + Command() + { + } + + String name; ///< Command name + String description; ///< Command help + String group; ///< Command group + Callback callback; ///< Command Delegate (function that is called when command is invoked) +}; + +} // namespace CommandProcessing + +/** @} */ diff --git a/Sming/Components/CommandProcessing/src/CommandProcessing/Handler.cpp b/Sming/Components/CommandProcessing/src/CommandProcessing/Handler.cpp new file mode 100644 index 0000000000..540d7b3d49 --- /dev/null +++ b/Sming/Components/CommandProcessing/src/CommandProcessing/Handler.cpp @@ -0,0 +1,228 @@ +/* + * CommandHandler.cpp + * + * Created on: 2 jul. 2015 + * Author: Herman + */ + +#include +#include +#include +#include +#include "Handler.h" + +namespace CommandProcessing +{ +Handler::Handler() : currentPrompt(F("Sming>")), currentWelcomeMessage(F("Welcome to the Sming CommandProcessing\r\n")) +{ +} + +size_t Handler::process(char recvChar) +{ + auto& output = getOutputStream(); + + if(recvChar == 27) // ESC -> delete current commandLine + { + commandBuf.clear(); + if(isVerbose()) { + output.println(); + output.print(getCommandPrompt()); + } + } else if(recvChar == getCommandEOL()) { + String command(commandBuf.getBuffer(), commandBuf.getLength()); + commandBuf.clear(); + processCommandLine(command); + } else if(recvChar == '\b' || recvChar == 0x7f) { + if(commandBuf.backspace()) { + output.print(_F("\b \b")); + } + } else { + if(commandBuf.addChar(recvChar) && localEcho) { + output.print(recvChar); + } + } + return 1; +} + +String Handler::processNow(const char* buffer, size_t size) +{ + if(outputStream != nullptr && outputStream->getStreamType() != eSST_MemoryWritable) { + debug_e("Cannot use this method when output stream is set"); + } + + size_t processed = process(buffer, size); + if(processed == size) { + String output; + if(outputStream->moveString(output)) { + return output; + } + } + + return nullptr; +} + +void Handler::processCommandLine(const String& cmdString) +{ + if(cmdString.length() == 0) { + outputStream->println(); + } else { + debug_d("Received full Command line, size = %u,cmd = %s", cmdString.length(), cmdString.c_str()); + String cmdCommand; + int cmdLen = cmdString.indexOf(' '); + if(cmdLen < 0) { + cmdCommand = cmdString; + } else { + cmdCommand = cmdString.substring(0, cmdLen); + } + + debug_d("CommandExecutor : executing command %s", cmdCommand.c_str()); + + Command cmdDelegate = getCommandDelegate(cmdCommand); + + if(!cmdDelegate.callback) { + outputStream->print(_F("Command not found, cmd = '")); + outputStream->print(cmdCommand); + outputStream->println('\''); + } else { + cmdDelegate.callback(cmdString, *outputStream); + } + } + + if(isVerbose()) { + outputStream->print(getCommandPrompt()); + } +} + +void Handler::registerSystemCommands() +{ + String system = F("system"); + registerCommand({F("status"), F("Displays System Information"), system, {&Handler::procesStatusCommand, this}}); + registerCommand({F("echo"), F("Displays command entered"), system, {&Handler::procesEchoCommand, this}}); + registerCommand({F("help"), F("Displays all available commands"), system, {&Handler::procesHelpCommand, this}}); + registerCommand({F("debugon"), F("Set Serial debug on"), system, {&Handler::procesDebugOnCommand, this}}); + registerCommand({F("debugoff"), F("Set Serial debug off"), system, {&Handler::procesDebugOffCommand, this}}); + registerCommand({F("command"), + F("Use verbose/silent/prompt as command options"), + system, + {&Handler::processCommandOptions, this}}); +} + +Command Handler::getCommandDelegate(const String& commandString) +{ + if(registeredCommands.contains(commandString)) { + debug_d("Returning Delegate for %s \r\n", commandString.c_str()); + return registeredCommands[commandString]; + } else { + debug_d("Command %s not recognized, returning NULL\r\n", commandString.c_str()); + return Command("", "", "", nullptr); + } +} + +bool Handler::registerCommand(Command reqDelegate) +{ + if(registeredCommands.contains(reqDelegate.name)) { + // Command already registered, don't allow duplicates + debug_d("Commandhandler duplicate command %s", reqDelegate.name.c_str()); + return false; + } else { + registeredCommands[reqDelegate.name] = reqDelegate; + debug_d("Commandhandlercommand %s registered", reqDelegate.name.c_str()); + return true; + } +} + +bool Handler::unregisterCommand(Command reqDelegate) +{ + if(!registeredCommands.contains(reqDelegate.name)) { + // Command not registered, cannot remove + return false; + } else { + registeredCommands.remove(reqDelegate.name); + // (*registeredCommands)[reqDelegate.commandName] = reqDelegate; + return true; + } +} + +void Handler::procesHelpCommand(String commandLine, ReadWriteStream& outputStream) +{ + debug_d("HelpCommand entered"); + outputStream.println(_F("Commands available are :")); + for(auto cmd : registeredCommands) { + outputStream << cmd->name << " | " << cmd->group << " | " << cmd->description << endl; + } +} + +void Handler::procesStatusCommand(String commandLine, ReadWriteStream& outputStream) +{ + debug_d("StatusCommand entered"); + outputStream << _F("Sming Framework Version : " SMING_VERSION) << endl; + outputStream << _F("ESP SDK version : ") << system_get_sdk_version() << endl; + outputStream << _F("Time = ") << SystemClock.getSystemTimeString() << endl; + outputStream << _F("System Start Reason : ") << system_get_rst_info()->reason << endl; +} + +void Handler::procesEchoCommand(String commandLine, ReadWriteStream& outputStream) +{ + debug_d("HelpCommand entered"); + outputStream << _F("You entered : '") << commandLine << '\'' << endl; +} + +void Handler::procesDebugOnCommand(String commandLine, ReadWriteStream& outputStream) +{ + // Serial.systemDebugOutput(true); + // outputStream.println(_F("Debug set to : On")); +} + +void Handler::procesDebugOffCommand(String commandLine, ReadWriteStream& outputStream) +{ + // Serial.systemDebugOutput(false); + // outputStream.println(_F("Debug set to : Off")); +} + +void Handler::processCommandOptions(String commandLine, ReadWriteStream& outputStream) +{ + Vector commandToken; + int numToken = splitString(commandLine, ' ', commandToken); + bool errorCommand = false; + bool printUsage = false; + + switch(numToken) { + case 2: + if(commandToken[1] == _F("help")) { + printUsage = true; + } + if(commandToken[1] == _F("verbose")) { + setVerbose(true); + outputStream.println(_F("Verbose mode selected")); + break; + } + if(commandToken[1] == _F("silent")) { + setVerbose(false); + outputStream.println(_F("Silent mode selected")); + break; + } + errorCommand = true; + break; + case 3: + if(commandToken[1] != _F("prompt")) { + errorCommand = true; + break; + } + setCommandPrompt(commandToken[2]); + outputStream << _F("Prompt set to : ") << commandToken[2] << endl; + break; + default: + errorCommand = true; + } + if(errorCommand) { + outputStream << _F("Unknown command : ") << commandLine << endl; + } + if(printUsage) { + outputStream << _F("command usage :") << endl + << _F("command verbose : Set verbose mode") << endl + << _F("command silent : Set silent mode") << endl + << _F("command prompt 'new prompt' : Set prompt to use") << endl; + } +} + +} // namespace CommandProcessing diff --git a/Sming/Services/CommandProcessing/CommandHandler.h b/Sming/Components/CommandProcessing/src/CommandProcessing/Handler.h similarity index 53% rename from Sming/Services/CommandProcessing/CommandHandler.h rename to Sming/Components/CommandProcessing/src/CommandProcessing/Handler.h index 8c6d2d4919..25a7f6569e 100644 --- a/Sming/Services/CommandProcessing/CommandHandler.h +++ b/Sming/Components/CommandProcessing/src/CommandProcessing/Handler.h @@ -6,45 +6,98 @@ */ /** @defgroup commandhandler Command Handler * @brief Provide command line interface - - Command handler provides a common command line interface. CLI is available for the following remote access methods: - - Serial - - Telnet - - Websockets - - By default, CLI is disabled. Enable CLI by calling "commandProcessing" on the appropriate access class object, e.g. - - Serial.commandProcessing(true) - Commands can be added to and removed from the command handler. Each command will trigger a defined Delegate. - A welcome message may be shown when a user connects and end of line character may be defined. An automatic "help" display is available. * @{ */ #pragma once -#include "CommandDelegate.h" #include -#include -#include +#include +#include +#include +#include +#include "Command.h" + +namespace CommandProcessing +{ +constexpr size_t MAX_COMMANDSIZE = 64; /** @brief Verbose mode */ -enum VerboseMode { - VERBOSE, ///< Verbose mode - SILENT ///< Silent mode -}; /** @brief Command handler class */ -class CommandHandler +class Handler { public: - /** @brief Instantiate a CommandHandler - */ - CommandHandler(); + /** + * @brief Instantiate a CommandHandler + */ + Handler(); - CommandHandler(const CommandHandler&) = delete; + Handler(ReadWriteStream* stream, bool owned = true) : outputStream(stream), ownedStream(owned) + { + } + + Handler(const Handler& rhs) = delete; + + ~Handler() + { + if(ownedStream) { + delete outputStream; + } + } + + // I/O methods + + /** + * @brief sets the output stream + * @param stream pointer to the output stream + * @param owned specifies if the output stream should be deleted in this class(owned=true) + */ + void setOutputStream(ReadWriteStream* stream, bool owned = true) + { + if(outputStream != nullptr && ownedStream) { + delete outputStream; + } + + outputStream = stream; + ownedStream = owned; + } + + ReadWriteStream& getOutputStream() + { + if(outputStream == nullptr) { + outputStream = new MemoryDataStream(); + ownedStream = true; + } + + return *outputStream; + } + + size_t process(char charToWrite); + + /** @brief Write chars to stream + * @param buffer Pointer to buffer to write to the stream + * @param size Quantity of chars to write + * @retval size_t Quantity of chars processed + */ + size_t process(const char* buffer, size_t size) + { + size_t retval = 0; + for(size_t i = 0; i < size; i++) { + if(process(buffer[i]) != 1) { + break; + } + retval++; + } + return retval; + } + + String processNow(const char* buffer, size_t size); + + // Command registration/de-registration methods /** @brief Add a new command to the command handler * @param reqDelegate Command delegate to register @@ -52,12 +105,12 @@ class CommandHandler * @note If command already exists, it will not be replaced and function will fail. Call unregisterCommand first if you want to replace a command. */ - bool registerCommand(CommandDelegate reqDelegate); + bool registerCommand(Command reqDelegate); /** @brief Remove a command from the command handler * @brief reqDelegate Delegate to remove from command handler */ - bool unregisterCommand(CommandDelegate reqDelegate); + bool unregisterCommand(Command reqDelegate); /** @brief Register default system commands * @note Adds the following system commands to the command handler @@ -74,12 +127,12 @@ class CommandHandler * @param commandString Command to query * @retval CommandDelegate The command delegate matching the command */ - CommandDelegate getCommandDelegate(const String& commandString); + Command getCommandDelegate(const String& commandString); /** @brief Get the verbose mode * @retval VerboseMode Verbose mode */ - VerboseMode getVerboseMode() + bool isVerbose() const { return verboseMode; } @@ -87,9 +140,9 @@ class CommandHandler /** @brief Set the verbose mode * @param reqVerboseMode Verbose mode to set */ - void setVerboseMode(VerboseMode reqVerboseMode) + void setVerbose(bool mode) { - verboseMode = reqVerboseMode; + verboseMode = mode; } /** @brief Get the command line prompt @@ -97,7 +150,7 @@ class CommandHandler * @note This is what is shown on the command line before user input * Default is Sming> */ - String getCommandPrompt() + const String& getCommandPrompt() const { return currentPrompt; } @@ -116,7 +169,7 @@ class CommandHandler * @retval char The EOL character * @note Only supports one EOL, unlike Windows */ - char getCommandEOL() + char getCommandEOL() const { return currentEOL; } @@ -134,7 +187,7 @@ class CommandHandler * @retval String The welcome message that is shown when clients connect * @note Only if verbose mode is enabled */ - String getCommandWelcomeMessage() + const String& getCommandWelcomeMessage() const { return currentWelcomeMessage; } @@ -148,28 +201,32 @@ class CommandHandler currentWelcomeMessage = reqWelcomeMessage; } - // int deleteGroup(String reqGroup); - private: - HashMap registeredCommands; - void procesHelpCommand(String commandLine, CommandOutput* commandOutput); - void procesStatusCommand(String commandLine, CommandOutput* commandOutput); - void procesEchoCommand(String commandLine, CommandOutput* commandOutput); - void procesDebugOnCommand(String commandLine, CommandOutput* commandOutput); - void procesDebugOffCommand(String commandLine, CommandOutput* commandOutput); - void processCommandOptions(String commandLine, CommandOutput* commandOutput); - - VerboseMode verboseMode = VERBOSE; + HashMap registeredCommands; String currentPrompt; #ifdef ARCH_HOST - char currentEOL = '\n'; + char currentEOL{'\n'}; #else - char currentEOL = '\r'; + char currentEOL{'\r'}; #endif + bool verboseMode{false}; + bool localEcho{true}; String currentWelcomeMessage; + + ReadWriteStream* outputStream{nullptr}; + bool ownedStream = true; + LineBuffer commandBuf; + + void procesHelpCommand(String commandLine, ReadWriteStream& outputStream); + void procesStatusCommand(String commandLine, ReadWriteStream& outputStream); + void procesEchoCommand(String commandLine, ReadWriteStream& outputStream); + void procesDebugOnCommand(String commandLine, ReadWriteStream& outputStream); + void procesDebugOffCommand(String commandLine, ReadWriteStream& outputStream); + void processCommandOptions(String commandLine, ReadWriteStream& outputStream); + + void processCommandLine(const String& cmdString); }; -/** @brief Global instance of CommandHandler */ -extern CommandHandler commandHandler; +} // namespace CommandProcessing /** @} */ diff --git a/Sming/Components/CommandProcessing/src/CommandProcessing/Utils.cpp b/Sming/Components/CommandProcessing/src/CommandProcessing/Utils.cpp new file mode 100644 index 0000000000..d044b19a52 --- /dev/null +++ b/Sming/Components/CommandProcessing/src/CommandProcessing/Utils.cpp @@ -0,0 +1,15 @@ +#include "Utils.h" + +namespace CommandProcessing +{ +void enable(Handler& commandHandler, HardwareSerial& serial) +{ + commandHandler.setOutputStream(&serial, false); + Serial.onDataReceived([&commandHandler](Stream& source, char arrivedChar, uint16_t availableCharsCount) { + while(availableCharsCount--) { + commandHandler.process(source.read()); + } + }); +} + +} // namespace CommandProcessing diff --git a/Sming/Components/CommandProcessing/src/CommandProcessing/Utils.h b/Sming/Components/CommandProcessing/src/CommandProcessing/Utils.h new file mode 100644 index 0000000000..7ffd2cbac4 --- /dev/null +++ b/Sming/Components/CommandProcessing/src/CommandProcessing/Utils.h @@ -0,0 +1,10 @@ +#pragma once + +#include "Handler.h" +#include + +namespace CommandProcessing +{ +void enable(Handler& commandHandler, HardwareSerial& serial); + +} // namespace CommandProcessing diff --git a/Sming/Components/Network/src/Network/FtpServer.h b/Sming/Components/Network/src/Network/FtpServer.h index e096311f2c..7d0e9492a0 100644 --- a/Sming/Components/Network/src/Network/FtpServer.h +++ b/Sming/Components/Network/src/Network/FtpServer.h @@ -42,7 +42,7 @@ class CustomFtpServer : public TcpServer TcpConnection* createClient(tcp_pcb* clientTcp) override; /** - * @brief Handle an incomding command + * @brief Handle an incoming command * @param cmd The command identifier, e.g. LIST * @param data Any command arguments * @param connection The associated TCP connection to receive any response diff --git a/Sming/Components/Network/src/Network/Http/Websocket/WebsocketResource.cpp b/Sming/Components/Network/src/Network/Http/Websocket/WebsocketResource.cpp index 24288d2997..4d2586dccd 100644 --- a/Sming/Components/Network/src/Network/Http/Websocket/WebsocketResource.cpp +++ b/Sming/Components/Network/src/Network/Http/Websocket/WebsocketResource.cpp @@ -35,8 +35,6 @@ int WebsocketResource::checkHeaders(HttpServerConnection& connection, HttpReques connection.userData = (void*)socket; connection.setUpgradeCallback(HttpServerProtocolUpgradeCallback(&WebsocketConnection::onConnected, socket)); - // TODO: Re-Enable Command Executor... - return 0; } diff --git a/Sming/Components/Network/src/Network/Http/Websocket/WsCommandHandlerResource.h b/Sming/Components/Network/src/Network/Http/Websocket/WsCommandHandlerResource.h deleted file mode 100644 index d14a666935..0000000000 --- a/Sming/Components/Network/src/Network/Http/Websocket/WsCommandHandlerResource.h +++ /dev/null @@ -1,51 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * WsCommandHandlerResource.h - * - * @author: 2017 - Slavey Karadzhov - * - ****/ - -#pragma once - -#include "../HttpResource.h" -#include "WebsocketConnection.h" -#include "WString.h" -#include "Services/CommandProcessing/CommandProcessingIncludes.h" // TODO: .... - -class WsCommandHandlerResource : protected WebsocketResource -{ -public: - WsCommandHandlerResource() : WebsocketResource() - { - wsMessage = WebsocketMessageDelegate(&WsCommandHandlerResource::onMessage, this); - } - -protected: - int checkHeaders(HttpServerConnection& connection, HttpRequest& request, HttpResponse& response) override - { - int err = WebsocketResource::checkHeaders(connection, request, response); - if(err != 0) { - return err; - } - - WebsocketConnection* socket = (WebsocketConnection*)connection.userData; - if(socket != nullptr) { - socket->setMessageHandler(); - - // create new command handler - } - } - - void onMessage(WebsocketConnection& connection, const String& message) - { - commandExecutor.executorReceive(message + "\r"); - } - -private: - CommandExecutor commandExecutor; -}; diff --git a/Sming/Components/Network/src/Network/TcpClient.h b/Sming/Components/Network/src/Network/TcpClient.h index 74b93fa14c..4d1d3becf9 100644 --- a/Sming/Components/Network/src/Network/TcpClient.h +++ b/Sming/Components/Network/src/Network/TcpClient.h @@ -19,7 +19,6 @@ #include "TcpConnection.h" class TcpClient; -class ReadWriteStream; class IpAddress; using TcpClientEventDelegate = Delegate; diff --git a/Sming/Components/Network/src/Network/TelnetServer.cpp b/Sming/Components/Network/src/Network/TelnetServer.cpp deleted file mode 100644 index 345a50ed41..0000000000 --- a/Sming/Components/Network/src/Network/TelnetServer.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * TelnetServer.cpp - * - * Created on: 18 apr. 2015 - * Author: Herman - * - ****/ - -#include "TelnetServer.h" -#include "Debug.h" - -void TelnetServer::enableDebug(bool reqStatus) -{ - telnetDebug = reqStatus; - if(telnetDebug && curClient != nullptr) /* only setSetDebug when already connected */ - { - Debug.setDebug(DebugPrintCharDelegate(&TelnetServer::wrchar, this)); - } else { - Debug.setDebug(Serial); - } -} - -void TelnetServer::enableCommand(bool reqStatus) -{ -#if ENABLE_CMD_EXECUTOR - if(reqStatus && curClient != nullptr && commandExecutor == nullptr) { - commandExecutor = new CommandExecutor(curClient); - } - if(!reqStatus && commandExecutor != nullptr) { - delete commandExecutor; - commandExecutor = nullptr; - } -#endif - telnetCommand = reqStatus; -} - -void TelnetServer::onClient(TcpClient* client) -{ - debug_d("TelnetServer onClient %s", client->getRemoteIp().toString().c_str()); - - TcpServer::onClient(client); - - if(curClient != nullptr) { - debug_d("TCP Client already connected"); - client->sendString("Telnet Client already connected\r\n"); - client->close(); - } else { - curClient = client; - curClient->setTimeOut(USHRT_MAX); - curClient->sendString("Welcome to Sming / ESP6266 Telnet\r\n"); - if(telnetCommand) { -#if ENABLE_CMD_EXECUTOR - commandExecutor = new CommandExecutor(client); -#endif - } - if(telnetDebug) { - Debug.setDebug(DebugPrintCharDelegate(&TelnetServer::wrchar, this)); - } - Debug.printf("This is debug after telnet start\r\n"); - } -} - -void TelnetServer::onClientComplete(TcpClient& client, bool successful) -{ - if(&client == curClient) { -#if ENABLE_CMD_EXECUTOR - delete commandExecutor; - commandExecutor = nullptr; -#endif - curClient = nullptr; - debug_d("TelnetServer onClientComplete %s", client.getRemoteIp().toString().c_str()); - } else { - debug_d("Telnet server unconnected client close"); - } - - debug_d("TelnetServer onClientComplete %s", client.getRemoteIp().toString().c_str()); - TcpServer::onClientComplete(client, successful); - Debug.setDebug(Serial); -} - -void TelnetServer::wrchar(char c) -{ - char ca[2]; - ca[0] = c; - curClient->write(ca, 1); -} - -bool TelnetServer::onClientReceive(TcpClient& client, char* data, int size) -{ - debug_d("TelnetServer onClientReceive : %s, %d bytes \r\n", client.getRemoteIp().toString().c_str(), size); - debug_d("Data : %s", data); -#if ENABLE_CMD_EXECUTOR - if(commandExecutor != nullptr) { - commandExecutor->executorReceive(data, size); - } -#endif - return true; -} diff --git a/Sming/Components/Network/src/Network/TelnetServer.h b/Sming/Components/Network/src/Network/TelnetServer.h deleted file mode 100644 index 04942e3bac..0000000000 --- a/Sming/Components/Network/src/Network/TelnetServer.h +++ /dev/null @@ -1,53 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * TelnetServer.h - * - * Created on: 18 apr. 2015 - * Author: Herman - * - ****/ - -/** @defgroup telnetserver Telnet server - * @brief Provides Telnet server - * @ingroup tcpserver - * @{ - */ - -#pragma once - -#include "TcpClient.h" -#include "TcpServer.h" -#include "SystemClock.h" -#include "Services/CommandProcessing/CommandExecutor.h" - -#ifndef TELNETSERVER_MAX_COMMANDSIZE -#define TELNETSERVER_MAX_COMMANDSIZE 64 -#endif - -using TelnetServerCommandDelegate = Delegate; - -class TelnetServer : public TcpServer -{ -public: - void enableDebug(bool reqStatus); - void enableCommand(bool reqStatus); - -private: - void onClient(TcpClient* client) override; - bool onClientReceive(TcpClient& client, char* data, int size) override; - void onClientComplete(TcpClient& client, bool successful) override; - - void wrchar(char c); - -private: - TcpClient* curClient = nullptr; - CommandExecutor* commandExecutor = nullptr; - bool telnetDebug = true; - bool telnetCommand = true; -}; - -/** @} */ diff --git a/Sming/Core/Debug.cpp b/Sming/Core/Debug.cpp deleted file mode 100644 index b95d9c1ea8..0000000000 --- a/Sming/Core/Debug.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * Debug.cpp - * - ****/ - -#include "Debug.h" -#include - -DebugClass::DebugClass() -{ - debugf("DebugClass Instantiating"); - setDebug(Serial); -} - -void DebugClass::initCommand() -{ -#if ENABLE_CMD_EXECUTOR - commandHandler.registerCommand(CommandDelegate(F("debug"), F("New debug in development"), F("Debug"), - CommandFunctionDelegate(&DebugClass::processDebugCommands, this))); -#endif -} - -void DebugClass::start() -{ - started = true; - println(_F("Debug started")); -} - -void DebugClass::stop() -{ - println(_F("Debug stopped")); - started = false; -} - -void DebugClass::setDebug(DebugPrintCharDelegate reqDelegate) -{ - debugOut.debugStream = nullptr; - debugOut.debugDelegate = reqDelegate; - print(_F("Welcome to DebugDelegate\r\n")); -} - -void DebugClass::setDebug(Stream& reqStream) -{ - debugOut.debugDelegate = nullptr; - debugOut.debugStream = &reqStream; - print(_F("Welcome to DebugStream")); -} - -void DebugClass::printPrefix() -{ - if(useDebugPrefix) { - uint32_t curMillis = millis(); - printf(_F("Dbg %4u.%03u : "), curMillis / 1000, curMillis % 1000); - } -} - -size_t DebugClass::write(uint8_t c) -{ - if(started) { - if(newDebugLine) { - newDebugLine = false; - printPrefix(); - } - if(c == '\n') { - newDebugLine = true; - } - if(debugOut.debugDelegate) { - debugOut.debugDelegate(c); - return 1; - } - if(debugOut.debugStream) { - debugOut.debugStream->write(c); - return 1; - } - } - - return 0; -} - -void DebugClass::processDebugCommands(String commandLine, CommandOutput* commandOutput) -{ - Vector commandToken; - int numToken = splitString(commandLine, ' ', commandToken); - - if(numToken == 1) { - commandOutput->print(_F("Debug Commands available : \r\n")); - commandOutput->print(_F("on : Start Debug output\r\n")); - commandOutput->print(_F("off : Stop Debug output\r\n")); - commandOutput->print(_F("serial : Send Debug output to Serial\r\n")); - } else { - if(commandToken[1] == "on") { - start(); - commandOutput->print(_F("Debug started\r\n")); - } else if(commandToken[1] == _F("off")) { - commandOutput->print(_F("Debug stopped\r\n")); - stop(); - } else if(commandToken[1] == _F("serial")) { - setDebug(Serial); - commandOutput->print(_F("Debug set to Serial")); - }; - } -} - -DebugClass Debug; diff --git a/Sming/Core/Debug.h b/Sming/Core/Debug.h deleted file mode 100644 index 831056e3e6..0000000000 --- a/Sming/Core/Debug.h +++ /dev/null @@ -1,112 +0,0 @@ -/**** - * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development. - * Created 2015 by Skurydin Alexey - * http://github.com/SmingHub/Sming - * All files of the Sming Core are provided under the LGPL v3 license. - * - * Debug.h - * - ****/ - -#pragma once - -#include "HardwareSerial.h" -#include "Clock.h" -#include "WString.h" -#include "Services/CommandProcessing/CommandProcessingIncludes.h" - -/** @brief Delegate constructor usage: (&YourClass::method, this) - * Handler function for debug print - * @ingroup event_handlers - */ -using DebugPrintCharDelegate = Delegate; - -/** @brief Structure for debug options - * @ingroup structures - */ -struct DebugOuputOptions { - DebugPrintCharDelegate debugDelegate; ///< Function to handle debug output - Stream* debugStream{nullptr}; ///< Debug output stream -}; - -/** @brief Debug prefix state - * @ingroup constants - */ -enum eDBGPrefix { - eDBGnoPrefix = 0, ///< Do not use debug prefix - eDBGusePrefix = 1 ///< Use debug prefix -}; - -/** @defgroup debug Debug functions - * @brief Provides debug functions - * @{ -*/ - -/** @brief Provides debug output to stream (e.g. Serial) or delegate function handler. - * - * Debug output may be prefixed with an elapsed timestamp. Use standard print methods to produce debug output. - * Sming CLI (command handler) may be enabled to provide control of debug output to end user. - */ -class DebugClass : public Print -{ -public: - /** @brief Instantiate a debug object - * @note Default output is Serial stream - */ - DebugClass(); - - /** @brief Enable control of debug output from CLI command handler output - */ - void initCommand(); - - /** @brief Start debug output - */ - void start(); - - /** @brief Stop debug output - */ - void stop(); - - /** @brief Get debug status - * @retval bool True if debug enabled - */ - bool status() - { - return started; - } - - /** @brief Configure debug to use delegate handler for its output - * @param reqDelegate Function to handle debug output - * @note Disables stream output - */ - void setDebug(DebugPrintCharDelegate reqDelegate); - - /** @brief Configures debug to use stream for its output - * @param reqStream Stream for debug output - * @note Disables delegate handler - */ - void setDebug(Stream& reqStream); - - /* implementation of write for Print Class */ - size_t write(uint8_t) override; - -private: - bool started = false; - bool useDebugPrefix = true; - bool newDebugLine = true; - DebugOuputOptions debugOut; - void printPrefix(); - void processDebugCommands(String commandLine, CommandOutput* commandOutput); -}; - -/** @brief Global instance of Debug object - * @note Use Debug.function to access Debug functions - * @note Example: - * @code - * Debug.start(); - * Debug.printf("My value is %d", myVal); - @endcode -*/ -extern DebugClass Debug; - -/** @} */ diff --git a/Sming/Core/HardwareSerial.cpp b/Sming/Core/HardwareSerial.cpp index b305cfbe0c..c83a51c570 100644 --- a/Sming/Core/HardwareSerial.cpp +++ b/Sming/Core/HardwareSerial.cpp @@ -15,19 +15,8 @@ #include "Platform/System.h" #include "m_printf.h" -#if ENABLE_CMD_EXECUTOR -#include -#endif - HardwareSerial Serial(UART_ID_0); -HardwareSerial::~HardwareSerial() -{ -#if ENABLE_CMD_EXECUTOR - delete commandExecutor; -#endif -} - bool HardwareSerial::begin(uint32_t baud, SerialFormat format, SerialMode mode, uint8_t txPin, uint8_t rxPin) { end(); @@ -123,14 +112,6 @@ void HardwareSerial::invokeCallbacks() if(HWSDelegate) { HWSDelegate(*this, receivedChar, smg_uart_rx_available(uart)); } -#if ENABLE_CMD_EXECUTOR - if(commandExecutor) { - int c; - while((c = smg_uart_read_char(uart)) >= 0) { - commandExecutor->executorReceive(c); - } - } -#endif } } @@ -190,11 +171,7 @@ void HardwareSerial::staticCallbackHandler(smg_uart_t* uart, uint32_t status) bool HardwareSerial::updateUartCallback() { uint16_t mask = 0; -#if ENABLE_CMD_EXECUTOR - if(HWSDelegate || commandExecutor) { -#else if(HWSDelegate) { -#endif mask |= UART_STATUS_RXFIFO_FULL | UART_STATUS_RXFIFO_TOUT | UART_STATUS_RXFIFO_OVF; } @@ -208,18 +185,3 @@ bool HardwareSerial::updateUartCallback() return mask != 0; } - -void HardwareSerial::commandProcessing(bool reqEnable) -{ -#if ENABLE_CMD_EXECUTOR - if(reqEnable) { - if(!commandExecutor) { - commandExecutor = new CommandExecutor(this); - } - } else { - delete commandExecutor; - commandExecutor = nullptr; - } - updateUartCallback(); -#endif -} diff --git a/Sming/Core/HardwareSerial.h b/Sming/Core/HardwareSerial.h index 055e9e6708..4416c338b2 100644 --- a/Sming/Core/HardwareSerial.h +++ b/Sming/Core/HardwareSerial.h @@ -50,8 +50,6 @@ using StreamDataReceivedDelegate = Delegate; -class CommandExecutor; - // clang-format off #define SERIAL_CONFIG_MAP(XX) \ XX(5N1) XX(6N1) XX(7N1) XX(8N1) XX(5N2) XX(6N2) XX(7N2) XX(8N2) XX(5E1) XX(6E1) XX(7E1) XX(8E1) \ @@ -116,8 +114,6 @@ class HardwareSerial : public ReadWriteStream { } - ~HardwareSerial(); - void setPort(int uartPort) { end(); @@ -340,8 +336,12 @@ class HardwareSerial : public ReadWriteStream * @param reqEnable True to enable command processing * @note Command processing provides a CLI to the system * @see commandHandler + * + * @deprecated include and use `CommandProcessing::enable(Handler, Serial)` instead. */ - void commandProcessing(bool reqEnable); + void commandProcessing(bool reqEnable) SMING_DEPRECATED + { + } /** @brief Set handler for received data * @param dataReceivedDelegate Function to handle received data @@ -449,7 +449,6 @@ class HardwareSerial : public ReadWriteStream int uartNr = UART_NO; TransmitCompleteDelegate transmitComplete = nullptr; ///< Callback for transmit completion StreamDataReceivedDelegate HWSDelegate = nullptr; ///< Callback for received data - CommandExecutor* commandExecutor = nullptr; ///< Callback for command execution (received data) smg_uart_t* uart = nullptr; uart_options_t options = _BV(UART_OPT_TXWAIT); size_t txSize = DEFAULT_TX_BUFFER_SIZE; diff --git a/Sming/Kconfig b/Sming/Kconfig index 9a4bfd12cd..993af06be2 100644 --- a/Sming/Kconfig +++ b/Sming/Kconfig @@ -43,12 +43,6 @@ mainmenu "${SMING_SOC} Sming Framework Configuration" This will recompile your application to use the revised baud rate. Note that this will change the default speed used for both flashing and serial comms. - config ENABLE_CMD_EXECUTOR - bool "Enable command executor functionality" - default y - help - This facility requires documenting! - config TASK_QUEUE_LENGTH int "Length of task queue" default 10 diff --git a/Sming/Libraries/CS5460/samples/generic/app/application.cpp b/Sming/Libraries/CS5460/samples/generic/app/application.cpp index 3defc39983..ea0bec20a1 100644 --- a/Sming/Libraries/CS5460/samples/generic/app/application.cpp +++ b/Sming/Libraries/CS5460/samples/generic/app/application.cpp @@ -1,5 +1,4 @@ #include -#include #include CS5460 powerMeter(PIN_NDEFINED, PIN_NDEFINED, PIN_NDEFINED, PIN_NDEFINED); @@ -16,7 +15,6 @@ void init() Serial.begin(SERIAL_BAUD_RATE, SERIAL_8N1, SERIAL_FULL); // 115200 by default, GPIO1,GPIO3, see Serial.swap(), HardwareSerial Serial.systemDebugOutput(true); - Debug.setDebug(Serial); powerMeter.init(); powerMeter.setCurrentGain(190.84); //0.25 / shunt (0.00131) diff --git a/Sming/Libraries/ModbusMaster/samples/generic/app/application.cpp b/Sming/Libraries/ModbusMaster/samples/generic/app/application.cpp index 3d8d826030..ddefd7a32b 100644 --- a/Sming/Libraries/ModbusMaster/samples/generic/app/application.cpp +++ b/Sming/Libraries/ModbusMaster/samples/generic/app/application.cpp @@ -1,5 +1,4 @@ #include -#include #include #define MODBUS_COM_SPEED 115200 @@ -105,11 +104,6 @@ void init() SERIAL_TX_ONLY); // 115200 by default, GPIO1,GPIO3, see Serial.swap(), HardwareSerial debugComPort.systemDebugOutput(true); - Debug.setDebug(debugComPort); - Debug.initCommand(); - Debug.start(); - Debug.printf("This is the debug output\r\n"); - mbMaster.preTransmission(preTransmission); mbMaster.postTransmission(postTransmission); mbMaster.logReceive(mbLogReceive); diff --git a/Sming/Libraries/USB b/Sming/Libraries/USB index 9055f1b444..ae08687c90 160000 --- a/Sming/Libraries/USB +++ b/Sming/Libraries/USB @@ -1 +1 @@ -Subproject commit 9055f1b4443d3bd5fbdd08147c74a6f0528a6a8a +Subproject commit ae08687c900582a94db86d4cff1c492317e52307 diff --git a/Sming/Libraries/modbusino/samples/generic/app/application.cpp b/Sming/Libraries/modbusino/samples/generic/app/application.cpp index 6405541879..0a0d3e9f41 100644 --- a/Sming/Libraries/modbusino/samples/generic/app/application.cpp +++ b/Sming/Libraries/modbusino/samples/generic/app/application.cpp @@ -1,5 +1,4 @@ #include -#include #include #define ARRLEN 3 @@ -17,8 +16,6 @@ void init() { debugComPort.begin(SERIAL_BAUD_RATE, SERIAL_8N1, SERIAL_TX_ONLY); debugComPort.systemDebugOutput(true); - Debug.setDebug(debugComPort); - Debug.start(); mbSlave.setup(SERIAL_BAUD_RATE); mbSlave.setRxCallback(mbPrint); } diff --git a/Sming/Services/CommandProcessing/CommandDelegate.h b/Sming/Services/CommandProcessing/CommandDelegate.h deleted file mode 100644 index c43e2d0751..0000000000 --- a/Sming/Services/CommandProcessing/CommandDelegate.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * CommandDelegate.h - * - * Created on: 2 jul. 2015 - * Author: Herman - */ -/** @addtogroup commandhandler - * @{ - */ - -#pragma once - -#include -#include -#include "CommandOutput.h" - -/** @brief Command delegate function - * @param commandLine Command line entered by user at CLI, including command and parameters - * @param commandOutput Pointer to the CLI print stream - * @note CommandFunctionDelegate defines the structure of a function that handles individual commands - * @note Can use standard print functions on commandOutput - */ -using CommandFunctionDelegate = Delegate; - -/** @brief Command delegate class */ -class CommandDelegate -{ -public: - /** Instantiate a command delegate - * @param reqName Command name - the text a user types to invoke the command - * @param reqHelp Help message shown by CLI "help" command - * @param reqGroup The command group to which this command belongs - * @param reqFunction Delegate that should be invoked (triggered) when the command is entered by a user - */ - CommandDelegate(String reqName, String reqHelp, String reqGroup, CommandFunctionDelegate reqFunction) - : commandName(reqName), commandHelp(reqHelp), commandGroup(reqGroup), commandFunction(reqFunction) - { - } - - CommandDelegate() - { - } - - String commandName; ///< Command name - String commandHelp; ///< Command help - String commandGroup; ///< Command group - CommandFunctionDelegate commandFunction; ///< Command Delegate (function that is called when command is invoked) -}; - -/** @} */ diff --git a/Sming/Services/CommandProcessing/CommandExecutor.cpp b/Sming/Services/CommandProcessing/CommandExecutor.cpp deleted file mode 100644 index 4cb49e78ce..0000000000 --- a/Sming/Services/CommandProcessing/CommandExecutor.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * CommandExecutor.cpp - * - * Created on: 2 jul. 2015 - * Author: Herman - */ - -#include "CommandExecutor.h" -#include "HardwareSerial.h" -#include - -CommandExecutor::CommandExecutor() -{ - commandHandler.registerSystemCommands(); -} - -CommandExecutor::CommandExecutor(Stream* reqStream) : CommandExecutor() -{ - commandOutput.reset(new CommandOutput(reqStream)); - if(commandHandler.getVerboseMode() != SILENT) { - commandOutput->println(_F("Welcome to the Stream Command executor")); - } -} - -#ifndef DISABLE_NETWORK -CommandExecutor::CommandExecutor(TcpClient* cmdClient) : CommandExecutor() -{ - commandOutput.reset(new CommandOutput(cmdClient)); - if(commandHandler.getVerboseMode() != SILENT) { - commandOutput->println(_F("Welcome to the Tcp Command executor")); - } -} - -CommandExecutor::CommandExecutor(WebsocketConnection* reqSocket) -{ - commandOutput.reset(new CommandOutput(reqSocket)); - if(commandHandler.getVerboseMode() != SILENT) { - reqSocket->sendString(_F("Welcome to the Websocket Command Executor")); - } -} -#endif - -int CommandExecutor::executorReceive(char* recvData, int recvSize) -{ - int receiveReturn = 0; - for(int recvIdx = 0; recvIdx < recvSize; recvIdx++) { - receiveReturn = executorReceive(recvData[recvIdx]); - if(receiveReturn != 0) { - break; - } - } - return receiveReturn; -} - -int CommandExecutor::executorReceive(const String& recvString) -{ - int receiveReturn = 0; - for(unsigned recvIdx = 0; recvIdx < recvString.length(); recvIdx++) { - receiveReturn = executorReceive(recvString[recvIdx]); - if(receiveReturn != 0) { - break; - } - } - return receiveReturn; -} - -int CommandExecutor::executorReceive(char recvChar) -{ - if(recvChar == 27) // ESC -> delete current commandLine - { - commandBuf.clear(); - if(commandHandler.getVerboseMode() == VERBOSE) { - commandOutput->println(); - commandOutput->print(commandHandler.getCommandPrompt()); - } - } else if(recvChar == commandHandler.getCommandEOL()) { - String command(commandBuf.getBuffer(), commandBuf.getLength()); - commandBuf.clear(); - processCommandLine(command); - } else if(recvChar == '\b' || recvChar == 0x7f) { - if(commandBuf.backspace()) { - commandOutput->print(_F("\b \b")); - } - } else { - if(commandBuf.addChar(recvChar)) { - commandOutput->print(recvChar); - } - } - return 0; -} - -void CommandExecutor::processCommandLine(const String& cmdString) -{ - if(cmdString.length() == 0) { - commandOutput->println(); - } else { - debugf("Received full Command line, size = %u,cmd = %s", cmdString.length(), cmdString.c_str()); - String cmdCommand; - int cmdLen = cmdString.indexOf(' '); - if(cmdLen < 0) { - cmdCommand = cmdString; - } else { - cmdCommand = cmdString.substring(0, cmdLen); - } - - debugf("CommandExecutor : executing command %s", cmdCommand.c_str()); - - CommandDelegate cmdDelegate = commandHandler.getCommandDelegate(cmdCommand); - - if(!cmdDelegate.commandFunction) { - commandOutput->print(_F("Command not found, cmd = '")); - commandOutput->print(cmdCommand); - commandOutput->println('\''); - } else { - cmdDelegate.commandFunction(cmdString, commandOutput.get()); - } - } - - if(commandHandler.getVerboseMode() == VERBOSE) { - commandOutput->print(commandHandler.getCommandPrompt()); - } -} diff --git a/Sming/Services/CommandProcessing/CommandExecutor.h b/Sming/Services/CommandProcessing/CommandExecutor.h deleted file mode 100644 index a04ac0e6c4..0000000000 --- a/Sming/Services/CommandProcessing/CommandExecutor.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * CommandExecutor.h - * - * Created on: 2 jul. 2015 - * Author: Herman - */ - -#pragma once - -#include "CommandHandler.h" -#include "CommandOutput.h" -#include -#include - -#ifndef DISABLE_NETWORK -#include -#endif - -#define MAX_COMMANDSIZE 64 - -class CommandExecutor -{ -public: - CommandExecutor(const CommandExecutor&) = delete; - CommandExecutor& operator=(const CommandExecutor&) = delete; - -#ifndef DISABLE_NETWORK - CommandExecutor(TcpClient* cmdClient); - CommandExecutor(WebsocketConnection* reqSocket); -#endif - CommandExecutor(Stream* reqStream); - - int executorReceive(char* recvData, int recvSize); - int executorReceive(char recvChar); - int executorReceive(const String& recvString); - void setCommandEOL(char reqEOL); - -private: - CommandExecutor(); - void processCommandLine(const String& cmdString); - LineBuffer commandBuf; - std::unique_ptr commandOutput; -}; diff --git a/Sming/Services/CommandProcessing/CommandHandler.cpp b/Sming/Services/CommandProcessing/CommandHandler.cpp deleted file mode 100644 index c1ba3406ea..0000000000 --- a/Sming/Services/CommandProcessing/CommandHandler.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* - * CommandHandler.cpp - * - * Created on: 2 jul. 2015 - * Author: Herman - */ - -#include "CommandHandler.h" -#include "CommandDelegate.h" -#include -#include -#include - -#ifndef DISABLE_NETWORK -#include -#endif - -#ifndef LWIP_HASH_STR -#define LWIP_HASH_STR "" -#endif - -CommandHandler::CommandHandler() - : currentPrompt(F("Sming>")), currentWelcomeMessage(F("Welcome to the Sming CommandProcessing\r\n")) -{ -} - -void CommandHandler::registerSystemCommands() -{ - String system = F("system"); - registerCommand(CommandDelegate(F("status"), F("Displays System Information"), system, - CommandFunctionDelegate(&CommandHandler::procesStatusCommand, this))); - registerCommand(CommandDelegate(F("echo"), F("Displays command entered"), system, - CommandFunctionDelegate(&CommandHandler::procesEchoCommand, this))); - registerCommand(CommandDelegate(F("help"), F("Displays all available commands"), system, - CommandFunctionDelegate(&CommandHandler::procesHelpCommand, this))); - registerCommand(CommandDelegate(F("debugon"), F("Set Serial debug on"), system, - CommandFunctionDelegate(&CommandHandler::procesDebugOnCommand, this))); - registerCommand(CommandDelegate(F("debugoff"), F("Set Serial debug off"), system, - CommandFunctionDelegate(&CommandHandler::procesDebugOffCommand, this))); - registerCommand(CommandDelegate(F("command"), F("Use verbose/silent/prompt as command options"), system, - CommandFunctionDelegate(&CommandHandler::processCommandOptions, this))); -} - -CommandDelegate CommandHandler::getCommandDelegate(const String& commandString) -{ - if(registeredCommands.contains(commandString)) { - debugf("Returning Delegate for %s \r\n", commandString.c_str()); - return registeredCommands[commandString]; - } else { - debugf("Command %s not recognized, returning NULL\r\n", commandString.c_str()); - return CommandDelegate("", "", "", nullptr); - } -} - -bool CommandHandler::registerCommand(CommandDelegate reqDelegate) -{ - if(registeredCommands.contains(reqDelegate.commandName)) { - // Command already registered, don't allow duplicates - debugf("Commandhandler duplicate command %s", reqDelegate.commandName.c_str()); - return false; - } else { - registeredCommands[reqDelegate.commandName] = reqDelegate; - debugf("Commandhandlercommand %s registered", reqDelegate.commandName.c_str()); - return true; - } -} - -bool CommandHandler::unregisterCommand(CommandDelegate reqDelegate) -{ - if(!registeredCommands.contains(reqDelegate.commandName)) { - // Command not registered, cannot remove - return false; - } else { - registeredCommands.remove(reqDelegate.commandName); - // (*registeredCommands)[reqDelegate.commandName] = reqDelegate; - return true; - } -} - -void CommandHandler::procesHelpCommand(String commandLine, CommandOutput* commandOutput) -{ - debugf("HelpCommand entered"); - commandOutput->println(_F("Commands available are :")); - for(unsigned idx = 0; idx < registeredCommands.count(); idx++) { - commandOutput->print(registeredCommands.valueAt(idx).commandName); - commandOutput->print(" | "); - commandOutput->print(registeredCommands.valueAt(idx).commandGroup); - commandOutput->print(" | "); - commandOutput->print(registeredCommands.valueAt(idx).commandHelp); - commandOutput->print("\r\n"); - } -} - -void CommandHandler::procesStatusCommand(String commandLine, CommandOutput* commandOutput) -{ - debugf("StatusCommand entered"); - commandOutput->println(_F("System information : ESP8266 Sming Framework")); - commandOutput->println(_F("Sming Framework Version : " SMING_VERSION)); - commandOutput->print(_F("ESP SDK version : ")); - commandOutput->print(system_get_sdk_version()); - commandOutput->println(); -#ifndef DISABLE_NETWORK - commandOutput->printf(_F("lwIP version : %d.%d.%d(%s)\r\n"), LWIP_VERSION_MAJOR, LWIP_VERSION_MINOR, - LWIP_VERSION_REVISION, LWIP_HASH_STR); -#endif - commandOutput->print(_F("Time = ")); - commandOutput->print(SystemClock.getSystemTimeString()); - commandOutput->println(); - commandOutput->printf(_F("System Start Reason : %d\r\n"), system_get_rst_info()->reason); -} - -void CommandHandler::procesEchoCommand(String commandLine, CommandOutput* commandOutput) -{ - debugf("HelpCommand entered"); - commandOutput->print(_F("You entered : '")); - commandOutput->print(commandLine); - commandOutput->println('\''); -} - -void CommandHandler::procesDebugOnCommand(String commandLine, CommandOutput* commandOutput) -{ - Serial.systemDebugOutput(true); - commandOutput->println(_F("Debug set to : On")); -} - -void CommandHandler::procesDebugOffCommand(String commandLine, CommandOutput* commandOutput) -{ - Serial.systemDebugOutput(false); - commandOutput->println(_F("Debug set to : Off")); -} - -void CommandHandler::processCommandOptions(String commandLine, CommandOutput* commandOutput) -{ - Vector commandToken; - int numToken = splitString(commandLine, ' ', commandToken); - bool errorCommand = false; - bool printUsage = false; - - switch(numToken) { - case 2: - if(commandToken[1] == _F("help")) { - printUsage = true; - } - if(commandToken[1] == _F("verbose")) { - commandHandler.setVerboseMode(VERBOSE); - commandOutput->println(_F("Verbose mode selected")); - break; - } - if(commandToken[1] == _F("silent")) { - commandHandler.setVerboseMode(SILENT); - commandOutput->println(_F("Silent mode selected")); - break; - } - errorCommand = true; - break; - case 3: - if(commandToken[1] != _F("prompt")) { - errorCommand = true; - break; - } - commandHandler.setCommandPrompt(commandToken[2]); - commandOutput->print(_F("Prompt set to : ")); - commandOutput->print(commandToken[2]); - commandOutput->println(); - break; - default: - errorCommand = true; - } - if(errorCommand) { - commandOutput->print(_F("Unknown command : ")); - commandOutput->print(commandLine); - commandOutput->println(); - } - if(printUsage) { - commandOutput->println(_F("command usage : \r\n")); - commandOutput->println(_F("command verbose : Set verbose mode")); - commandOutput->println(_F("command silent : Set silent mode")); - commandOutput->println(_F("command prompt 'new prompt' : Set prompt to use")); - } -} - -CommandHandler commandHandler; diff --git a/Sming/Services/CommandProcessing/CommandOutput.cpp b/Sming/Services/CommandProcessing/CommandOutput.cpp deleted file mode 100644 index a8bf385103..0000000000 --- a/Sming/Services/CommandProcessing/CommandOutput.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * CommandOutput.cpp - * - * Created on: 5 jul. 2015 - * Author: Herman - */ - -#include "CommandOutput.h" -#include - -CommandOutput::CommandOutput(Stream* reqStream) : outputStream(reqStream) -{ -} - -CommandOutput::~CommandOutput() -{ - debugf("destruct"); -} - -size_t CommandOutput::write(uint8_t outChar) -{ - if(outputStream) { - return outputStream->write(outChar); - } - -#ifndef DISABLE_NETWORK - if(outputTcpClient) { - char outBuf[1] = {char(outChar)}; - return outputTcpClient->write(outBuf, 1); - } - if(outputSocket) { - if(outChar == '\r') { - outputSocket->sendString(tempSocket); - tempSocket = ""; - } else { - tempSocket += char(outChar); - } - - return 1; - } -#endif - - return 0; -} diff --git a/Sming/Services/CommandProcessing/CommandOutput.h b/Sming/Services/CommandProcessing/CommandOutput.h deleted file mode 100644 index 9ae25228e0..0000000000 --- a/Sming/Services/CommandProcessing/CommandOutput.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * CommandOutput.h - * - * Created on: 5 jul. 2015 - * Author: Herman - */ - -#pragma once - -#include -#include - -#ifndef DISABLE_NETWORK -#include -#include -#endif - -class CommandOutput : public Print -{ -public: -#ifndef DISABLE_NETWORK - CommandOutput(TcpClient* reqClient) : outputTcpClient(reqClient) - { - } - - CommandOutput(WebsocketConnection* reqSocket) : outputSocket(reqSocket) - { - } - -#endif - - CommandOutput(Stream* reqStream); - ~CommandOutput(); - - size_t write(uint8_t outChar); - -#ifndef DISABLE_NETWORK - TcpClient* outputTcpClient = nullptr; - WebsocketConnection* outputSocket = nullptr; -#endif - Stream* outputStream = nullptr; - String tempSocket = ""; -}; diff --git a/Sming/Services/CommandProcessing/CommandProcessingDependencies.h b/Sming/Services/CommandProcessing/CommandProcessingDependencies.h deleted file mode 100644 index 00a48271bb..0000000000 --- a/Sming/Services/CommandProcessing/CommandProcessingDependencies.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * CommandProcessingDependencies.h - * - * Created on: 2 jul. 2015 - * Author: Herman - */ - -#pragma once diff --git a/Sming/Services/CommandProcessing/CommandProcessingIncludes.h b/Sming/Services/CommandProcessing/CommandProcessingIncludes.h deleted file mode 100644 index 6061ee7ec9..0000000000 --- a/Sming/Services/CommandProcessing/CommandProcessingIncludes.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * CommandProcessingIncludes.h - * - * Created on: 2 jul. 2015 - * Author: Herman - */ - -#pragma once - -#include "CommandOutput.h" -#include "CommandProcessingDependencies.h" -#include "CommandDelegate.h" -#include "CommandExecutor.h" -#include "CommandHandler.h" diff --git a/Sming/component.mk b/Sming/component.mk index c0e95cf705..e6d132a69e 100644 --- a/Sming/component.mk +++ b/Sming/component.mk @@ -31,14 +31,6 @@ COMPONENT_DOXYGEN_INPUT := \ Wiring \ System -# => Disable CommandExecutor functionality if not used and save some ROM and RAM -COMPONENT_VARS += ENABLE_CMD_EXECUTOR -ENABLE_CMD_EXECUTOR ?= 1 -ifeq ($(ENABLE_CMD_EXECUTOR),1) -COMPONENT_SRCDIRS += Services/CommandProcessing -endif -GLOBAL_CFLAGS += -DENABLE_CMD_EXECUTOR=$(ENABLE_CMD_EXECUTOR) - # RELINK_VARS += DISABLE_NETWORK DISABLE_NETWORK ?= 0 diff --git a/docs/source/framework/services/command-processing/index.rst b/docs/source/framework/services/command-processing/index.rst deleted file mode 100644 index 42eb48fcb8..0000000000 --- a/docs/source/framework/services/command-processing/index.rst +++ /dev/null @@ -1,42 +0,0 @@ -Command Executor -================ - -.. highlight:: c++ - -Introduction ------------- - -Command handler provides a common command line interface. CLI is available for the following remote access methods: - -- Serial -- Telnet -- Websockets - -By default, CLI is disabled. Enable CLI by calling "commandProcessing" on the appropriate access class object, e.g:: - - Serial.commandProcessing(true) - -Commands can be added to and removed from the command handler. Each command will trigger a defined Delegate. - -A welcome message may be shown when a user connects and end of line character may be defined. An automatic "help" display is available. - -Build Variables ---------------- - -.. envvar:: ENABLE_CMD_EXECUTOR - - Default: 1 (ON) - - This feature enables execution of certain commands by registering token handlers for text - received via serial, websocket or telnet connection. If this feature - is not used additional RAM/Flash can be obtained by setting - ``ENABLE_CMD_EXECUTOR=0``. This will save ~1KB RAM and ~3KB of flash - memory. - - -API Documentation ------------------ - -.. doxygengroup:: commandhandler - :content-only: - :members: diff --git a/docs/source/framework/services/index.rst b/docs/source/framework/services/index.rst index 03fd153d9a..5a1a05d18f 100644 --- a/docs/source/framework/services/index.rst +++ b/docs/source/framework/services/index.rst @@ -4,5 +4,4 @@ Services .. toctree:: :maxdepth: 1 - command-processing/index profiling/index diff --git a/docs/source/upgrading/4.7-5.1.rst b/docs/source/upgrading/4.7-5.1.rst new file mode 100644 index 0000000000..a1c8aa0c87 --- /dev/null +++ b/docs/source/upgrading/4.7-5.1.rst @@ -0,0 +1,63 @@ +From v4.7 to v5.1 +================= + +.. highlight:: c++ + +Command Processing +------------------ + +The CommandProcessing service has been refactored and moved to a component. +This means that the following classes ``CommandHandler``, ``CommandExecutor`` and ``CommandOutput`` are no longer available. + + +Enabling +~~~~~~~~ + +The command processing component used to be enabled by setting the directive ``ENABLE_CMD_EXECUTOR`` to 1 in your ``component.mk`` file or during compilation. +This has to be replaced with the directive ``COMPONENT_DEPENDS += CommandProcessing`` in your ``component.mk`` file. + + +Including Header Files +~~~~~~~~~~~~~~~~~~~~~~~ + +To include the command processing headers in your C/C++ application we used to do the following + +For example:: + + #include + +becomes:: + + #include + + +Usage +~~~~~ + +There is no longer a global instance of commandHandler. This means that you will need to create one yourself when you need it. +This can be done using the code below:: + + CommandProcessing::CommandHandler commandHandler; + +In order to register a command the old example code:: + + commandHandler.registerCommand( + CommandDelegate("example", "Example Command", "Application", processExampleCommand)); + +becomes:: + + commandHandler.registerCommand( + CommandProcessing::Command("example", "Example Command", "Application", processExampleCommand)); + +HardwareSerial no longer is dependent on CommandProcessing classes. And the following command will no longer work:: + + Serial.commandProcessing(true); + +The line above has to be replaced with:: + + CommandProcessing::enable(commandProcessing, Serial); + +See the modified samples +:sample:`CommandLine`, +:sample:`TelnetServer` +and :sample:`HttpServer_WebSockets` for details. diff --git a/docs/source/upgrading/index.rst b/docs/source/upgrading/index.rst index a53c6a896f..9677ddf287 100644 --- a/docs/source/upgrading/index.rst +++ b/docs/source/upgrading/index.rst @@ -7,6 +7,7 @@ For newer versions we have dedicated pages. .. toctree:: :maxdepth: 1 + 4.7-5.1 4.6-4.7 4.5-4.6 4.4-4.5 diff --git a/samples/Arducam/app/ArduCamCommand.cpp b/samples/Arducam/app/ArduCamCommand.cpp deleted file mode 100644 index 961fb0a2e7..0000000000 --- a/samples/Arducam/app/ArduCamCommand.cpp +++ /dev/null @@ -1,248 +0,0 @@ - -#include -#include -#include - -ArduCamCommand::ArduCamCommand(ArduCAM* CAM) -{ - debugf("ArduCamCommand Instantiating"); - myCAM = CAM; - imgSize = OV2640_320x240; - imgType = JPEG; -} - -ArduCamCommand::~ArduCamCommand() -{ -} - -void ArduCamCommand::initCommand() -{ - commandHandler.registerCommand(CommandDelegate("set", "ArduCAM config commands", "Application", - CommandFunctionDelegate(&ArduCamCommand::processSetCommands, this))); - // commandHandler.registerCommand( - // CommandDelegate("out", "ArduCAM output commands", "Application", - // CommandFunctionDelegate(&ArduCamCommand::processOutCommands,this))); -} - -void ArduCamCommand::showSettings(CommandOutput* commandOutput) -{ - // review settings - commandOutput->printf("ArduCam Settings:\n"); - commandOutput->printf(" img Type: [%s]\n", getImageType()); - commandOutput->printf(" img Size: [%s]\n", getImageSize()); -}; - -void ArduCamCommand::processSetCommands(String commandLine, CommandOutput* commandOutput) -{ - Vector commandToken; - int numToken = splitString(commandLine, ' ', commandToken); - - if(numToken == 1) { - // review settings - showSettings(commandOutput); - } - // handle command -> set - else if(commandToken[1] == "help") { - *commandOutput << _F("set img [bmp|jpeg]") << endl; - *commandOutput << _F("set size [160|176|320|352|640|800|1024|1280|1600]") << endl; - } - - // handle command -> set - else if(commandToken[1] == "img") { - if(numToken == 3) { - if(commandToken[2] == "bmp") { - // TODO: set image size and init cam - // settings->setImageType(BMP); - set_format(BMP); - } else if(commandToken[2] == "jpg") { - set_format(JPEG); - } else { - *commandOutput << _F("invalid image format [") << commandToken[2] << ']' << endl; - } - } else { - *commandOutput << _F("Syntax: set img [bmp|jpeg]") << endl; - } - showSettings(commandOutput); - } - - // handle command -> settings - else if(commandToken[1] == "size") { - if(numToken == 3) { - if(commandToken[2] == "160") { - imgSize = OV2640_160x120; - myCAM->OV2640_set_JPEG_size(OV2640_160x120); - set_format(JPEG); - } else if(commandToken[2] == "176") { - imgSize = OV2640_176x144; - myCAM->OV2640_set_JPEG_size(OV2640_176x144); - set_format(JPEG); - } else if(commandToken[2] == "320") { - imgSize = OV2640_320x240; - myCAM->OV2640_set_JPEG_size(OV2640_320x240); - } else if(commandToken[2] == "352") { - imgSize = OV2640_352x288; - myCAM->OV2640_set_JPEG_size(OV2640_352x288); - set_format(JPEG); - } else if(commandToken[2] == "640") { - imgSize = OV2640_640x480; - myCAM->OV2640_set_JPEG_size(OV2640_640x480); - set_format(JPEG); - } else if(commandToken[2] == "800") { - imgSize = OV2640_800x600; - myCAM->OV2640_set_JPEG_size(OV2640_800x600); - set_format(JPEG); - } else if(commandToken[2] == "1024") { - imgSize = OV2640_1024x768; - myCAM->OV2640_set_JPEG_size(OV2640_1024x768); - set_format(JPEG); - } else if(commandToken[2] == "1280") { - imgSize = OV2640_1280x1024; - myCAM->OV2640_set_JPEG_size(OV2640_1280x1024); - set_format(JPEG); - } else if(commandToken[2] == "1600") { - imgSize = OV2640_1600x1200; - myCAM->OV2640_set_JPEG_size(OV2640_1600x1200); - set_format(JPEG); - } else { - *commandOutput << _F("invalid size definition[") << commandToken[2] << ']' << endl; - } - } else { - *commandOutput << _F("Syntax: set size [160|176|320|352|640|800|1024|1280|1600]") << endl; - } - showSettings(commandOutput); - } -} - -void ArduCamCommand::set_size(String size) -{ - if(size == "160x120") { - imgSize = OV2640_160x120; - myCAM->OV2640_set_JPEG_size(OV2640_160x120); - set_format(JPEG); - } else if(size == "176x144") { - imgSize = OV2640_176x144; - myCAM->OV2640_set_JPEG_size(OV2640_176x144); - set_format(JPEG); - } else if(size == "320x240") { - imgSize = OV2640_320x240; - myCAM->OV2640_set_JPEG_size(OV2640_320x240); - } else if(size == "352x288") { - imgSize = OV2640_352x288; - myCAM->OV2640_set_JPEG_size(OV2640_352x288); - set_format(JPEG); - } else if(size == "640x480") { - imgSize = OV2640_640x480; - myCAM->OV2640_set_JPEG_size(OV2640_640x480); - set_format(JPEG); - } else if(size == "800x600") { - imgSize = OV2640_800x600; - myCAM->OV2640_set_JPEG_size(OV2640_800x600); - set_format(JPEG); - } else if(size == "1024x768") { - imgSize = OV2640_1024x768; - myCAM->OV2640_set_JPEG_size(OV2640_1024x768); - set_format(JPEG); - } else if(size == "1280x1024") { - imgSize = OV2640_1280x1024; - myCAM->OV2640_set_JPEG_size(OV2640_1280x1024); - set_format(JPEG); - } else if(size == "1600x1200") { - imgSize = OV2640_1600x1200; - myCAM->OV2640_set_JPEG_size(OV2640_1600x1200); - set_format(JPEG); - } else { - debugf("ERROR: invalid size definition[%s]\r\n", size.c_str()); - } -} - -void ArduCamCommand::set_type(String type) -{ - if(type == "BMP") { - myCAM->set_format(BMP); - if(imgType != BMP) { - // reset the cam - myCAM->InitCAM(); - imgType = BMP; - imgSize = OV2640_320x240; - } - } else { - myCAM->set_format(JPEG); - // reset the cam - if(imgType != JPEG) { - // reset the cam - myCAM->InitCAM(); - myCAM->OV2640_set_JPEG_size(imgSize); - imgType = JPEG; - } - } -} - -void ArduCamCommand::set_format(uint8 type) -{ - if(type == BMP) { - myCAM->set_format(BMP); - if(imgType != BMP) { - // reset the cam - myCAM->InitCAM(); - imgType = BMP; - imgSize = OV2640_320x240; - } - } else { - myCAM->set_format(JPEG); - // reset the cam - if(imgType != JPEG) { - // reset the cam - myCAM->InitCAM(); - myCAM->OV2640_set_JPEG_size(imgSize); - imgType = JPEG; - } - } -} - -const char* ArduCamCommand::getImageType() -{ - switch(imgType) { - case JPEG: - return "JPEG"; - case BMP: - default: - return "BMP"; - } -} - -const char* ArduCamCommand::getContentType() -{ - switch(imgType) { - case JPEG: - return "image/jpeg"; - case BMP: - default: - return "image/x-ms-bmp"; - } -} - -const char* ArduCamCommand::getImageSize() -{ - switch(imgSize) { - case OV2640_1600x1200: - return "1600x1200"; - case OV2640_1280x1024: - return "1280x1024"; - case OV2640_1024x768: - return "1024x768"; - case OV2640_800x600: - return "800x600"; - case OV2640_640x480: - return "640x480"; - case OV2640_352x288: - return "352x288"; - case OV2640_320x240: - return "320x240"; - case OV2640_176x144: - return "176x144"; - case OV2640_160x120: - return "160x120"; - default: - return "320x240"; - } -} diff --git a/samples/Arducam/component.mk b/samples/Arducam/component.mk deleted file mode 100644 index 76533c24f2..0000000000 --- a/samples/Arducam/component.mk +++ /dev/null @@ -1,3 +0,0 @@ -ARDUINO_LIBRARIES := ArduCAM -HWCONFIG = spiffs-2m -SPIFF_FILES = web/build diff --git a/samples/Arducam/include/ArduCamCommand.h b/samples/Arducam/include/ArduCamCommand.h deleted file mode 100644 index 80493ea1fc..0000000000 --- a/samples/Arducam/include/ArduCamCommand.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ArduCamCommand.h - * - */ - -#ifndef ARDUCAM_COMMAND_H_ -#define ARDUCAM_COMMAND_H_ - -#include "WString.h" -#include -#include -#include - -class ArduCamCommand -{ -public: - ArduCamCommand(ArduCAM* CAM); - virtual ~ArduCamCommand(); - void initCommand(); - const char* getContentType(); - void set_size(String size); - void set_type(String type); - -private: - bool status = true; - ArduCAM* myCAM; - uint8 imgType; - uint8 imgSize; - void processSetCommands(String commandLine, CommandOutput* commandOutput); - - void set_format(uint8 type); - void showSettings(CommandOutput* commandOutput); - - const char* getImageType(); - const char* getImageSize(); -}; - -#endif /* SMINGCORE_DEBUG_H_ */ diff --git a/samples/CommandProcessing_Debug/README.rst b/samples/CommandProcessing_Debug/README.rst deleted file mode 100644 index 6686ed6a04..0000000000 --- a/samples/CommandProcessing_Debug/README.rst +++ /dev/null @@ -1,4 +0,0 @@ -CommandProcessing Debug -======================= - -Demonstrates Sming's command handling capability via HTTP, FTP and Telnet interfaces. diff --git a/samples/CommandProcessing_Debug/app/ExampleCommand.cpp b/samples/CommandProcessing_Debug/app/ExampleCommand.cpp deleted file mode 100644 index 9bc37bbb82..0000000000 --- a/samples/CommandProcessing_Debug/app/ExampleCommand.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Debug.cpp - * - */ - -#include - -ExampleCommand::ExampleCommand() -{ - debugf("ExampleCommand Instantiating"); -} - -ExampleCommand::~ExampleCommand() -{ -} - -void ExampleCommand::initCommand() -{ - commandHandler.registerCommand( - CommandDelegate("example", "Example Command from Class", "Application", - CommandFunctionDelegate(&ExampleCommand::processExampleCommands, this))); -} - -void ExampleCommand::processExampleCommands(String commandLine, CommandOutput* commandOutput) -{ - Vector commandToken; - int numToken = splitString(commandLine, ' ', commandToken); - - if(numToken == 1) { - commandOutput->printf("Example Commands available : \r\n"); - commandOutput->printf("on : Set example status ON\r\n"); - commandOutput->printf("off : Set example status OFF\r\n"); - commandOutput->printf("status : Show example status\r\n"); - } else { - if(commandToken[1] == "on") { - status = true; - commandOutput->printf("Status ON\r\n"); - } else if(commandToken[1] == "off") { - status = false; - commandOutput->printf("Status OFF\r\n"); - } else if(commandToken[1] == "status") { - String tempString = status ? "ON" : "OFF"; - commandOutput->printf("Example Status is %s\r\n", tempString.c_str()); - }; - } -} diff --git a/samples/CommandProcessing_Debug/app/application.cpp b/samples/CommandProcessing_Debug/app/application.cpp deleted file mode 100644 index e9b3ad4e32..0000000000 --- a/samples/CommandProcessing_Debug/app/application.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include -#include -#include -#include -#include - -// If you want, you can define WiFi settings globally in Eclipse Environment Variables -#ifndef WIFI_SSID -#define WIFI_SSID "PleaseEnterSSID" // Put your SSID and password here -#define WIFI_PWD "PleaseEnterPass" -#endif - -HttpServer server; -FtpServer ftp; -TelnetServer telnet; - -Timer msgTimer; - -ExampleCommand exampleCommand; - -void onIndex(HttpRequest& request, HttpResponse& response) -{ - TemplateFileStream* tmpl = new TemplateFileStream("index.html"); - auto& vars = tmpl->variables(); - //vars["counter"] = String(counter); - response.sendNamedStream(tmpl); // this template object will be deleted automatically -} - -void onFile(HttpRequest& request, HttpResponse& response) -{ - String file = request.uri.getRelativePath(); - - if(file[0] == '.') - response.code = HTTP_STATUS_FORBIDDEN; - else { - response.setCache(86400, true); // It's important to use cache for better performance. - response.sendFile(file); - } -} - -int msgCount = 0; - -void wsConnected(WebsocketConnection& socket) -{ - Serial.println(_F("Socket connected")); -} - -void wsMessageReceived(WebsocketConnection& socket, const String& message) -{ - Serial.println(_F("WebsocketConnection message received:")); - Serial.println(message); - String response = "Echo: " + message; - socket.sendString(response); -} - -void wsBinaryReceived(WebsocketConnection& socket, uint8_t* data, size_t size) -{ - Serial << _F("Websocket binary data received, size: ") << size << endl; -} - -void wsDisconnected(WebsocketConnection& socket) -{ - Serial.println(_F("Socket disconnected")); -} - -void processApplicationCommands(String commandLine, CommandOutput* commandOutput) -{ - commandOutput->println(_F("This command is handle by the application")); -} - -void StartServers() -{ - server.listen(80); - server.paths.set("/", onIndex); - server.paths.setDefault(onFile); - - // Web Sockets configuration - WebsocketResource* wsResource = new WebsocketResource(); - wsResource->setConnectionHandler(wsConnected); - wsResource->setMessageHandler(wsMessageReceived); - wsResource->setBinaryHandler(wsBinaryReceived); - wsResource->setDisconnectionHandler(wsDisconnected); - - server.paths.set("/ws", wsResource); - - Serial.println(_F("\r\n=== WEB SERVER STARTED ===")); - Serial.println(WifiStation.getIP()); - Serial.println(_F("==============================\r\n")); - - // Start FTP server - ftp.listen(21); - ftp.addUser("me", "123"); // FTP account - - Serial.println(_F("\r\n=== FTP SERVER STARTED ===")); - Serial.println(_F("==============================\r\n")); - - telnet.listen(23); - telnet.enableDebug(true); - - Serial.println(_F("\r\n=== TelnetServer SERVER STARTED ===")); - Serial.println(_F("==============================\r\n")); -} - -void startExampleApplicationCommand() -{ - exampleCommand.initCommand(); - commandHandler.registerCommand( - CommandDelegate(F("example"), F("Example Command from Class"), F("Application"), processApplicationCommands)); -} - -void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway) -{ - StartServers(); - - startExampleApplicationCommand(); -} - -void init() -{ - spiffs_mount(); // Mount file system, in order to work with files - - Serial.begin(SERIAL_BAUD_RATE); // 115200 by default - - commandHandler.registerSystemCommands(); - Debug.setDebug(Serial); - - Serial.systemDebugOutput(true); // Enable debug output to serial - Serial.commandProcessing(true); - - WifiStation.enable(true); - WifiStation.config(WIFI_SSID, WIFI_PWD); - WifiAccessPoint.enable(false); - - // Run our method when station was connected to AP - WifiEvents.onStationGotIP(gotIP); -} diff --git a/samples/CommandProcessing_Debug/component.mk b/samples/CommandProcessing_Debug/component.mk deleted file mode 100644 index 372d718852..0000000000 --- a/samples/CommandProcessing_Debug/component.mk +++ /dev/null @@ -1 +0,0 @@ -HWCONFIG := spiffs-2m diff --git a/samples/CommandProcessing_Debug/include/ExampleCommand.h b/samples/CommandProcessing_Debug/include/ExampleCommand.h deleted file mode 100644 index f16501af40..0000000000 --- a/samples/CommandProcessing_Debug/include/ExampleCommand.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ExampleCommand.h - * - */ - -#pragma once - -#include "WString.h" -#include - -class ExampleCommand -{ -public: - ExampleCommand(); - virtual ~ExampleCommand(); - void initCommand(); - -private: - bool status = true; - void processExampleCommands(String commandLine, CommandOutput* commandOutput); -}; diff --git a/samples/HttpServer_WebSockets/Kconfig b/samples/HttpServer_WebSockets/Kconfig new file mode 100644 index 0000000000..8744832f6b --- /dev/null +++ b/samples/HttpServer_WebSockets/Kconfig @@ -0,0 +1,11 @@ +# +# For a description of the syntax of this configuration file, +# see kconfig/kconfig-language.txt. +# +mainmenu "Sample Configuration" + + menu "Command Hanler" + config ENABLE_CMD_HANDLER + bool "Enable command handler functionality" + default y + endmenu \ No newline at end of file diff --git a/samples/HttpServer_WebSockets/app/application.cpp b/samples/HttpServer_WebSockets/app/application.cpp index 77062a5bfd..193966e636 100644 --- a/samples/HttpServer_WebSockets/app/application.cpp +++ b/samples/HttpServer_WebSockets/app/application.cpp @@ -2,6 +2,11 @@ #include #include "CUserData.h" +#if ENABLE_CMD_HANDLER +#include +CommandProcessing::Handler commandHandler; +#endif + // If you want, you can define WiFi settings globally in Eclipse Environment Variables #ifndef WIFI_SSID #define WIFI_SSID "PleaseEnterSSID" // Put your SSID and password here @@ -76,6 +81,33 @@ void wsMessageReceived(WebsocketConnection& socket, const String& message) } } +#if ENABLE_CMD_HANDLER +void wsCommandReceived(WebsocketConnection& socket, const String& message) +{ + String response = commandHandler.processNow(message.c_str(), message.length()); + socket.sendString(response); + + //Normally you would use dynamic cast but just be careful not to convert to wrong object type! + auto user = reinterpret_cast(socket.getUserData()); + if(user != nullptr) { + user->printMessage(socket, message); + } +} + +void processShutdownCommand(String commandLine, ReadWriteStream& commandOutput) +{ + // Don't shutdown immediately, wait a bit to allow messages to propagate + auto timer = new SimpleTimer; + timer->initializeMs<1000>( + [](void* timer) { + delete static_cast(timer); + server.shutdown(); + }, + timer); + timer->startOnce(); +} +#endif + void wsBinaryReceived(WebsocketConnection& socket, uint8_t* data, size_t size) { Serial << _F("Websocket binary data received, size: ") << size << endl; @@ -106,6 +138,10 @@ void startWebServer() auto wsResource = new WebsocketResource(); wsResource->setConnectionHandler(wsConnected); wsResource->setMessageHandler(wsMessageReceived); +#if ENABLE_CMD_HANDLER + wsResource->setMessageHandler(wsCommandReceived); +#endif + wsResource->setBinaryHandler(wsBinaryReceived); wsResource->setDisconnectionHandler(wsDisconnected); @@ -127,6 +163,12 @@ void init() { spiffs_mount(); // Mount file system, in order to work with files +#if ENABLE_CMD_HANDLER + commandHandler.registerSystemCommands(); + commandHandler.registerCommand( + CommandProcessing::Command("shutdown", "Shutdown Server Command", "Application", processShutdownCommand)); +#endif + Serial.begin(SERIAL_BAUD_RATE); // 115200 by default Serial.systemDebugOutput(true); // Enable debug output to serial diff --git a/samples/HttpServer_WebSockets/component.mk b/samples/HttpServer_WebSockets/component.mk index 372d718852..25bbd74f26 100644 --- a/samples/HttpServer_WebSockets/component.mk +++ b/samples/HttpServer_WebSockets/component.mk @@ -1 +1,10 @@ HWCONFIG := spiffs-2m + +COMPONENT_VARS += ENABLE_CMD_HANDLER +ENABLE_CMD_HANDLER ?= 1 + +ifeq ($(ENABLE_CMD_HANDLER), 1) + COMPONENT_DEPENDS += CommandProcessing +endif + +APP_CFLAGS += -DENABLE_CMD_HANDLER=$(ENABLE_CMD_HANDLER) \ No newline at end of file diff --git a/samples/Telnet_Server/README.rst b/samples/Telnet_Server/README.rst deleted file mode 100644 index 10803fd21c..0000000000 --- a/samples/Telnet_Server/README.rst +++ /dev/null @@ -1,4 +0,0 @@ -Telnet Server -============= - -Demonstrates a simple Telnet server application. diff --git a/samples/Telnet_Server/app/application.cpp b/samples/Telnet_Server/app/application.cpp deleted file mode 100644 index dfa10d920c..0000000000 --- a/samples/Telnet_Server/app/application.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include -#include -#include "Services/CommandProcessing/CommandProcessingIncludes.h" -#include - -// If you want, you can define WiFi settings globally in Eclipse Environment Variables -#ifndef WIFI_SSID -#define WIFI_SSID "PleaseEnterSSID" // Put you SSID and Password here -#define WIFI_PWD "PleaseEnterPass" -#endif - -Timer memoryTimer; -int savedHeap = 0; - -void checkHeap() -{ - int currentHeap = system_get_free_heap_size(); - if(currentHeap != savedHeap) { - Debug << _F("Heap change, current = ") << currentHeap << endl; - savedHeap = currentHeap; - } -} - -void applicationCommand(String commandLine, CommandOutput* commandOutput) -{ - *commandOutput << _F("Hello from Telnet Example application") << endl - << _F("You entered : '") << commandLine << '\'' << endl - << _F("Tokenized commandLine is : ") << endl; - - Vector commandToken; - unsigned numToken = splitString(commandLine, ' ', commandToken); - for(unsigned i = 0; i < numToken; i++) { - *commandOutput << i << " : " << commandToken[i] << endl; - } -} - -void appheapCommand(String commandLine, CommandOutput* commandOutput) -{ - Vector commandToken; - int numToken = splitString(commandLine, ' ', commandToken); - if(numToken != 2) { - commandOutput->println(_F("Usage appheap on/off/now")); - } else if(commandToken[1] == "on") { - commandOutput->println(_F("Timer heap display started")); - savedHeap = 0; - memoryTimer.initializeMs(250, checkHeap).start(); - } else if(commandToken[1] == "off") { - commandOutput->println(_F("Timer heap display stopped")); - savedHeap = 0; - memoryTimer.stop(); - } else if(commandToken[1] == "now") { - *commandOutput << _F("Heap current free = ") << system_get_free_heap_size() << endl; - } else { - commandOutput->println(_F("Usage appheap on/off/now")); - } -} - -void tcpServerClientConnected(TcpClient* client) -{ - debugf("Application onClientCallback : %s\r\n", client->getRemoteIp().toString().c_str()); -} - -bool tcpServerClientReceive(TcpClient& client, char* data, int size) -{ - debugf("Application DataCallback : %s, %d bytes \r\n", client.getRemoteIp().toString().c_str(), size); - debugf("Data : %s", data); - client.sendString(F("sendString data\r\n"), false); - client.writeString(F("writeString data\r\n"), 0); - if(strcmp(data, "close") == 0) { - debugf("Closing client"); - client.close(); - }; - return true; -} - -void tcpServerClientComplete(TcpClient& client, bool successful) -{ - debugf("Application CompleteCallback : %s \r\n", client.getRemoteIp().toString().c_str()); -} - -TcpServer tcpServer(tcpServerClientConnected, tcpServerClientReceive, tcpServerClientComplete); -TelnetServer telnetServer; - -void startServers() -{ - tcpServer.listen(8023); - - Serial.println(_F("\r\n" - "=== TCP SERVER Port 8023 STARTED ===")); - Serial.println(WifiStation.getIP()); - Serial.println(_F("====================================\r\n")); - - telnetServer.listen(23); - - Serial.println(_F("\r\n" - "=== Telnet SERVER Port 23 STARTED ===")); - Serial.println(WifiStation.getIP()); - Serial.println(_F("=====================================\r\n")); - - commandHandler.registerCommand(CommandDelegate( - F("application"), F("This command is defined by the application\r\n"), F("testGroup"), applicationCommand)); -} - -void connectFail(const String& ssid, MacAddress bssid, WifiDisconnectReason reason) -{ - debugf("I'm NOT CONNECTED!"); -} - -void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway) -{ - startServers(); -} - -void init() -{ - Serial.begin(SERIAL_BAUD_RATE); // 115200 by default - Serial.systemDebugOutput(true); // Enable debug output to serial - Serial.commandProcessing(true); - WifiStation.enable(true); - WifiStation.config(WIFI_SSID, WIFI_PWD); - WifiAccessPoint.enable(false); - - // Run our method when station was connected to AP - WifiEvents.onStationDisconnect(connectFail); - WifiEvents.onStationGotIP(gotIP); - Debug.setDebug(Serial); - Debug.initCommand(); - Debug.start(); - Debug.println(_F("This is the debug output")); - telnetServer.enableDebug(true); /* is default but here to show possibility */ - commandHandler.registerCommand(CommandDelegate(F("appheap"), F("Usage appheap on/off/now for heapdisplay\r\n"), - F("testGroup"), appheapCommand)); - memoryTimer.initializeMs(250, checkHeap).start(); -}