including tftp based shell and sockets from different project
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
idf_component_register(
|
||||
SRC_DIRS "extern"
|
||||
INCLUDE_DIRS "include" "extern"
|
||||
)
|
||||
+1156
File diff suppressed because it is too large
Load Diff
+312
@@ -0,0 +1,312 @@
|
||||
#ifndef EMBEDDED_CLI_H
|
||||
#define EMBEDDED_CLI_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern "C" {
|
||||
#else
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#endif
|
||||
|
||||
// cstdint is available only since C++11, so use C header
|
||||
#include <stdint.h>
|
||||
|
||||
// used for proper alignment of cli buffer
|
||||
#if UINTPTR_MAX == 0xFFFF
|
||||
#define CLI_UINT uint16_t
|
||||
#elif UINTPTR_MAX == 0xFFFFFFFF
|
||||
#define CLI_UINT uint32_t
|
||||
#elif UINTPTR_MAX == 0xFFFFFFFFFFFFFFFFu
|
||||
#define CLI_UINT uint64_t
|
||||
#else
|
||||
#error unsupported pointer size
|
||||
#endif
|
||||
|
||||
#define CLI_UINT_SIZE (sizeof(CLI_UINT))
|
||||
// convert size in bytes to size in terms of CLI_UINTs (rounded up
|
||||
// if bytes is not divisible by size of single CLI_UINT)
|
||||
#define BYTES_TO_CLI_UINTS(bytes) \
|
||||
(((bytes) + CLI_UINT_SIZE - 1)/CLI_UINT_SIZE)
|
||||
|
||||
typedef struct CliCommand CliCommand;
|
||||
typedef struct CliCommandBinding CliCommandBinding;
|
||||
typedef struct EmbeddedCli EmbeddedCli;
|
||||
typedef struct EmbeddedCliConfig EmbeddedCliConfig;
|
||||
|
||||
|
||||
struct CliCommand {
|
||||
/**
|
||||
* Name of the command.
|
||||
* In command "set led 1 1" "set" is name
|
||||
*/
|
||||
const char *name;
|
||||
|
||||
/**
|
||||
* String of arguments of the command.
|
||||
* In command "set led 1 1" "led 1 1" is string of arguments
|
||||
* Is ended with double 0x00 char
|
||||
* Use tokenize functions to easily get individual tokens
|
||||
*/
|
||||
char *args;
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct to describe binding of command to function and
|
||||
*/
|
||||
struct CliCommandBinding {
|
||||
/**
|
||||
* Name of command to bind. Should not be NULL.
|
||||
*/
|
||||
const char *name;
|
||||
|
||||
/**
|
||||
* Help string that will be displayed when "help <cmd>" is executed.
|
||||
* Can have multiple lines separated with "\r\n"
|
||||
* Can be NULL if no help is provided.
|
||||
*/
|
||||
const char *help;
|
||||
|
||||
/**
|
||||
* Flag to perform tokenization before calling binding function.
|
||||
*/
|
||||
bool tokenizeArgs;
|
||||
|
||||
/**
|
||||
* Pointer to any specific app context that is required for this binding.
|
||||
* It will be provided in binding callback.
|
||||
*/
|
||||
void *context;
|
||||
|
||||
/**
|
||||
* Binding function for when command is received.
|
||||
* If null, default callback (onCommand) will be called.
|
||||
* @param cli - pointer to cli that is calling this binding
|
||||
* @param args - string of args (if tokenizeArgs is false) or tokens otherwise
|
||||
* @param context
|
||||
*/
|
||||
void (*binding)(EmbeddedCli *cli, char *args, void *context);
|
||||
};
|
||||
|
||||
struct EmbeddedCli {
|
||||
/**
|
||||
* Should write char to connection
|
||||
* @param cli - pointer to cli that executed this function
|
||||
* @param c - actual character to write
|
||||
*/
|
||||
void (*writeChar)(EmbeddedCli *cli, char c);
|
||||
|
||||
/**
|
||||
* Called when command is received and command not found in list of
|
||||
* command bindings (or binding function is null).
|
||||
* @param cli - pointer to cli that executed this function
|
||||
* @param command - pointer to received command
|
||||
*/
|
||||
void (*onCommand)(EmbeddedCli *cli, CliCommand *command);
|
||||
|
||||
/**
|
||||
* Can be used for any application context
|
||||
*/
|
||||
void *appContext;
|
||||
|
||||
/**
|
||||
* Pointer to actual implementation, do not use.
|
||||
*/
|
||||
void *_impl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration to create CLI
|
||||
*/
|
||||
struct EmbeddedCliConfig {
|
||||
/**
|
||||
* Invitation string. Is printed at the beginning of each line with user
|
||||
* input
|
||||
*/
|
||||
const char *invitation;
|
||||
|
||||
/**
|
||||
* Size of buffer that is used to store characters until they're processed
|
||||
*/
|
||||
uint16_t rxBufferSize;
|
||||
|
||||
/**
|
||||
* Size of buffer that is used to store current input that is not yet
|
||||
* sended as command (return not pressed yet)
|
||||
*/
|
||||
uint16_t cmdBufferSize;
|
||||
|
||||
/**
|
||||
* Size of buffer that is used to store previously entered commands
|
||||
* Only unique commands are stored in buffer. If buffer is smaller than
|
||||
* entered command (including arguments), command is discarded from history
|
||||
*/
|
||||
uint16_t historyBufferSize;
|
||||
|
||||
/**
|
||||
* Maximum amount of bindings that can be added via addBinding function.
|
||||
* Cli increases takes extra bindings for internal commands:
|
||||
* - help
|
||||
*/
|
||||
uint16_t maxBindingCount;
|
||||
|
||||
/**
|
||||
* Buffer to use for cli and all internal structures. If NULL, memory will
|
||||
* be allocated dynamically. Otherwise this buffer is used and no
|
||||
* allocations are made
|
||||
*/
|
||||
CLI_UINT *cliBuffer;
|
||||
|
||||
/**
|
||||
* Size of buffer for cli and internal structures (in bytes).
|
||||
*/
|
||||
uint16_t cliBufferSize;
|
||||
|
||||
/**
|
||||
* Whether autocompletion should be enabled.
|
||||
* If false, autocompletion is disabled but you still can use 'tab' to
|
||||
* complete current command manually.
|
||||
*/
|
||||
bool enableAutoComplete;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns pointer to default configuration for cli creation. It is safe to
|
||||
* modify it and then send to embeddedCliNew().
|
||||
* Returned structure is always the same so do not free and try to use it
|
||||
* immediately.
|
||||
* Default values:
|
||||
* <ul>
|
||||
* <li>rxBufferSize = 64</li>
|
||||
* <li>cmdBufferSize = 64</li>
|
||||
* <li>historyBufferSize = 128</li>
|
||||
* <li>cliBuffer = NULL (use dynamic allocation)</li>
|
||||
* <li>cliBufferSize = 0</li>
|
||||
* <li>maxBindingCount = 8</li>
|
||||
* <li>enableAutoComplete = true</li>
|
||||
* </ul>
|
||||
* @return configuration for cli creation
|
||||
*/
|
||||
EmbeddedCliConfig *embeddedCliDefaultConfig(void);
|
||||
|
||||
/**
|
||||
* Returns how many space in config buffer is required for cli creation
|
||||
* If you provide buffer with less space, embeddedCliNew will return NULL
|
||||
* This amount will always be divisible by CLI_UINT_SIZE so allocated buffer
|
||||
* and internal structures can be properly aligned
|
||||
* @param config
|
||||
* @return
|
||||
*/
|
||||
uint16_t embeddedCliRequiredSize(EmbeddedCliConfig *config);
|
||||
|
||||
/**
|
||||
* Create new CLI.
|
||||
* Memory is allocated dynamically if cliBuffer in config is NULL.
|
||||
* After CLI is created, override function pointers to start using it
|
||||
* @param config - config for cli creation
|
||||
* @return pointer to created CLI
|
||||
*/
|
||||
EmbeddedCli *embeddedCliNew(EmbeddedCliConfig *config);
|
||||
|
||||
/**
|
||||
* Same as calling embeddedCliNew with default config.
|
||||
* @return
|
||||
*/
|
||||
EmbeddedCli *embeddedCliNewDefault(void);
|
||||
|
||||
/**
|
||||
* Receive character and put it to internal buffer
|
||||
* Actual processing is done inside embeddedCliProcess
|
||||
* You can call this function from something like interrupt service routine,
|
||||
* just make sure that you call it only from single place. Otherwise input
|
||||
* might get corrupted
|
||||
* @param cli
|
||||
* @param c - received char
|
||||
*/
|
||||
void embeddedCliReceiveChar(EmbeddedCli *cli, char c);
|
||||
|
||||
/**
|
||||
* Process rx/tx buffers. Command callbacks are called from here
|
||||
* @param cli
|
||||
*/
|
||||
void embeddedCliProcess(EmbeddedCli *cli);
|
||||
|
||||
/**
|
||||
* Add specified binding to list of bindings. If list is already full, binding
|
||||
* is not added and false is returned
|
||||
* @param cli
|
||||
* @param binding
|
||||
* @return true if binding was added, false otherwise
|
||||
*/
|
||||
bool embeddedCliAddBinding(EmbeddedCli *cli, CliCommandBinding binding);
|
||||
|
||||
/**
|
||||
* Print specified string and account for currently entered but not submitted
|
||||
* command.
|
||||
* Current command is deleted, provided string is printed (with new line) after
|
||||
* that current command is printed again, so user can continue typing it.
|
||||
* @param cli
|
||||
* @param string
|
||||
*/
|
||||
void embeddedCliPrint(EmbeddedCli *cli, const char *string);
|
||||
|
||||
/**
|
||||
* Free allocated for cli memory
|
||||
* @param cli
|
||||
*/
|
||||
void embeddedCliFree(EmbeddedCli *cli);
|
||||
|
||||
/**
|
||||
* Perform tokenization of arguments string. Original string is modified and
|
||||
* should not be used directly (only inside other token functions).
|
||||
* Individual tokens are separated by single 0x00 char, double 0x00 is put at
|
||||
* the end of token list. After calling this function, you can use other
|
||||
* token functions to get individual tokens and token count.
|
||||
*
|
||||
* Important: Call this function only once. Otherwise information will be lost if
|
||||
* more than one token existed
|
||||
* @param args - string to tokenize (must have extra writable char after 0x00)
|
||||
* @return
|
||||
*/
|
||||
void embeddedCliTokenizeArgs(char *args);
|
||||
|
||||
/**
|
||||
* Return specific token from tokenized string
|
||||
* @param tokenizedStr
|
||||
* @param pos (counted from 1)
|
||||
* @return token
|
||||
*/
|
||||
const char *embeddedCliGetToken(const char *tokenizedStr, uint16_t pos);
|
||||
|
||||
/**
|
||||
* Same as embeddedCliGetToken but works on non-const buffer
|
||||
* @param tokenizedStr
|
||||
* @param pos (counted from 1)
|
||||
* @return token
|
||||
*/
|
||||
char *embeddedCliGetTokenVariable(char *tokenizedStr, uint16_t pos);
|
||||
|
||||
/**
|
||||
* Find token in provided tokens string and return its position (counted from 1)
|
||||
* If no such token is found - 0 is returned.
|
||||
* @param tokenizedStr
|
||||
* @param token - token to find
|
||||
* @return position (increased by 1) or zero if no such token found
|
||||
*/
|
||||
uint16_t embeddedCliFindToken(const char *tokenizedStr, const char *token);
|
||||
|
||||
/**
|
||||
* Return number of tokens in tokenized string
|
||||
* @param tokenizedStr
|
||||
* @return number of tokens
|
||||
*/
|
||||
uint16_t embeddedCliGetTokenCount(const char *tokenizedStr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif //EMBEDDED_CLI_H
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Sviatoslav Kokurin (funbiscuit)
|
||||
|
||||
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.
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
# Embedded CLI
|
||||
|
||||
Implementation is taken from `funbiscuit` @ [github](https://github.com/funbiscuit/embedded-cli)
|
||||
|
||||
- Only source and header where integrated.
|
||||
- Full project is included in `external/embedded-cli`
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* @file cliWrapper.hpp
|
||||
* @author Gustice
|
||||
* @brief Wrapping Command-Line-Interfaces with custom endpoints
|
||||
* @details Command-Line-Interface is based on the implementation of
|
||||
* https://github.com/funbiscuit/embedded-cli
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "embedded_cli.h"
|
||||
#include <esp_log.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include "utils.hpp"
|
||||
|
||||
/* Module configuration */
|
||||
static constexpr int CLI_RX_BUFFER_SIZE = 64;
|
||||
static constexpr int CLI_CMD_BUFFER_SIZE = 64; // to also accept URLs for Updates
|
||||
static constexpr int CLI_HISTORY_SIZE = 16;
|
||||
static constexpr int CLI_BINDING_COUNT = 8;
|
||||
static constexpr std::string_view CliWelcomeString{
|
||||
"** Smart-DMX-Bridge **\n"
|
||||
" send 'help' for help-page\n"
|
||||
" NOTE: Syslog-messages are sent to client of this session\n"};
|
||||
|
||||
/**
|
||||
* @brief Wrapper for c-implementation of CLI
|
||||
*/
|
||||
class Cli {
|
||||
public:
|
||||
/// @brief Type for callback arguments
|
||||
using CArgs = std::vector<std::string> &;
|
||||
/// @brief Type for bind callback
|
||||
using BindCb = std::function<void(CArgs)>;
|
||||
/// @brief Type for command callback
|
||||
using CommandCb = std::function<void(std::string, CArgs)>;
|
||||
|
||||
/// @brief Parameter structure for command-binding
|
||||
struct Binding {
|
||||
std::string_view name;
|
||||
std::string_view help_output;
|
||||
BindCb callback;
|
||||
};
|
||||
|
||||
/// @brief Constructor
|
||||
/// @param port Reference to serial port
|
||||
/// @param cmd command callback
|
||||
Cli(CharStream &port, CommandCb cmd)
|
||||
: _port(port), _commandCb(cmd) {
|
||||
EmbeddedCliConfig *config = embeddedCliDefaultConfig();
|
||||
// NOTE: Note setting cliBuffer allows Cli to allocate needed buffer in correct size
|
||||
// config->cliBuffer = cliBuffer;
|
||||
// config->cliBufferSize = CLI_BUFFER_SIZE;
|
||||
config->rxBufferSize = CLI_RX_BUFFER_SIZE;
|
||||
config->cmdBufferSize = CLI_CMD_BUFFER_SIZE;
|
||||
config->historyBufferSize = CLI_HISTORY_SIZE;
|
||||
config->maxBindingCount = CLI_BINDING_COUNT;
|
||||
cli = embeddedCliNew(config);
|
||||
|
||||
if (cli == NULL) {
|
||||
ESP_LOGE("CLI", "Cli was not created, requires %d bytes. Check sizes!",
|
||||
embeddedCliRequiredSize(config));
|
||||
return;
|
||||
}
|
||||
cli->onCommand = genericCallback;
|
||||
cli->writeChar = writeToken;
|
||||
// appContext is a user-end variable and is bound to current instance
|
||||
cli->appContext = this;
|
||||
}
|
||||
|
||||
/// @brief Destructor
|
||||
~Cli() {
|
||||
embeddedCliFree(cli);
|
||||
}
|
||||
|
||||
/// @brief Create command binding
|
||||
bool addBinding(Binding bind) {
|
||||
BindCb *cb = new BindCb{bind.callback};
|
||||
|
||||
CliCommandBinding cBinding{.name = bind.name.begin(),
|
||||
.help = bind.help_output.begin(),
|
||||
.tokenizeArgs = true,
|
||||
// NOTE: this hard reference only works because we only provide
|
||||
// an add-function without remove
|
||||
.context = (void *)(cb),
|
||||
.binding = boundCallback};
|
||||
return embeddedCliAddBinding(cli, cBinding);
|
||||
}
|
||||
|
||||
/// @brief Static method to generate c-compatible function-pointer for bound-command-callback
|
||||
/// @details - receives and wraps arguments in string,
|
||||
/// - determines object according to appContext
|
||||
/// - calls appropriate method of appropriate object
|
||||
static void boundCallback(EmbeddedCli *cli, char *args, void *context) {
|
||||
if (context == nullptr) {
|
||||
return;
|
||||
ESP_LOGE("CLI", "No context in callback available");
|
||||
}
|
||||
ESP_LOGD("CLI", "Received command:");
|
||||
|
||||
BindCb &cb = *((BindCb *)context);
|
||||
uint len = embeddedCliGetTokenCount(args);
|
||||
std::vector<std::string> sArgs;
|
||||
while (len-- > 0) {
|
||||
const char *const arg = embeddedCliGetToken(args, 1);
|
||||
ESP_LOGD("CLI", " arg: %s", arg);
|
||||
sArgs.emplace_back(arg);
|
||||
// shift position to end of this element to save time
|
||||
args += sArgs.back().size() + 1; // needs also to be shifted by null-delimiter
|
||||
}
|
||||
cb(sArgs);
|
||||
}
|
||||
|
||||
/// @brief Static method to generate c-compatible function-pointer for command-callback
|
||||
/// @details - receives and wraps arguments in string,
|
||||
/// - determines object according to appContext
|
||||
/// - calls command-callback of appropriate object
|
||||
static void genericCallback(EmbeddedCli *cli, CliCommand *command) {
|
||||
std::string name(command->name);
|
||||
ESP_LOGI("CLI", "Received generic command: %s", name.c_str());
|
||||
|
||||
embeddedCliTokenizeArgs(command->args);
|
||||
std::vector<std::string> sArgs;
|
||||
for (int i = 1; i <= embeddedCliGetTokenCount(command->args); ++i) {
|
||||
sArgs.emplace_back(embeddedCliGetToken(command->args, i));
|
||||
ESP_LOGI("CLI", " arg %d : %s", i, sArgs.back().c_str());
|
||||
}
|
||||
auto &commandCb = static_cast<Cli *>(cli->appContext)->_commandCb;
|
||||
commandCb(name, sArgs);
|
||||
}
|
||||
|
||||
/// @brief Process buffer and trigger commands
|
||||
void process() {
|
||||
auto r = _port.read();
|
||||
for (auto &&c : r) {
|
||||
embeddedCliReceiveChar(cli, c);
|
||||
}
|
||||
embeddedCliProcess(cli);
|
||||
}
|
||||
|
||||
/// @brief publicly exposed write method
|
||||
void write(std::string output) {
|
||||
_port.write(output);
|
||||
}
|
||||
|
||||
private:
|
||||
/// @brief Reference to hardware port
|
||||
CharStream &_port;
|
||||
/// @brief Callback for generic command
|
||||
CommandCb _commandCb;
|
||||
EmbeddedCli *cli = nullptr;
|
||||
|
||||
/// @brief Write callback
|
||||
static void writeToken(EmbeddedCli *embeddedCli, char c) {
|
||||
static_cast<Cli *>(embeddedCli->appContext)->_port.write(c);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user