AceRoutine  1.0.1
A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms.
CommandDispatcher.h
1 /*
2 MIT License
3 
4 Copyright (c) 2018 Brian T. Park
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12 
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24 
25 #ifndef ACE_ROUTINE_COMMAND_DISPATCHER_H
26 #define ACE_ROUTINE_COMMAND_DISPATCHER_H
27 
28 #include <Print.h> // Print
29 #include <AceRoutine.h>
30 #include "CommandHandler.h"
31 #include "InputLine.h"
32 
33 class __FlashStringHelper;
34 
35 namespace ace_routine {
36 namespace cli {
37 
53  public:
69  Channel<InputLine>& channel,
70  Print& printer,
71  const CommandHandler* const* commands,
72  uint8_t numCommands,
73  const char** argv,
74  uint8_t argvSize,
75  const char* prompt):
76  mChannel(channel),
77  mPrinter(printer),
78  mCommands(commands),
79  mNumCommands(numCommands),
80  mArgv(argv),
81  mArgvSize(argvSize),
82  mPrompt(prompt) {}
83 
85  virtual ~CommandDispatcher() {}
86 
95  static uint8_t tokenize(char* line, const char** argv, uint8_t argvSize) {
96  char* token = strtok(line, DELIMS);
97  int argc = 0;
98  while (token != nullptr && argc < argvSize) {
99  argv[argc] = token;
100  argc++;
101  token = strtok(nullptr, DELIMS);
102  }
103  return argc;
104  }
105 
106  int runCoroutine() override {
107  InputLine input;
108  COROUTINE_LOOP() {
109  if (mPrompt != nullptr) {
110  mPrinter.print(mPrompt);
111  }
112  COROUTINE_CHANNEL_READ(mChannel, input);
113 
114  if (input.status == InputLine::kStatusOverflow) {
115  printLineError(input.line, STATUS_BUFFER_OVERFLOW);
116  continue;
117  }
118 
119  if (mPrompt != nullptr) {
120  mPrinter.print(input.line); // line includes the \n
121  }
122  runCommand(input.line);
123  }
124  }
125 
135  const CommandHandler* findCommand(const char* cmd) const {
136  for (uint8_t i = 0; i < mNumCommands; i++) {
137  const CommandHandler* command = mCommands[i];
138  if (command->getName().compareTo(FCString(cmd)) == 0) {
139  return command;
140  }
141  }
142  return nullptr;
143  }
144 
145  protected:
146  // Disable copy-constructor and assignment operator
147  CommandDispatcher(const CommandDispatcher&) = delete;
148  CommandDispatcher& operator=(const CommandDispatcher&) = delete;
149 
151  void printLineError(const char* line, uint8_t statusCode) const;
152 
154  void helpCommandHandler(Print& printer, int argc, const char* const* argv)
155  const;
156 
158  void helpAll(Print& printer) const;
159 
161  bool helpSpecific(Print& printer, const char* cmd) const;
162 
164  static void printHelp(Print& printer, const CommandHandler* command);
165 
167  void runCommand(char* line) const;
168 
170  void findAndRunCommand(const char* cmd, int argc, const char* const* argv)
171  const;
172 
173  static const uint8_t STATUS_SUCCESS = 0;
174  static const uint8_t STATUS_BUFFER_OVERFLOW = 1;
175  static const uint8_t STATUS_FLUSH_TO_EOL = 2;
176  static const char DELIMS[];
177 
178  Channel<InputLine>& mChannel;
179  Print& mPrinter;
180  const CommandHandler* const* const mCommands;
181  uint8_t const mNumCommands;
182  const char** const mArgv;
183  uint8_t const mArgvSize;
184  const char* const mPrompt;
185 };
186 
187 }
188 }
189 
190 #endif
ace_routine::cli::CommandDispatcher::helpAll
void helpAll(Print &printer) const
Print help on all commands.
Definition: CommandDispatcher.cpp:77
ace_routine::cli::CommandDispatcher::tokenize
static uint8_t tokenize(char *line, const char **argv, uint8_t argvSize)
Tokenize the line, separating tokens delimited by whitespace (space, formfeed, carriage return,...
Definition: CommandDispatcher.h:95
ace_routine::cli::CommandDispatcher::findAndRunCommand
void findAndRunCommand(const char *cmd, int argc, const char *const *argv) const
Find and run the given command.
Definition: CommandDispatcher.cpp:122
ace_routine::cli::CommandDispatcher::printHelp
static void printHelp(Print &printer, const CommandHandler *command)
Print help string for the given command.
Definition: CommandDispatcher.cpp:95
COROUTINE_LOOP
#define COROUTINE_LOOP()
Mark the beginning of a coroutine loop.
Definition: Coroutine.h:129
ace_routine::cli::CommandDispatcher::~CommandDispatcher
virtual ~CommandDispatcher()
Destructor.
Definition: CommandDispatcher.h:85
ace_routine::FCString::compareTo
int compareTo(const FCString &that) const
Compare to another FCString.
Definition: FCString.cpp:86
ace_routine::FCString
A union of (const char*) and (const __FlashStringHelper*) with a discriminator.
Definition: FCString.h:46
ace_routine::cli::CommandDispatcher::printLineError
void printLineError(const char *line, uint8_t statusCode) const
Print the input line that caused an error along with its status code.
Definition: CommandDispatcher.cpp:39
ace_routine::cli::CommandDispatcher::runCommand
void runCommand(char *line) const
Tokenize the given line and run the command handler.
Definition: CommandDispatcher.cpp:107
ace_routine::Channel
An unbuffered synchronized channel.
Definition: Channel.h:43
ace_routine::cli::CommandHandler
Signature for a command handler.
Definition: CommandHandler.h:47
ace_routine::cli::CommandDispatcher::CommandDispatcher
CommandDispatcher(Channel< InputLine > &channel, Print &printer, const CommandHandler *const *commands, uint8_t numCommands, const char **argv, uint8_t argvSize, const char *prompt)
Constructor.
Definition: CommandDispatcher.h:68
ace_routine::cli::CommandDispatcher
A coroutine that reads lines from the Serial port, tokenizes the line on whitespace boundaries,...
Definition: CommandDispatcher.h:52
ace_routine::cli::CommandDispatcher::helpSpecific
bool helpSpecific(Print &printer, const char *cmd) const
Print helpString of specific cmd.
Definition: CommandDispatcher.cpp:85
ace_routine::Coroutine
Base class of all coroutines.
Definition: Coroutine.h:255
ace_routine::cli::InputLine
Message sent from StreamLineReader to CommandDispatcher coroutines through Channel<InputLine> channel...
Definition: InputLine.h:36
ace_routine::cli::CommandDispatcher::findCommand
const CommandHandler * findCommand(const char *cmd) const
Find the CommandHandler of the given command name.
Definition: CommandDispatcher.h:135
ace_routine::cli::CommandDispatcher::helpCommandHandler
void helpCommandHandler(Print &printer, int argc, const char *const *argv) const
Handle the 'help' command.
Definition: CommandDispatcher.cpp:55
ace_routine::cli::CommandDispatcher::runCoroutine
int runCoroutine() override
The body of the coroutine.
Definition: CommandDispatcher.h:106
ace_routine::cli::CommandHandler::getName
FCString getName() const
Return the name of the command.
Definition: CommandHandler.h:68