Initial Check-in of CLI Library
This commit is contained in:
178
src/CLI.cpp
Normal file
178
src/CLI.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* CLI.cpp - CLI library for Arduino/ESP8266 and others implementation
|
||||
*
|
||||
* Version 1.0, latest version, documentation and bugtracker available at:
|
||||
* https://gitlab.lindenaar.net/arduino/CLI
|
||||
*
|
||||
* Copyright (c) 2019 Frederik Lindenaar
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify it under
|
||||
* the terms of version 3 of the GNU General Public License as published by the
|
||||
* Free Software Foundation, or (at your option) a later version of the license.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, visit <http://www.gnu.org/licenses/> to download it.
|
||||
*/
|
||||
|
||||
#include <CLI.h>
|
||||
|
||||
#define CHAR_TAB '\t'
|
||||
#define CHAR_BS '\b'
|
||||
#define CHAR_DELETE char(127)
|
||||
#define CHAR_CR '\r'
|
||||
#define CHAR_LF '\n'
|
||||
|
||||
const char CLI_DEFAULT_PROMPT[] PROGMEM = "\n> ";
|
||||
const char CLI_PREFIX_PARAMETER_ERROR[] PROGMEM = "Invalid parameters for ";
|
||||
const char CLI_PREFIX_UNKNOWN_COMMAND[] PROGMEM = "Unknown command ";
|
||||
|
||||
size_t CLI::print_P (const char *str PROGMEM) {
|
||||
size_t len = 0;
|
||||
if (str) {
|
||||
while (char c = pgm_read_byte(str++)) {
|
||||
write(c);
|
||||
len++;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void CLI::print2digits(uint8_t num, char filler, uint8_t base) {
|
||||
if (num < base) print(filler);
|
||||
print(num, base);
|
||||
}
|
||||
|
||||
void CLI::print_mem(uint16_t addr, const uint8_t buff[], uint8_t len, uint8_t width) {
|
||||
if (addr < 0x1000) print(' ');
|
||||
if (addr < 0x100) print(' ');
|
||||
if (addr < 0x10) print(' ');
|
||||
print(addr, HEX);
|
||||
print(':');
|
||||
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
print(' ');
|
||||
if (buff[i] < 0x10) print(0);
|
||||
print(buff[i], HEX);
|
||||
}
|
||||
while (width > len++) print_P(PSTR(" "));
|
||||
|
||||
print('\t');
|
||||
for (uint8_t i = 0; i < len; i++)
|
||||
write(isprint(buff[i]) ? buff[i] : '.');
|
||||
|
||||
println();
|
||||
}
|
||||
|
||||
void CLI::printtab() {
|
||||
print(CHAR_TAB);
|
||||
};
|
||||
|
||||
CLI::CLI(Stream &stream, const char *banner PROGMEM, const char *prompt PROGMEM) : _stream(&stream), _banner(banner) {
|
||||
_state = STATE_INIT;
|
||||
_command_count = 0;
|
||||
_prompt = (prompt) ? prompt : CLI_DEFAULT_PROMPT;
|
||||
};
|
||||
|
||||
void CLI::add_command(CLI_Command *cmd) {
|
||||
if (_command_count < CLI_MAX_CMDS)
|
||||
_commands[_command_count++] = cmd;
|
||||
};
|
||||
|
||||
CLI_Command *CLI::get_command(int index) {
|
||||
return (index < _command_count) ? _commands[index] : NULL;
|
||||
}
|
||||
|
||||
CLI_Command *CLI::get_command(const char *name, int namelen) {
|
||||
for (int i = 0; i < _command_count; i++) {
|
||||
if (_commands[i]->matches(name, namelen)) return _commands[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if CLI_MAX_CMDS < 255
|
||||
uint8_t CLI::find_command(const char *name, int namelen) {
|
||||
uint8_t idx = _command_count;
|
||||
#else
|
||||
uint16_t CLI::find_command(const char *name, int namelen) {
|
||||
uint16_t idx = _command_count;
|
||||
#endif
|
||||
while (idx-- && !_commands[idx]->matches(name, namelen));
|
||||
return idx;
|
||||
}
|
||||
|
||||
bool CLI::process() { // Workhorse of the CLI
|
||||
if (_state == STATE_INIT) { // INIT: print banner (if set)
|
||||
if (_banner) {
|
||||
print_P(_banner);
|
||||
println();
|
||||
}
|
||||
_state = STATE_READY;
|
||||
} else if (_state == STATE_READY) { // READY: print prompt & init
|
||||
print_P(_prompt);
|
||||
memset(_cmdbuffer, 0, _line_len);
|
||||
_line_len = 0;
|
||||
_current_cmd = NULL;
|
||||
_state = STATE_INPUT;
|
||||
} else if (_state == STATE_INPUT) { // INPUT: process user input
|
||||
while (available()) { // loop while stream input
|
||||
int c = read(); // get next char
|
||||
if (c == CHAR_DELETE) { // Process BACKSPACE key
|
||||
print_P(PSTR("\b \b"));
|
||||
if (_line_len) _cmdbuffer[_line_len--] = 0;
|
||||
} else if (c == CHAR_CR) { // Process ENTER key
|
||||
println();
|
||||
_state = STATE_PARSE; // Change state to PARSE
|
||||
return false; // and stop processing input
|
||||
} else if (c != CHAR_LF && isprint(c)) { // Process other valid input
|
||||
if (_line_len < CLI_MAX_LINE - 1) { // add to line if space left
|
||||
_cmdbuffer[_line_len++] = c;
|
||||
write(c); // print char to echo input
|
||||
} else { // if not, beep & ignore
|
||||
write(char(7));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (_state == STATE_PARSE) { // PARSE: parse user command
|
||||
const char *cmd = CLI_STR_skipSep(_cmdbuffer); // skip initial whitespace
|
||||
if (*cmd && cmd - _cmdbuffer < _line_len) { // do we have a command?
|
||||
for (char *p = _cmdbuffer + _line_len - 1; *p == ' '; p--, _line_len--)
|
||||
*p = 0; // clear trailing whitespace
|
||||
const char *sep = CLI_STR_findSep(cmd); // find end of command
|
||||
if (_current_cmd = get_command(cmd, sep - cmd)) { // known command?
|
||||
sep = CLI_STR_skipSep(sep); // get start of params
|
||||
if (_current_cmd->setparams((*sep) ? sep : 0)) {// parse params
|
||||
_state = STATE_EXEC; // all OK, change state
|
||||
return true; // and stop processing
|
||||
} else print_P(CLI_PREFIX_PARAMETER_ERROR); // print invalid parameters
|
||||
} else print_P(CLI_PREFIX_UNKNOWN_COMMAND) ; // print unknown command
|
||||
_stream->write(cmd, sep - cmd); // print command name
|
||||
println(); // and add newline
|
||||
}
|
||||
_state = STATE_READY; // if we get here: READY
|
||||
} else if (_state == STATE_EXEC) { // EXEC: execute the command
|
||||
if (_current_cmd->execute(*this)) { // Execute, false when done
|
||||
return true; // not yet done, return true
|
||||
} else {
|
||||
_state = STATE_READY; // done, READY
|
||||
}
|
||||
}
|
||||
return false; // default result false (done)
|
||||
}
|
||||
|
||||
|
||||
CLI_Command::CLI_Command(CLI &cli, const char *command, const char *description, const char *usagehelp) : command(command), description(description), usagehelp(usagehelp) {
|
||||
cli.add_command(this);
|
||||
};
|
||||
|
||||
bool CLI_Command::matches(const char *cmd, uint8_t cmdlen) {
|
||||
return pgm_read_byte(&command[cmdlen]) == 0 && strncmp_P(cmd, command, cmdlen) == 0;
|
||||
};
|
||||
|
||||
bool CLI_Command::setparams(const char *params) {
|
||||
return !params;
|
||||
}
|
||||
|
||||
182
src/CLI.h
Normal file
182
src/CLI.h
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* CLI.h - CLI library for Arduino/ESP8266 and others definitions
|
||||
*
|
||||
* Version 1.0, latest version, documentation and bugtracker available at:
|
||||
* https://gitlab.lindenaar.net/arduino/CLI
|
||||
*
|
||||
* Copyright (c) 2019 Frederik Lindenaar
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify it under
|
||||
* the terms of version 3 of the GNU General Public License as published by the
|
||||
* Free Software Foundation, or (at your option) a later version of the license.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, visit <http://www.gnu.org/licenses/> to download it.
|
||||
*/
|
||||
|
||||
#include <Stream.h>
|
||||
|
||||
#ifndef CLI_H
|
||||
#define CLI_H
|
||||
|
||||
#ifndef CLI_MAX_CMDS
|
||||
#define CLI_MAX_CMDS 16
|
||||
#endif // CLI_MAX_CMDS
|
||||
|
||||
#ifndef CLI_MAX_LINE
|
||||
#define CLI_MAX_LINE 80
|
||||
#endif // CLI_MAX_LINE
|
||||
|
||||
class CLI;
|
||||
|
||||
struct CLI_Command_Param {
|
||||
const char *param PROGMEM;
|
||||
union {
|
||||
int int16;
|
||||
uint16_t uint16;
|
||||
int8_t int8;
|
||||
uint8_t uint8;
|
||||
int32_t int32;
|
||||
uint32_t uint32;
|
||||
char *str PROGMEM;
|
||||
};
|
||||
};
|
||||
|
||||
struct CLI_Command_Flags {
|
||||
const char *command;
|
||||
uint8_t cmdlen, flags, intparam;
|
||||
};
|
||||
|
||||
const char *CLI_STR_skipSep(const char *str);
|
||||
const char *CLI_STR_findSep(const char *str);
|
||||
const char *CLI_STR_parseInt(const char *, int &, int = -32768, int = 32767);
|
||||
const char *CLI_STR_parse_HEX_byte(const char *, uint8_t &);
|
||||
const struct CLI_Command_Param *CLI_STR_parseParam_P (const char *, const struct CLI_Command_Param params[]);
|
||||
const char *CLI_STR_parseFlags_P (const char *, const struct CLI_Command_Flags params[], uint8_t, uint8_t, uint8_t *);
|
||||
|
||||
class CLI_Command {
|
||||
friend class Help_Command;
|
||||
friend class CLI;
|
||||
protected:
|
||||
const char *command, *description, *usagehelp;
|
||||
bool matches(const char *cmd, uint8_t cmdlen);
|
||||
public:
|
||||
CLI_Command(CLI &cli , const char *command PROGMEM, const char *description PROGMEM, const char *help PROGMEM = NULL);
|
||||
virtual bool setparams(const char *params);
|
||||
virtual bool execute(CLI &cli) = 0;
|
||||
};
|
||||
|
||||
|
||||
class Help_Command : public CLI_Command {
|
||||
CLI &_cli;
|
||||
#if CLI_MAX_CMDS < 255
|
||||
uint8_t _cmd_idx;
|
||||
#else
|
||||
uint16_t _cmd_idx;
|
||||
#endif
|
||||
bool _cmd_list;
|
||||
public:
|
||||
Help_Command(CLI &cli);
|
||||
bool setparams(const char *);
|
||||
bool execute(CLI &cli);
|
||||
};
|
||||
|
||||
|
||||
class EEPROM_Dump_Command : public CLI_Command {
|
||||
int _offset;
|
||||
public:
|
||||
EEPROM_Dump_Command(CLI &cli);
|
||||
bool setparams(const char *);
|
||||
bool execute(CLI &cli);
|
||||
};
|
||||
|
||||
class Reset_Command : public CLI_Command {
|
||||
int _resetting;
|
||||
public:
|
||||
Reset_Command(CLI &cli);
|
||||
bool execute(CLI &cli);
|
||||
};
|
||||
|
||||
class I2C_Scan_Command : public CLI_Command {
|
||||
uint8_t _address, _found;
|
||||
public:
|
||||
I2C_Scan_Command(CLI &cli);
|
||||
bool setparams(const char *);
|
||||
bool execute(CLI &cli);
|
||||
};
|
||||
|
||||
class I2C_Dump_Command : public CLI_Command {
|
||||
uint8_t _address;
|
||||
bool _large;
|
||||
uint16_t _length, _offset;
|
||||
public:
|
||||
I2C_Dump_Command(CLI &cli);
|
||||
bool setparams(const char *);
|
||||
bool execute(CLI &cli);
|
||||
};
|
||||
|
||||
|
||||
class CLI : public Stream {
|
||||
enum CLI_State { STATE_INIT, STATE_READY, STATE_INPUT, STATE_PARSE, STATE_EXEC } _state;
|
||||
#if CLI_MAX_CMDS < 255
|
||||
uint8_t _command_count;
|
||||
#else
|
||||
uint16_t _command_count;
|
||||
#endif
|
||||
CLI_Command *_commands[CLI_MAX_CMDS];
|
||||
#if CLI_MAX_LINE < 255
|
||||
uint8_t _line_len;
|
||||
#else
|
||||
uint16_t _line_len;
|
||||
#endif
|
||||
char _cmdbuffer[CLI_MAX_LINE];
|
||||
// const char *_params;
|
||||
CLI_Command *_current_cmd;
|
||||
protected:
|
||||
Stream *_stream;
|
||||
const char *_banner, *_prompt;
|
||||
public:
|
||||
CLI(Stream &stream, const char *banner PROGMEM = NULL, const char *prompt PROGMEM = NULL);
|
||||
void add_command(CLI_Command *cmd);
|
||||
CLI_Command *get_command(int);
|
||||
CLI_Command *get_command(const char *, int);
|
||||
#if CLI_MAX_CMDS < 256
|
||||
uint8_t find_command(const char *, int);
|
||||
inline uint8_t command_count() {
|
||||
#else
|
||||
uint16_t find_command(const char *, int);
|
||||
inline uint16_t command_count() {
|
||||
#endif
|
||||
return _command_count;
|
||||
};
|
||||
|
||||
inline int available() {
|
||||
return _stream->available();
|
||||
};
|
||||
|
||||
inline int peek() {
|
||||
return _stream->peek();
|
||||
};
|
||||
|
||||
inline int read() {
|
||||
return _stream->read();
|
||||
};
|
||||
|
||||
inline size_t write(uint8_t c) {
|
||||
return _stream->write(c);
|
||||
};
|
||||
|
||||
size_t print_P (const char *str PROGMEM);
|
||||
void print2digits(uint8_t num, char filler = '0', uint8_t base=10);
|
||||
void print_mem(uint16_t addr, const uint8_t buff[], uint8_t len, uint8_t width=16);
|
||||
void printtab();
|
||||
|
||||
bool process();
|
||||
};
|
||||
|
||||
#endif // CLI_H
|
||||
|
||||
110
src/CLI_Utils.cpp
Normal file
110
src/CLI_Utils.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* CLI_Utils.cpp - CLI library for Arduino/ESP8266 and others utility functions
|
||||
*
|
||||
* Version 1.0, latest version, documentation and bugtracker available at:
|
||||
* https://gitlab.lindenaar.net/arduino/CLI
|
||||
*
|
||||
* Copyright (c) 2019 Frederik Lindenaar
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify it under
|
||||
* the terms of version 3 of the GNU General Public License as published by the
|
||||
* Free Software Foundation, or (at your option) a later version of the license.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, visit <http://www.gnu.org/licenses/> to download it.
|
||||
*/
|
||||
|
||||
#include <CLI.h>
|
||||
|
||||
const char *CLI_STR_skipSep(const char *str) {
|
||||
while (*str == ' ') str++;
|
||||
return str;
|
||||
};
|
||||
|
||||
const char *CLI_STR_findSep(const char *str) {
|
||||
while (*str && *str != ' ') str++;
|
||||
return str;
|
||||
};
|
||||
|
||||
const char *CLI_STR_parseInt(const char *str, int &value, int minvalue, int maxvalue) {
|
||||
int v = 0;
|
||||
const char *p = str;
|
||||
bool negative = *p == '-';
|
||||
if (negative || *p == '+') p++;
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
v *= 10;
|
||||
v += *(p++) - '0';
|
||||
}
|
||||
if (str != p && v >= minvalue && v <= maxvalue) {
|
||||
value = (negative) ? -v : v;
|
||||
return p;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t parseHexNibble(char c) {
|
||||
if(c >= 'a' && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
} else if(c >= 'A' && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
} else if(c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
} else return 0xff;
|
||||
}
|
||||
|
||||
const char *CLI_STR_parse_HEX_byte(const char *str, uint8_t &value) {
|
||||
if (str) {
|
||||
uint8_t v;
|
||||
if((v = parseHexNibble(*(str++))) <= 0xf) {
|
||||
value = v << 4;
|
||||
if((v = parseHexNibble(*(str++))) <= 0xf) {
|
||||
value |= v;
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct CLI_Command_Param *CLI_STR_parseParam_P (const char *param, const struct CLI_Command_Param params[]) {
|
||||
for (const struct CLI_Command_Param *p = params; pgm_read_ptr(&p->param); p++)
|
||||
if (!strcmp_P(param, (char *)pgm_read_ptr(&p->param))) return p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *CLI_STR_parseFlags_P (const char *str, const struct CLI_Command_Flags params[], uint8_t param_count, uint8_t mask, uint8_t *flags) {
|
||||
uint8_t f = 0;
|
||||
while (*str) {
|
||||
const struct CLI_Command_Flags *p = params;
|
||||
while (p <= ¶ms[param_count] && strncmp_P(str, pgm_read_word(&p->command), pgm_read_byte(&p->cmdlen)) ) p++;
|
||||
uint8_t flags = pgm_read_byte(&p->flags);
|
||||
if (p > ¶ms[param_count] || (f != 0 && ((f & mask) != (flags & mask)))) return 0;
|
||||
f |= flags;
|
||||
str = CLI_STR_skipSep(str + pgm_read_byte(&p->cmdlen));
|
||||
|
||||
if (uint8_t intparam = pgm_read_byte(&p->intparam)) {
|
||||
int i;
|
||||
if (str = CLI_STR_parseInt(str, i)) {
|
||||
if (pgm_read_byte(&p->cmdlen) == 0)
|
||||
if (int divider = pgm_read_word(&p->command)) {
|
||||
i /= divider & 0xff;
|
||||
i += divider >> 8;
|
||||
}
|
||||
if (i <= (intparam & 0x1f)) {
|
||||
f |= i << (intparam >> 5);
|
||||
str = CLI_STR_skipSep(str);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (*str) return 0;
|
||||
*flags = f;
|
||||
return str;
|
||||
}
|
||||
|
||||
98
src/Commands.cpp
Normal file
98
src/Commands.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* CLI_Commands.cpp - CLI library for Arduino/ESP8266 and others general commands
|
||||
*
|
||||
* Version 1.0, latest version, documentation and bugtracker available at:
|
||||
* https://gitlab.lindenaar.net/arduino/CLI
|
||||
*
|
||||
* Copyright (c) 2019 Frederik Lindenaar
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify it under
|
||||
* the terms of version 3 of the GNU General Public License as published by the
|
||||
* Free Software Foundation, or (at your option) a later version of the license.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, visit <http://www.gnu.org/licenses/> to download it.
|
||||
*/
|
||||
|
||||
#include <CLI.h>
|
||||
#include <avr/eeprom.h>
|
||||
|
||||
Help_Command::Help_Command(CLI & cli) :
|
||||
CLI_Command(cli, PSTR("help"), PSTR("Display command help"),
|
||||
PSTR("Usage: help [<command>]\n"
|
||||
"\tdisplays usage help for <command> or lists available commands\n"
|
||||
"\twhen called without parameters\n")), _cli(cli) { };
|
||||
|
||||
bool Help_Command::setparams(const char *params) {
|
||||
if (_cmd_list = !params) {
|
||||
_cmd_idx = 0;
|
||||
return true;
|
||||
} else {
|
||||
_cmd_idx = _cli.find_command(params, strlen(params));
|
||||
return _cmd_idx < _cli.command_count();
|
||||
}
|
||||
}
|
||||
|
||||
bool Help_Command::execute(CLI &cli) {
|
||||
if(CLI_Command *cmd = cli.get_command(_cmd_idx)) {
|
||||
if (_cmd_list) {
|
||||
if (_cmd_idx == 0) cli.print_P(PSTR("Known Commands:\n"));
|
||||
_cmd_idx++;
|
||||
cli.printtab();
|
||||
if (cli.print_P(cmd->command) < 8) cli.printtab();
|
||||
cli.printtab();
|
||||
cli.print_P(cmd->description);
|
||||
cli.println();
|
||||
return true;
|
||||
} else {
|
||||
cli.print_P(cmd->description);
|
||||
cli.println();
|
||||
if (cmd->usagehelp) cli.print_P(cmd->usagehelp);
|
||||
}
|
||||
} else if (_cmd_list) {
|
||||
cli.print_P((_cmd_idx)
|
||||
? PSTR("\nfor more information on a command use \"help <command>\"")
|
||||
: PSTR("No Commands"));
|
||||
}
|
||||
cli.println();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
EEPROM_Dump_Command::EEPROM_Dump_Command(CLI & cli) : CLI_Command(cli,
|
||||
PSTR("eeprom_dump"), PSTR("Show EEPROM contents in HEX and ASCII")) { };
|
||||
|
||||
bool EEPROM_Dump_Command::setparams(const char *params) {
|
||||
_offset = 0;
|
||||
return !params && E2END > 0;
|
||||
}
|
||||
|
||||
bool EEPROM_Dump_Command::execute(CLI &cli) {
|
||||
if (_offset == 0) {
|
||||
cli.print_P(PSTR("EEPROM Size: "));
|
||||
cli.print(E2END + 1);
|
||||
cli.print_P(PSTR(" Bytes\n\n"));
|
||||
}
|
||||
uint8_t buffer[16];
|
||||
eeprom_read_block(&buffer, (void *)_offset, sizeof(buffer));
|
||||
cli.print_mem(_offset, buffer, sizeof(buffer));
|
||||
_offset += sizeof(buffer);
|
||||
return _offset <= E2END;
|
||||
}
|
||||
|
||||
|
||||
Reset_Command::Reset_Command(CLI & cli) : CLI_Command(cli,
|
||||
PSTR("reset"), PSTR("Restart microcontroller")) { };
|
||||
|
||||
void(* resetFunc) (void) = 0; //declare reset function @ address 0
|
||||
bool Reset_Command::execute(CLI &cli) {
|
||||
if (_resetting == 2000) resetFunc();
|
||||
if (!_resetting) cli.print(PSTR("resetting...\n\n"));
|
||||
_resetting++;
|
||||
return true;
|
||||
}
|
||||
|
||||
110
src/I2C_Commands.cpp
Normal file
110
src/I2C_Commands.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* CLI_I2C_Commands.cpp - CLI library for Arduino/ESP8266 - I2C Commands implementation
|
||||
*
|
||||
* Version 1.0, latest version, documentation and bugtracker available at:
|
||||
* https://gitlab.lindenaar.net/arduino/CLI
|
||||
*
|
||||
* Copyright (c) 2019 Frederik Lindenaar
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify it under
|
||||
* the terms of version 3 of the GNU General Public License as published by the
|
||||
* Free Software Foundation, or (at your option) a later version of the license.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, visit <http://www.gnu.org/licenses/> to download it.
|
||||
*/
|
||||
|
||||
#include <CLI.h>
|
||||
#include <Wire.h>
|
||||
|
||||
I2C_Scan_Command::I2C_Scan_Command(CLI & cli) : CLI_Command(cli,
|
||||
PSTR("i2c_scan"), PSTR("Scan I2C bus for slave devices")) { };
|
||||
|
||||
bool I2C_Scan_Command::setparams(const char *params) {
|
||||
_address = _found = 0;
|
||||
return !params;
|
||||
}
|
||||
|
||||
bool I2C_Scan_Command::execute(CLI &cli) {
|
||||
if (_address < 127) {
|
||||
if (_address == 0) cli.println(F("Scanning I2C..."));
|
||||
Wire.beginTransmission(_address);
|
||||
uint8_t error = Wire.endTransmission();
|
||||
|
||||
if (error == 0) {
|
||||
cli.print(F("I2C device found at address 0x"));
|
||||
if (_address < 0x10) cli.print("0");
|
||||
cli.println(_address, HEX);
|
||||
_found++;
|
||||
} else if (error == 4) {
|
||||
cli.print(F("Unknown error at address 0x"));
|
||||
if (_address < 0x10) cli.print("0");
|
||||
cli.println(_address, HEX);
|
||||
}
|
||||
_address++;
|
||||
return true;
|
||||
} else {
|
||||
if (_found == 0)
|
||||
cli.print_P(PSTR("No I2C devices found"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
I2C_Dump_Command::I2C_Dump_Command(CLI & cli) : CLI_Command(cli,
|
||||
PSTR("i2c_dump"), PSTR("Display I2C EEPROM/Memory in HEX and ASCII"),
|
||||
PSTR("Usage: i2c_dump 0x<id> <size> [<skip>] [single]\n"
|
||||
"where:\t<id>\tHEX I2C device ID\n"
|
||||
"\t<size>\tsize of memory\n"
|
||||
"\t<skip>\t(optional) start offset\n"
|
||||
"\tsingle\tto enforce 1-byte addressing")) { };
|
||||
|
||||
bool I2C_Dump_Command::setparams(const char *params) {
|
||||
if (params && *(params++) == '0' && *(params++) == 'x') {
|
||||
if ((params = CLI_STR_parse_HEX_byte(params, _address)) && *params == ' ') {
|
||||
if(params = CLI_STR_parseInt(CLI_STR_skipSep(params), (int &)_length)) {
|
||||
_offset = 0;
|
||||
_large = _length > 0xff;
|
||||
if (*params == ' ') {
|
||||
params = CLI_STR_skipSep(params);
|
||||
if(const char *p = CLI_STR_parseInt(params, (int &)_offset))
|
||||
params = CLI_STR_skipSep(p);
|
||||
if (strcmp_P(params, PSTR("single")) == 0) {
|
||||
if (_large) return false;
|
||||
params += 6;
|
||||
}
|
||||
}
|
||||
return *params == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool I2C_Dump_Command::execute(CLI &cli) {
|
||||
uint8_t buffer[16], len = 0;
|
||||
|
||||
Wire.beginTransmission(_address);
|
||||
if (_large) Wire.write((uint8_t)(_offset >> 8)); // MSB
|
||||
Wire.write((uint8_t)(_offset & 0xff)); // LSB
|
||||
if (Wire.endTransmission() != 0) {
|
||||
cli.print(F("No I2C device at 0x"));
|
||||
cli.print(_address, HEX);
|
||||
cli.println();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_offset == 0) cli.println(F("I2C EEPROM/Memory: "));
|
||||
|
||||
Wire.requestFrom(_address, (uint8_t) (_length - _offset < sizeof(buffer)) ? _length - _offset : sizeof(buffer));
|
||||
while (Wire.available() && len < sizeof(buffer)) buffer[len++] = Wire.read();
|
||||
|
||||
cli.print_mem(_offset, buffer, len);
|
||||
_offset += len;
|
||||
return _offset < _length;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user