Initial CLI implementation
This commit is contained in:
parent
0e1a46c320
commit
7ca4c3b631
|
@ -3,13 +3,16 @@ set(SOURCES
|
|||
"usb-cdc.c"
|
||||
"nvs.c"
|
||||
"led.c"
|
||||
"uart.c"
|
||||
"cli-uart.c"
|
||||
"i2c.c"
|
||||
"delay.c"
|
||||
"network.c"
|
||||
"network-http.c"
|
||||
"network-uart.c"
|
||||
"network-gdb.c"
|
||||
"cli.c"
|
||||
"cli-uart.c"
|
||||
"cli-commands.c"
|
||||
)
|
||||
|
||||
set(INCLUDES
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "cli.h"
|
||||
#include "cli-commands.h"
|
||||
#include "helpers.h"
|
||||
|
||||
void cli_help(Cli* cli, mstring_t* args);
|
||||
|
||||
const CliItem cli_items[] = {
|
||||
{
|
||||
.name = "help",
|
||||
.callback = cli_help,
|
||||
},
|
||||
};
|
||||
|
||||
size_t cli_items_count = COUNT_OF(cli_items);
|
||||
|
||||
void cli_help(Cli* cli, mstring_t* args) {
|
||||
for(size_t i = 0; i < cli_items_count; i++) {
|
||||
cli_write_str(cli, cli_items[i].name);
|
||||
cli_write_eol(cli);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* @file cli-commands.h
|
||||
* @author Sergey Gavrilov (who.just.the.doctor@gmail.com)
|
||||
* @version 1.0
|
||||
* @date 2021-12-01
|
||||
*
|
||||
* Cli commands list
|
||||
*/
|
||||
#pragma once
|
||||
#include <m-string.h>
|
||||
|
||||
typedef void (*CliCallback)(Cli* cli, mstring_t* args);
|
||||
|
||||
struct CliItem {
|
||||
const char* name;
|
||||
CliCallback callback;
|
||||
};
|
||||
|
||||
extern const CliItem cli_items[];
|
||||
extern size_t cli_items_count;
|
|
@ -0,0 +1,81 @@
|
|||
#include <driver/uart.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <string.h>
|
||||
#include "cli.h"
|
||||
|
||||
#define CLI_UART_PORT_NUM UART_NUM_1
|
||||
#define CLI_UART_TXD_PIN (17)
|
||||
#define CLI_UART_RXD_PIN (18)
|
||||
#define CLI_UART_RTS_PIN (UART_PIN_NO_CHANGE)
|
||||
#define CLI_UART_CTS_PIN (UART_PIN_NO_CHANGE)
|
||||
#define CLI_UART_BAUD_RATE (115200)
|
||||
#define CLI_UART_BUF_SIZE (128)
|
||||
|
||||
static Cli* cli_uart;
|
||||
static QueueHandle_t cli_uart_queue;
|
||||
static void cli_uart_write(const uint8_t* data, size_t data_size, void* context);
|
||||
|
||||
static void cli_uart_rx_task(void* pvParameters) {
|
||||
uart_event_t event;
|
||||
uint8_t* rx_buffer = (uint8_t*)malloc(CLI_UART_BUF_SIZE);
|
||||
int received = 0;
|
||||
|
||||
for(;;) {
|
||||
//Waiting for UART event.
|
||||
if(xQueueReceive(cli_uart_queue, (void*)&event, (portTickType)portMAX_DELAY)) {
|
||||
bzero(rx_buffer, CLI_UART_BUF_SIZE);
|
||||
switch(event.type) {
|
||||
case UART_DATA:
|
||||
received =
|
||||
uart_read_bytes(CLI_UART_PORT_NUM, rx_buffer, event.size, portMAX_DELAY);
|
||||
for(int i = 0; i < received; i++) {
|
||||
cli_handle_char(cli_uart, rx_buffer[i]);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(rx_buffer);
|
||||
rx_buffer = NULL;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void cli_uart_init() {
|
||||
cli_uart = cli_init();
|
||||
cli_set_write_cb(cli_uart, cli_uart_write);
|
||||
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = CLI_UART_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_APB,
|
||||
};
|
||||
int intr_alloc_flags = 0;
|
||||
|
||||
#if CONFIG_UART_ISR_IN_IRAM
|
||||
intr_alloc_flags = ESP_INTR_FLAG_IRAM;
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(uart_driver_install(
|
||||
CLI_UART_PORT_NUM,
|
||||
CLI_UART_BUF_SIZE * 2,
|
||||
CLI_UART_BUF_SIZE * 2,
|
||||
10,
|
||||
&cli_uart_queue,
|
||||
intr_alloc_flags));
|
||||
ESP_ERROR_CHECK(uart_param_config(CLI_UART_PORT_NUM, &uart_config));
|
||||
ESP_ERROR_CHECK(uart_set_pin(
|
||||
CLI_UART_PORT_NUM, CLI_UART_TXD_PIN, CLI_UART_RXD_PIN, CLI_UART_RTS_PIN, CLI_UART_CTS_PIN));
|
||||
|
||||
xTaskCreate(cli_uart_rx_task, "cli_uart_rx", 4096, NULL, 5, NULL);
|
||||
}
|
||||
|
||||
static void cli_uart_write(const uint8_t* data, size_t data_size, void* context) {
|
||||
uart_write_bytes(CLI_UART_PORT_NUM, data, data_size);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
void cli_uart_init();
|
|
@ -0,0 +1,192 @@
|
|||
#include <m-string.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "cli.h"
|
||||
#include "delay.h"
|
||||
#include "helpers.h"
|
||||
#include "cli-commands.h"
|
||||
#include <esp_log.h>
|
||||
|
||||
typedef enum {
|
||||
CliSymbolAsciiSOH = 0x01,
|
||||
CliSymbolAsciiETX = 0x03,
|
||||
CliSymbolAsciiEOT = 0x04,
|
||||
CliSymbolAsciiBell = 0x07,
|
||||
CliSymbolAsciiBackspace = 0x08,
|
||||
CliSymbolAsciiTab = 0x09,
|
||||
CliSymbolAsciiCR = 0x0D,
|
||||
CliSymbolAsciiEsc = 0x1B,
|
||||
CliSymbolAsciiUS = 0x1F,
|
||||
CliSymbolAsciiSpace = 0x20,
|
||||
CliSymbolAsciiDel = 0x7F,
|
||||
} CliSymbols;
|
||||
|
||||
struct Cli {
|
||||
mstring_t* line;
|
||||
size_t cursor_position;
|
||||
|
||||
void* context;
|
||||
CliWrite write_cb;
|
||||
CliFlush flush_cb;
|
||||
};
|
||||
|
||||
Cli* cli_init(void) {
|
||||
Cli* cli = malloc(sizeof(Cli));
|
||||
cli->line = mstring_alloc();
|
||||
cli->context = NULL;
|
||||
cli->write_cb = NULL;
|
||||
cli->flush_cb = NULL;
|
||||
|
||||
return cli;
|
||||
}
|
||||
|
||||
void cli_reset(Cli* cli) {
|
||||
mstring_reset(cli->line);
|
||||
cli->cursor_position = 0;
|
||||
}
|
||||
|
||||
void cli_set_context(Cli* cli, void* context) {
|
||||
cli->context = context;
|
||||
}
|
||||
|
||||
void cli_set_write_cb(Cli* cli, CliWrite write_cb) {
|
||||
cli->write_cb = write_cb;
|
||||
}
|
||||
|
||||
void cli_set_flush_cb(Cli* cli, CliFlush flush_cb) {
|
||||
cli->flush_cb = flush_cb;
|
||||
}
|
||||
|
||||
void cli_write(Cli* cli, const uint8_t* data, size_t data_size) {
|
||||
ESP_LOGI("cli", "write");
|
||||
if(cli->write_cb != NULL) {
|
||||
cli->write_cb(data, data_size, cli->context);
|
||||
}
|
||||
}
|
||||
|
||||
void cli_flush(Cli* cli) {
|
||||
ESP_LOGI("cli", "flush");
|
||||
if(cli->flush_cb != NULL) {
|
||||
cli->flush_cb(cli->context);
|
||||
}
|
||||
}
|
||||
|
||||
void cli_write_str(Cli* cli, const char* str) {
|
||||
cli_write(cli, (const uint8_t*)str, strlen(str));
|
||||
}
|
||||
|
||||
void cli_write_char(Cli* cli, uint8_t c) {
|
||||
cli_write(cli, &c, 1);
|
||||
}
|
||||
|
||||
void cli_write_eol(Cli* cli) {
|
||||
cli_write_str(cli, "\r\n");
|
||||
}
|
||||
|
||||
static void cli_write_motd(Cli* cli) {
|
||||
cli_write_str(cli, "Hello!\r\nThis is MOTD\r\n");
|
||||
}
|
||||
|
||||
static void cli_write_prompt(Cli* cli) {
|
||||
cli_write_str(cli, "[esp]>");
|
||||
}
|
||||
|
||||
static const CliItem* cli_search_item(Cli* cli, const mstring_t* command) {
|
||||
const CliItem* item = NULL;
|
||||
|
||||
for(size_t i = 0; i < cli_items_count; i++) {
|
||||
if(mstring_cmp_cstr(command, cli_items[i].name) == 0) {
|
||||
item = &cli_items[i];
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static bool cli_handle_enter(Cli* cli) {
|
||||
mstring_t* command = mstring_alloc();
|
||||
mstring_t* args = mstring_alloc();
|
||||
bool result = false;
|
||||
const CliItem* item = NULL;
|
||||
|
||||
mstring_strim(cli->line, " \n\r\t");
|
||||
|
||||
size_t ws = mstring_search_char(cli->line, ' ', 0);
|
||||
if(ws == STRING_FAILURE) {
|
||||
mstring_set(command, mstring_get_cstr(cli->line));
|
||||
} else {
|
||||
mstring_set_n(command, cli->line, 0, ws);
|
||||
mstring_set_n(args, cli->line, ws, mstring_size(cli->line));
|
||||
mstring_strim(args, " \n\r\t");
|
||||
}
|
||||
|
||||
item = cli_search_item(cli, command);
|
||||
if(item != NULL) {
|
||||
item->callback(cli, args);
|
||||
} else {
|
||||
cli_write_str(cli, "Not found");
|
||||
}
|
||||
|
||||
mstring_free(command);
|
||||
mstring_free(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void cli_handle_backspace(Cli* cli) {
|
||||
if(mstring_size(cli->line) > 0) {
|
||||
// Other side
|
||||
cli_write_str(cli, "\e[D\e[1P");
|
||||
cli_flush(cli);
|
||||
// Our side
|
||||
mstring_set_strn(cli->line, mstring_get_cstr(cli->line), mstring_size(cli->line) - 1);
|
||||
cli->cursor_position--;
|
||||
} else {
|
||||
cli_write_char(cli, CliSymbolAsciiBell);
|
||||
}
|
||||
}
|
||||
|
||||
void cli_handle_char(Cli* cli, uint8_t c) {
|
||||
ESP_LOGI("cli", "%c", c);
|
||||
|
||||
switch(c) {
|
||||
case CliSymbolAsciiCR:
|
||||
cli_write_eol(cli);
|
||||
cli_handle_enter(cli);
|
||||
cli_reset(cli);
|
||||
cli_write_eol(cli);
|
||||
cli_write_prompt(cli);
|
||||
break;
|
||||
case CliSymbolAsciiDel:
|
||||
case CliSymbolAsciiBackspace:
|
||||
cli_handle_backspace(cli);
|
||||
break;
|
||||
case CliSymbolAsciiSOH:
|
||||
delay(33);
|
||||
cli_write_motd(cli);
|
||||
cli_write_eol(cli);
|
||||
cli_write_prompt(cli);
|
||||
break;
|
||||
case CliSymbolAsciiETX:
|
||||
cli_reset(cli);
|
||||
cli_write_eol(cli);
|
||||
cli_write_prompt(cli);
|
||||
break;
|
||||
case CliSymbolAsciiEOT:
|
||||
cli_reset(cli);
|
||||
break;
|
||||
case ' ' ... '~':
|
||||
if(cli->cursor_position == mstring_size(cli->line)) {
|
||||
mstring_push_back(cli->line, c);
|
||||
cli_write_char(cli, c);
|
||||
} else {
|
||||
mstring_push_back(cli->line, c);
|
||||
cli_write_str(cli, "\e[4h");
|
||||
cli_write_char(cli, c);
|
||||
cli_write_str(cli, "\e[4l");
|
||||
cli_flush(cli);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* @file cli.h
|
||||
* @author Sergey Gavrilov (who.just.the.doctor@gmail.com)
|
||||
* @version 1.0
|
||||
* @date 2021-12-01
|
||||
*
|
||||
* Cli commands
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct Cli Cli;
|
||||
typedef struct CliItem CliItem;
|
||||
|
||||
typedef void (*CliWrite)(const uint8_t* data, size_t data_size, void* context);
|
||||
typedef void (*CliFlush)(void* context);
|
||||
|
||||
Cli* cli_init(void);
|
||||
|
||||
void cli_set_context(Cli* cli, void* context);
|
||||
|
||||
void cli_set_write_cb(Cli* cli, CliWrite write_cb);
|
||||
|
||||
void cli_set_flush_cb(Cli* cli, CliFlush flush_cb);
|
||||
|
||||
void cli_write(Cli* cli, const uint8_t* data, size_t data_size);
|
||||
|
||||
void cli_flush(Cli* cli);
|
||||
|
||||
void cli_write_str(Cli* cli, const char* str);
|
||||
|
||||
void cli_write_char(Cli* cli, uint8_t c);
|
||||
|
||||
void cli_handle_char(Cli* cli, uint8_t c);
|
||||
|
||||
void cli_write_eol(Cli* cli);
|
|
@ -8,7 +8,7 @@
|
|||
#include "nvs.h"
|
||||
#include "gdb_main.h"
|
||||
#include "led.h"
|
||||
#include "uart.h"
|
||||
#include "cli-uart.h"
|
||||
#include "i2c.h"
|
||||
#include "network.h"
|
||||
#include "network-http.h"
|
||||
|
@ -65,10 +65,9 @@ void app_main(void) {
|
|||
|
||||
usb_cdc_init();
|
||||
|
||||
// TODO uart and i2c share the same pins, need switching mechanics
|
||||
// uart_init();
|
||||
// uart_print("Uart inited");
|
||||
cli_uart_init();
|
||||
|
||||
// TODO uart and i2c share the same pins, need switching mechanics
|
||||
// i2c_init();
|
||||
// i2c_scan();
|
||||
|
||||
|
|
|
@ -361,11 +361,11 @@ static esp_err_t wifi_set_credenitals_handler(httpd_req_t* req) {
|
|||
goto err_fail;
|
||||
}
|
||||
|
||||
if(mstring_length(ap_pass) < 8) {
|
||||
if(mstring_size(ap_pass) < 8) {
|
||||
error_text = JSON_ERROR("too short value in [pass]");
|
||||
goto err_fail;
|
||||
}
|
||||
if(mstring_length(ap_ssid) < 1) {
|
||||
if(mstring_size(ap_ssid) < 1) {
|
||||
error_text = JSON_ERROR("too short value in [ssid]");
|
||||
goto err_fail;
|
||||
}
|
||||
|
|
|
@ -99,16 +99,16 @@ static void network_start_ap(mstring_t* ap_ssid, mstring_t* ap_pass) {
|
|||
memcpy(
|
||||
&wifi_config.ap.ssid,
|
||||
mstring_get_cstr(ap_ssid),
|
||||
min(sizeof(wifi_config.ap.ssid), mstring_length(ap_ssid)));
|
||||
min(sizeof(wifi_config.ap.ssid), mstring_size(ap_ssid)));
|
||||
|
||||
memcpy(
|
||||
&wifi_config.ap.password,
|
||||
mstring_get_cstr(ap_pass),
|
||||
min(sizeof(wifi_config.ap.password), mstring_length(ap_pass)));
|
||||
min(sizeof(wifi_config.ap.password), mstring_size(ap_pass)));
|
||||
|
||||
wifi_config.ap.ssid_len = mstring_length(ap_ssid);
|
||||
wifi_config.ap.ssid_len = mstring_size(ap_ssid);
|
||||
|
||||
if(mstring_length(ap_pass) == 0) {
|
||||
if(mstring_size(ap_pass) == 0) {
|
||||
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
|
||||
}
|
||||
|
||||
|
@ -145,11 +145,11 @@ static bool network_connect_ap(mstring_t* ap_ssid, mstring_t* ap_pass) {
|
|||
memcpy(
|
||||
&wifi_config.sta.ssid,
|
||||
mstring_get_cstr(ap_ssid),
|
||||
min(sizeof(wifi_config.sta.ssid), mstring_length(ap_ssid)));
|
||||
min(sizeof(wifi_config.sta.ssid), mstring_size(ap_ssid)));
|
||||
memcpy(
|
||||
&wifi_config.sta.password,
|
||||
mstring_get_cstr(ap_pass),
|
||||
min(sizeof(wifi_config.sta.password), mstring_length(ap_pass)));
|
||||
min(sizeof(wifi_config.sta.password), mstring_size(ap_pass)));
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
|
||||
|
@ -226,7 +226,7 @@ WIFIMode network_init(void) {
|
|||
nvs_save_string("ap_pass", ap_pass);
|
||||
}
|
||||
|
||||
if(mstring_length(ap_pass) < 8) {
|
||||
if(mstring_size(ap_pass) < 8) {
|
||||
ESP_LOGW(TAG, "too short [ap_pass]");
|
||||
mstring_set(ap_ssid, ESP_WIFI_SSID);
|
||||
nvs_save_string("ap_ssid", ap_ssid);
|
||||
|
@ -236,7 +236,7 @@ WIFIMode network_init(void) {
|
|||
nvs_save_string("ap_mode", ap_mode);
|
||||
}
|
||||
|
||||
if(mstring_length(ap_ssid) < 1 || mstring_length(ap_ssid) > 32) {
|
||||
if(mstring_size(ap_ssid) < 1 || mstring_size(ap_ssid) > 32) {
|
||||
ESP_LOGW(TAG, "too short or too long [ap_ssid]");
|
||||
mstring_set(ap_ssid, ESP_WIFI_SSID);
|
||||
nvs_save_string("ap_ssid", ap_ssid);
|
||||
|
|
37
main/uart.c
37
main/uart.c
|
@ -1,37 +0,0 @@
|
|||
#include <driver/uart.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define UART_PORT_NUM UART_NUM_1
|
||||
#define UART_TXD_PIN (17)
|
||||
#define UART_RXD_PIN (18)
|
||||
#define UART_RTS_PIN (UART_PIN_NO_CHANGE)
|
||||
#define UART_CTS_PIN (UART_PIN_NO_CHANGE)
|
||||
#define UART_BAUD_RATE (115200)
|
||||
#define UART_BUF_SIZE (1024)
|
||||
|
||||
void uart_init() {
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = UART_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_APB,
|
||||
};
|
||||
int intr_alloc_flags = 0;
|
||||
|
||||
#if CONFIG_UART_ISR_IN_IRAM
|
||||
intr_alloc_flags = ESP_INTR_FLAG_IRAM;
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(
|
||||
uart_driver_install(UART_PORT_NUM, UART_BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));
|
||||
ESP_ERROR_CHECK(uart_param_config(UART_PORT_NUM, &uart_config));
|
||||
ESP_ERROR_CHECK(
|
||||
uart_set_pin(UART_PORT_NUM, UART_TXD_PIN, UART_RXD_PIN, UART_RTS_PIN, UART_CTS_PIN));
|
||||
}
|
||||
|
||||
void uart_print(const char* str) {
|
||||
uart_write_bytes(UART_PORT_NUM, str, strlen(str));
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
void uart_init();
|
||||
void uart_print(const char* str);
|
Loading…
Reference in New Issue