Initial CLI implementation

This commit is contained in:
DrZlo13 2021-12-01 14:15:45 +10:00
parent 0e1a46c320
commit 7ca4c3b631
12 changed files with 372 additions and 56 deletions

View File

@ -3,13 +3,16 @@ set(SOURCES
"usb-cdc.c" "usb-cdc.c"
"nvs.c" "nvs.c"
"led.c" "led.c"
"uart.c" "cli-uart.c"
"i2c.c" "i2c.c"
"delay.c" "delay.c"
"network.c" "network.c"
"network-http.c" "network-http.c"
"network-uart.c" "network-uart.c"
"network-gdb.c" "network-gdb.c"
"cli.c"
"cli-uart.c"
"cli-commands.c"
) )
set(INCLUDES set(INCLUDES

23
main/cli-commands.c Normal file
View File

@ -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);
}
}

20
main/cli-commands.h Normal file
View File

@ -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;

81
main/cli-uart.c Normal file
View File

@ -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);
}

3
main/cli-uart.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
void cli_uart_init();

192
main/cli.c Normal file
View File

@ -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;
}
}

36
main/cli.h Normal file
View File

@ -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);

View File

@ -8,7 +8,7 @@
#include "nvs.h" #include "nvs.h"
#include "gdb_main.h" #include "gdb_main.h"
#include "led.h" #include "led.h"
#include "uart.h" #include "cli-uart.h"
#include "i2c.h" #include "i2c.h"
#include "network.h" #include "network.h"
#include "network-http.h" #include "network-http.h"
@ -65,10 +65,9 @@ void app_main(void) {
usb_cdc_init(); usb_cdc_init();
// TODO uart and i2c share the same pins, need switching mechanics cli_uart_init();
// uart_init();
// uart_print("Uart inited");
// TODO uart and i2c share the same pins, need switching mechanics
// i2c_init(); // i2c_init();
// i2c_scan(); // i2c_scan();

View File

@ -361,11 +361,11 @@ static esp_err_t wifi_set_credenitals_handler(httpd_req_t* req) {
goto err_fail; goto err_fail;
} }
if(mstring_length(ap_pass) < 8) { if(mstring_size(ap_pass) < 8) {
error_text = JSON_ERROR("too short value in [pass]"); error_text = JSON_ERROR("too short value in [pass]");
goto err_fail; goto err_fail;
} }
if(mstring_length(ap_ssid) < 1) { if(mstring_size(ap_ssid) < 1) {
error_text = JSON_ERROR("too short value in [ssid]"); error_text = JSON_ERROR("too short value in [ssid]");
goto err_fail; goto err_fail;
} }

View File

@ -99,16 +99,16 @@ static void network_start_ap(mstring_t* ap_ssid, mstring_t* ap_pass) {
memcpy( memcpy(
&wifi_config.ap.ssid, &wifi_config.ap.ssid,
mstring_get_cstr(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( memcpy(
&wifi_config.ap.password, &wifi_config.ap.password,
mstring_get_cstr(ap_pass), 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; 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( memcpy(
&wifi_config.sta.ssid, &wifi_config.sta.ssid,
mstring_get_cstr(ap_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( memcpy(
&wifi_config.sta.password, &wifi_config.sta.password,
mstring_get_cstr(ap_pass), 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_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); 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); 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]"); ESP_LOGW(TAG, "too short [ap_pass]");
mstring_set(ap_ssid, ESP_WIFI_SSID); mstring_set(ap_ssid, ESP_WIFI_SSID);
nvs_save_string("ap_ssid", ap_ssid); nvs_save_string("ap_ssid", ap_ssid);
@ -236,7 +236,7 @@ WIFIMode network_init(void) {
nvs_save_string("ap_mode", ap_mode); 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]"); ESP_LOGW(TAG, "too short or too long [ap_ssid]");
mstring_set(ap_ssid, ESP_WIFI_SSID); mstring_set(ap_ssid, ESP_WIFI_SSID);
nvs_save_string("ap_ssid", ap_ssid); nvs_save_string("ap_ssid", ap_ssid);

View File

@ -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));
}

View File

@ -1,4 +0,0 @@
#pragma once
void uart_init();
void uart_print(const char* str);