GRMrGecko
3 months ago
commit
27b2cfb80b
7 changed files with 597 additions and 0 deletions
-
19LICENSE.txt
-
11README.md
-
377cmd.cpp
-
67cmd.h
-
95examples/standard/standard.ino
-
19library.json
-
9library.properties
@ -0,0 +1,19 @@ |
|||||
|
Copyright (c) 2024 Mr. Gecko's Media (James Coleman). http://mrgeckosmedia.com/ |
||||
|
|
||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
|
of this software and associated documentation files (the "Software"), to deal |
||||
|
in the Software without restriction, including without limitation the rights |
||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
|
copies of the Software, and to permit persons to whom the Software is |
||||
|
furnished to do so, subject to the following conditions: |
||||
|
|
||||
|
The above copyright notice and this permission notice shall be included in all |
||||
|
copies or substantial portions of the Software. |
||||
|
|
||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
|
SOFTWARE. |
@ -0,0 +1,11 @@ |
|||||
|
# cmd |
||||
|
|
||||
|
This is a simple Arduino Library I wrote because the existing Libraries did not do what I was looking for. I wanted a simple command line interface that worked similar to Linux and Cisco clis where you can edit the buffer and ask for help. Its fairly simple to use: |
||||
|
|
||||
|
## Example usage |
||||
|
See the standard example .ino file. |
||||
|
|
||||
|
You can load the tty with: |
||||
|
```bash |
||||
|
screen -L /dev/ttyUSB0 9600 |
||||
|
``` |
@ -0,0 +1,377 @@ |
|||||
|
#include "cmd.h"
|
||||
|
|
||||
|
// Initiator.
|
||||
|
// Size is the number of commands, default callback is called if a command is
|
||||
|
// not found.
|
||||
|
Cmd::Cmd(size_t size, CmdFunction defaultCallback) { |
||||
|
m_size = size; |
||||
|
m_commands = (const char **)malloc(sizeof(const char *) * m_size); |
||||
|
m_functions = (CmdFunction *)malloc(sizeof(CmdFunction) * m_size); |
||||
|
m_defaultFunction = defaultCallback; |
||||
|
} |
||||
|
|
||||
|
// Return the set size of the command array.
|
||||
|
size_t Cmd::GetSize() { return m_size; } |
||||
|
|
||||
|
// Add a command to the function list. If list is too full, false is returned.
|
||||
|
bool Cmd::AddCmd(const char *cmd, CmdFunction function) { |
||||
|
if (m_nextCmd >= m_size) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
m_commands[m_nextCmd] = cmd; |
||||
|
m_functions[m_nextCmd] = function; |
||||
|
|
||||
|
m_nextCmd++; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
// Get array of all commands.
|
||||
|
const char **Cmd::GetCmds() { return m_commands; } |
||||
|
|
||||
|
// Rather or not we echo back to serial characters received.
|
||||
|
bool Cmd::GetEcho() { return m_echo; } |
||||
|
void Cmd::SetEcho(bool echo) { m_echo = echo; } |
||||
|
|
||||
|
// The separator for command parsing.
|
||||
|
const char *Cmd::GetSeparator() { return m_separator; } |
||||
|
void Cmd::SetSeparator(const char *separator) { m_separator = separator; } |
||||
|
|
||||
|
// Indicates the command line.
|
||||
|
const char *Cmd::GetLineIndicator() { return m_line_indicator; } |
||||
|
void Cmd::SetLineIndicator(const char *line_indicator) { |
||||
|
m_line_indicator = line_indicator; |
||||
|
} |
||||
|
|
||||
|
// Buffer size configuration.
|
||||
|
size_t Cmd::GetBufferSize() { return m_buffer_size; } |
||||
|
void Cmd::SetBufferSize(size_t bufferSize) { m_buffer_size = bufferSize; } |
||||
|
|
||||
|
// Return current buffer.
|
||||
|
const char *Cmd::GetBuffer() { return m_buffer; } |
||||
|
|
||||
|
// Resets the buffer and prints
|
||||
|
void Cmd::StartNewBuffer() { |
||||
|
free(m_buffer); |
||||
|
m_buffer = NULL; |
||||
|
Serial.print(m_line_indicator); |
||||
|
} |
||||
|
|
||||
|
// Print the current buffer.
|
||||
|
void Cmd::PrintBuffer() { |
||||
|
// If we're processing a command, do not print.
|
||||
|
if (m_processing) { |
||||
|
return; |
||||
|
} |
||||
|
// Set the last character in the buffer to null to terminate.
|
||||
|
m_buffer[m_buffer_read] = '\0'; |
||||
|
// Print indicator and buffer.
|
||||
|
Serial.print(m_line_indicator); |
||||
|
Serial.print(m_buffer); |
||||
|
// Move cursor to correct location.
|
||||
|
for (unsigned int i = m_buffer_cursor; i < m_buffer_read; i++) { |
||||
|
Serial.write('\x08'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Parse next token.
|
||||
|
char *Cmd::Parse() { return strtok(NULL, m_separator); } |
||||
|
|
||||
|
// Print help for the current command.
|
||||
|
void Cmd::PrintHelp() { |
||||
|
// Copy buffer to token buffer.
|
||||
|
m_bufferTok = (char *)malloc(m_buffer_size); |
||||
|
strcpy(m_bufferTok, m_buffer); |
||||
|
|
||||
|
// Tokenize buffer based on separator and get first token being the command.
|
||||
|
char *cmd = strtok(m_bufferTok, m_separator); |
||||
|
|
||||
|
// Printing help means the command line is currently the line we're on.
|
||||
|
Serial.println(); |
||||
|
|
||||
|
// To prevent buffer printing during a command execution.
|
||||
|
m_processing = true; |
||||
|
// Look for the command that matches.
|
||||
|
bool foundCmd = false; |
||||
|
// Only scan for command if specified.
|
||||
|
if (cmd != NULL) { |
||||
|
for (unsigned int i = 0; i < m_size && m_commands[i] != NULL; i++) { |
||||
|
if (strcasecmp_P(cmd, m_commands[i]) == 0) { |
||||
|
// If command matches, call its function and tell it we're asking for
|
||||
|
// help.
|
||||
|
m_functions[i](this, cmd, true); |
||||
|
foundCmd = true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// If command wasn't found, call the default callback and tell it we're asking
|
||||
|
// for help.
|
||||
|
if (!foundCmd) { |
||||
|
Serial.println("Calling default function"); |
||||
|
m_defaultFunction(this, cmd, true); |
||||
|
} |
||||
|
m_processing = false; |
||||
|
|
||||
|
// Print the buffer now that help was provided.
|
||||
|
Serial.println(); |
||||
|
PrintBuffer(); |
||||
|
|
||||
|
// Free memory used by the token buffer.
|
||||
|
free(m_bufferTok); |
||||
|
m_bufferTok = NULL; |
||||
|
} |
||||
|
|
||||
|
// Parse buffer for command.
|
||||
|
void Cmd::ParseBuffer() { |
||||
|
// Copy buffer to token buffer.
|
||||
|
m_bufferTok = (char *)malloc(m_buffer_size); |
||||
|
strcpy(m_bufferTok, m_buffer); |
||||
|
|
||||
|
// Tokenize buffer based on separator and get first token being the command.
|
||||
|
char *cmd = strtok(m_bufferTok, m_separator); |
||||
|
|
||||
|
// To prevent buffer printing during a command execution.
|
||||
|
m_processing = true; |
||||
|
// Look for the command that matches.
|
||||
|
bool foundCmd = false; |
||||
|
// Only scan for command if specified.
|
||||
|
if (cmd != NULL) { |
||||
|
for (unsigned int i = 0; i < m_size && m_commands[i] != NULL; i++) { |
||||
|
if (strcasecmp_P(cmd, m_commands[i]) == 0) { |
||||
|
// If command matches, call its function.
|
||||
|
m_functions[i](this, cmd, false); |
||||
|
foundCmd = true; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// If command wasn't found, call the default callback.
|
||||
|
if (!foundCmd) { |
||||
|
m_defaultFunction(this, cmd, false); |
||||
|
} |
||||
|
m_processing = false; |
||||
|
|
||||
|
// Free memory used by the token buffer.
|
||||
|
free(m_bufferTok); |
||||
|
m_bufferTok = NULL; |
||||
|
} |
||||
|
|
||||
|
// Main command loop, call in the main loop of your program.
|
||||
|
void Cmd::Loop() { |
||||
|
// If no serial data is available, we do not have anything to process.
|
||||
|
if (!Serial.available()) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// If buffer is not allocated, let's reset.
|
||||
|
if (m_buffer == NULL) { |
||||
|
m_buffer = (char *)malloc(m_buffer_size); |
||||
|
m_buffer_read = 0; |
||||
|
m_buffer_cursor = 0; |
||||
|
} |
||||
|
|
||||
|
// Start read and read all available data in serial RX buffer.
|
||||
|
bool receivedEndLine = false; |
||||
|
size_t availableData = Serial.available(); |
||||
|
for (size_t i = 1; i <= availableData; i++) { |
||||
|
char byteRead = Serial.read(); |
||||
|
|
||||
|
// If we're currently reading an escape character, verify state.
|
||||
|
if (m_buffer_reading_esc == 1) { |
||||
|
// If we get the bracket, we need to move on to the next step in reading
|
||||
|
// an escape character. Otherwise, we are not reading an escape character.
|
||||
|
if (byteRead == '[') { |
||||
|
m_buffer_reading_esc = 2; |
||||
|
continue; |
||||
|
} else { |
||||
|
m_buffer_reading_esc = 0; |
||||
|
} |
||||
|
} else if (m_buffer_reading_esc == 2) { |
||||
|
// Process escape character read.
|
||||
|
switch (byteRead) { |
||||
|
case 'D': // Move cursor left
|
||||
|
m_buffer_reading_esc = 0; |
||||
|
if (m_buffer_cursor <= 0) { |
||||
|
continue; |
||||
|
} |
||||
|
m_buffer_cursor--; |
||||
|
Serial.print("\x1b[D"); |
||||
|
break; |
||||
|
case 'C': // Move cursor right
|
||||
|
m_buffer_reading_esc = 0; |
||||
|
if (m_buffer_cursor >= m_buffer_read) { |
||||
|
continue; |
||||
|
} |
||||
|
m_buffer_cursor++; |
||||
|
Serial.print("\x1b[C"); |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
m_buffer_reading_esc = 0; |
||||
|
break; |
||||
|
} |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// Check if ascii byte.
|
||||
|
bool is_ascii = byteRead >= 32 && byteRead <= 126; |
||||
|
|
||||
|
// If we're to echo and its an ascii byte, send the byte we read back to the
|
||||
|
// serial console.
|
||||
|
if (m_echo && is_ascii) { |
||||
|
Serial.write(byteRead); |
||||
|
} |
||||
|
|
||||
|
// If escape character received, move into escape reading mode.
|
||||
|
if (byteRead == '\x1b') { |
||||
|
m_buffer_reading_esc = 1; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// If backspace or delete key.
|
||||
|
if (byteRead == 8 || byteRead == 127) { |
||||
|
// Only perform character delete if buffer exists and cursor isn't at
|
||||
|
// start.
|
||||
|
if (m_buffer_read != 0 && m_buffer_cursor != 0) { |
||||
|
// If cursor isn't at start, we need to re-print the line minus the
|
||||
|
// character deleted.
|
||||
|
if (m_buffer_cursor != m_buffer_read) { |
||||
|
// Create new buffer for re-writing current buffer.
|
||||
|
char *buf = (char *)malloc(m_buffer_size); |
||||
|
// Copy current buffer.
|
||||
|
strcpy(buf, m_buffer); |
||||
|
// Clear the line from the curosr.
|
||||
|
Serial.print("\x08\x1b[1P"); |
||||
|
// Print and re-write the buffer from the cursor location minus
|
||||
|
// character deleted.
|
||||
|
for (unsigned int i = m_buffer_cursor; i < m_buffer_read; i++) { |
||||
|
m_buffer[i - 1] = buf[i]; |
||||
|
Serial.write(buf[i]); |
||||
|
} |
||||
|
// Now that the buffer has been re-written, we can free the buffer.
|
||||
|
free(buf); |
||||
|
// Move the cursor back to where it should be.
|
||||
|
for (unsigned int i = m_buffer_cursor; i < m_buffer_read; i++) { |
||||
|
Serial.write('\x08'); |
||||
|
} |
||||
|
} else { |
||||
|
// As we're not deleting from cursor location, we can just clear the
|
||||
|
// last character via this escape.
|
||||
|
Serial.print("\x08\x1b[K"); |
||||
|
} |
||||
|
// Wipe the last byte in the buffer in both cases.
|
||||
|
m_buffer_read--; |
||||
|
m_buffer_cursor--; |
||||
|
m_buffer[m_buffer_read] = '\0'; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// If begining of line requested.
|
||||
|
if (byteRead == 1) { |
||||
|
// Move cursor to beginning of line.
|
||||
|
while (m_buffer_cursor != 0) { |
||||
|
m_buffer_cursor--; |
||||
|
Serial.print("\x1b[D"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// If end of line requested.
|
||||
|
if (byteRead == 5) { |
||||
|
// Move cursor to end of line.
|
||||
|
while (m_buffer_cursor < m_buffer_read) { |
||||
|
m_buffer_cursor++; |
||||
|
Serial.print("\x1b[C"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// If cancel or exit received.
|
||||
|
if (byteRead == 3 || byteRead == 4) { |
||||
|
Serial.println(); |
||||
|
// Clear buffer, start new line,
|
||||
|
StartNewBuffer(); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// Clear screen.
|
||||
|
if (byteRead == 12) { |
||||
|
m_buffer[m_buffer_read] = '\0'; |
||||
|
Serial.print("\x1b[H\x1b[J"); |
||||
|
PrintBuffer(); |
||||
|
} |
||||
|
|
||||
|
// If end of line.
|
||||
|
if (byteRead == '\r') { |
||||
|
receivedEndLine = true; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
// If help requested, print it.
|
||||
|
if (byteRead == '?') { |
||||
|
m_buffer[m_buffer_read] = '\0'; |
||||
|
PrintHelp(); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// If not ascii, we only allow ascii on the cli.
|
||||
|
if (!is_ascii) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
// If cursor is not at end, we need to write new byte where cursor is.
|
||||
|
if (m_buffer_cursor != m_buffer_read) { |
||||
|
// Copy current buffer for re-write.
|
||||
|
char *buf = (char *)malloc(m_buffer_size); |
||||
|
strcpy(buf, m_buffer); |
||||
|
// Set current cursor location byte to newly read byte.
|
||||
|
m_buffer[m_buffer_cursor] = byteRead; |
||||
|
// From cursor location, re-write the buffer with old buffer data and
|
||||
|
// print to the console.
|
||||
|
for (unsigned int i = m_buffer_cursor; i < m_buffer_read; i++) { |
||||
|
m_buffer[i + 1] = buf[i]; |
||||
|
Serial.write(buf[i]); |
||||
|
} |
||||
|
// We're done with the buffer copy.
|
||||
|
free(buf); |
||||
|
// Move cursor back to where it was.
|
||||
|
for (unsigned int i = m_buffer_cursor; i < m_buffer_read; i++) { |
||||
|
Serial.write('\x08'); |
||||
|
} |
||||
|
} else { |
||||
|
// Otherwise new byte can go to end of buffer.
|
||||
|
m_buffer[m_buffer_read] = byteRead; |
||||
|
} |
||||
|
// We read a new byte, increment the cursor location and read index.
|
||||
|
m_buffer_read++; |
||||
|
m_buffer_cursor++; |
||||
|
|
||||
|
// If we're going to overflow next read, we need to stop that.
|
||||
|
if (m_buffer_read >= (m_buffer_size - 1)) { |
||||
|
Serial.println("Data too large."); |
||||
|
|
||||
|
// Clear the buffer, and start new line.
|
||||
|
StartNewBuffer(); |
||||
|
|
||||
|
// Clear the serial buffer.
|
||||
|
while (Serial.available()) { |
||||
|
Serial.read(); |
||||
|
} |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// If we received end of line in read, we need to parse the buffer.
|
||||
|
if (receivedEndLine) { |
||||
|
// Print new line and null terminate the buffer.
|
||||
|
Serial.println(); |
||||
|
m_buffer[m_buffer_read] = '\0'; |
||||
|
|
||||
|
// Parse the buffer.
|
||||
|
ParseBuffer(); |
||||
|
|
||||
|
// Start new buffer.
|
||||
|
StartNewBuffer(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,67 @@ |
|||||
|
#ifndef _CMD_H_ |
||||
|
#define _CMD_H_ |
||||
|
|
||||
|
#include <Arduino.h> |
||||
|
#include <stdint.h> |
||||
|
#include <stdio.h> |
||||
|
#include <string.h> |
||||
|
|
||||
|
class Cmd; |
||||
|
|
||||
|
typedef void (*CmdFunction)(Cmd *thisCmd, char *command, bool printHelp); |
||||
|
|
||||
|
class Cmd { |
||||
|
protected: |
||||
|
const char **m_commands = NULL; |
||||
|
CmdFunction *m_functions = NULL; |
||||
|
|
||||
|
CmdFunction m_defaultFunction; |
||||
|
|
||||
|
size_t m_size = 0; |
||||
|
size_t m_nextCmd = 0; |
||||
|
|
||||
|
bool m_echo = true; |
||||
|
bool m_processing = false; |
||||
|
const char *m_separator = " "; |
||||
|
const char *m_line_indicator = "$ "; |
||||
|
size_t m_buffer_size = 50; |
||||
|
|
||||
|
char *m_buffer = NULL; |
||||
|
char *m_bufferTok = NULL; |
||||
|
size_t m_buffer_read = 0; |
||||
|
uint8_t m_buffer_reading_esc = 0; |
||||
|
size_t m_buffer_cursor = 0; |
||||
|
|
||||
|
void PrintHelp(); |
||||
|
void ParseBuffer(); |
||||
|
void StartNewBuffer(); |
||||
|
|
||||
|
public: |
||||
|
Cmd(size_t size, CmdFunction defaultCallback); |
||||
|
|
||||
|
size_t GetSize(); |
||||
|
bool AddCmd(const char *cmd, CmdFunction function); |
||||
|
const char **GetCmds(); |
||||
|
|
||||
|
bool GetEcho(); |
||||
|
void SetEcho(bool echo); |
||||
|
|
||||
|
const char *GetSeparator(); |
||||
|
void SetSeparator(const char *separator); |
||||
|
|
||||
|
const char *GetLineIndicator(); |
||||
|
void SetLineIndicator(const char *line_indicator); |
||||
|
|
||||
|
size_t GetBufferSize(); |
||||
|
void SetBufferSize(size_t bufferSize); |
||||
|
|
||||
|
const char *GetBuffer(); |
||||
|
void PrintBuffer(); |
||||
|
char *Parse(); |
||||
|
|
||||
|
void SendESC(const char *code); |
||||
|
|
||||
|
void Loop(); |
||||
|
}; |
||||
|
|
||||
|
#endif // _CMD_H_ |
@ -0,0 +1,95 @@ |
|||||
|
#include <cmd.h>
|
||||
|
|
||||
|
// Global command variable.
|
||||
|
Cmd *cmd; |
||||
|
|
||||
|
// Command entered was invalid, or help is being requested.
|
||||
|
void cmd_unrecognized(Cmd *thisCmd, char *command, bool printHelp) { |
||||
|
// If help is being requested, print the available commands.
|
||||
|
if (printHelp) { |
||||
|
// Get the command parameters.
|
||||
|
size_t size = cmd->GetSize(); |
||||
|
PGM_P *commands = cmd->GetCmds(); |
||||
|
|
||||
|
// Print each command.
|
||||
|
Serial.println("Available commands:\n"); |
||||
|
for (int i = 0; i < size && commands[i] != NULL; i++) { |
||||
|
char buf[100]; |
||||
|
sprintf_P(buf, commands[i]); |
||||
|
Serial.println(buf); |
||||
|
} |
||||
|
// Stop here.
|
||||
|
return; |
||||
|
} |
||||
|
// No help was requested, so the command provided likely doesn't exist.
|
||||
|
Serial.print("Unrecognized command ["); |
||||
|
Serial.print(command); |
||||
|
Serial.println("]"); |
||||
|
} |
||||
|
|
||||
|
// Simple echo ping command.
|
||||
|
void cmd_pi(Cmd *thisCmd, char *command, bool printHelp) { |
||||
|
// If help was requested, print the help for this command.
|
||||
|
if (printHelp) { |
||||
|
Serial.print(command); |
||||
|
Serial.println(" *"); |
||||
|
return; |
||||
|
} |
||||
|
// Echo back the buffer.
|
||||
|
Serial.println(cmd->GetBuffer()); |
||||
|
} |
||||
|
|
||||
|
// Demo send command.
|
||||
|
void cmd_send(Cmd *thisCmd, char *command, bool printHelp) { |
||||
|
// If help was requested, print the help.
|
||||
|
if (printHelp) { |
||||
|
Serial.print(command); |
||||
|
Serial.println(" address code"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Parse the next available argument.
|
||||
|
char *parsed = cmd->Parse(); |
||||
|
if (parsed == NULL) { |
||||
|
Serial.println("Invalid address"); |
||||
|
return; |
||||
|
} |
||||
|
// Parse integer.
|
||||
|
int address = atoi(parsed); |
||||
|
|
||||
|
// Get the next argument.
|
||||
|
parsed = cmd->Parse(); |
||||
|
if (parsed == NULL) { |
||||
|
Serial.println("Invalid code"); |
||||
|
return; |
||||
|
} |
||||
|
// Parse char.
|
||||
|
unsigned char code = atoi(parsed); |
||||
|
|
||||
|
// Print parsed arguments.
|
||||
|
Serial.print("Sending code: "); |
||||
|
Serial.print(code); |
||||
|
Serial.print(" to <"); |
||||
|
Serial.print(address); |
||||
|
Serial.println(">"); |
||||
|
} |
||||
|
|
||||
|
void setup() { |
||||
|
// Setup serial interface.
|
||||
|
Serial.begin(9600); |
||||
|
|
||||
|
// Initialize the command line with 2 commands.
|
||||
|
cmd = new Cmd(2, cmd_unrecognized); |
||||
|
|
||||
|
// Add commands.
|
||||
|
cmd->AddCmd(PSTR("pi"), cmd_pi); |
||||
|
cmd->AddCmd(PSTR("send"), cmd_send); |
||||
|
|
||||
|
// Print a line indicator to inform the user the cli is ready.
|
||||
|
Serial.print(cmd->GetLineIndicator()); |
||||
|
} |
||||
|
|
||||
|
void loop() { |
||||
|
// Run the command line loop.
|
||||
|
cmd->Loop(); |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
{ |
||||
|
"name": "cmd", |
||||
|
"description": "A serial command line interface with buffer editing.", |
||||
|
"keywords": "serial, cmd, communication, processing, command", |
||||
|
"authors": |
||||
|
{ |
||||
|
"name": "James Coleman", |
||||
|
"email": "grmrgecko@gmail.com", |
||||
|
"url": "https://github.com/GRMrGecko" |
||||
|
}, |
||||
|
"repository": |
||||
|
{ |
||||
|
"type": "git", |
||||
|
"url": "https://github.com/GRMrGecko/cmd.git" |
||||
|
}, |
||||
|
"version": "1.0.0", |
||||
|
"frameworks": "arduino", |
||||
|
"platforms": "*" |
||||
|
} |
@ -0,0 +1,9 @@ |
|||||
|
name=cmd |
||||
|
version=1.0.0 |
||||
|
author=James Coleman <grmrgecko@gmail.com> |
||||
|
maintainer=James Coleman <grmrgecko@gmail.com> |
||||
|
sentence=A serial command line interface with buffer editing. |
||||
|
paragraph=An easy to use command line interface, simply add commands and their callbacks. |
||||
|
category=Data Processing |
||||
|
url=https://github.com/GRMrGecko/cmd |
||||
|
architectures=* |
Write
Preview
Loading…
Cancel
Save
Reference in new issue