Air quality sensor
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
esp-airsensor/main/console/console_server.c

156 lines
3.8 KiB

//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include <stdint.h>
#include <sys/socket.h>
#include <esp_log.h>
#include <string.h>
#include <freertos/ringbuf.h>
#include "socket_server.h"
#include "console_server.h"
#include "application.h"
#include "tasks.h"
#include "telnet_parser.h"
#include "console_ioimpl.h"
static const char *TAG = "console_srv";
Tcpd_t g_telnet_server = NULL;
TcpdClient_t telnetsrv_last_rx_client = NULL;
/**
* Send a textual message to all the connected peers
*
* @param interface
* @param packet
* @param timeout
* @return
*/
esp_err_t telnetsrv_send(TcpdClient_t client, const char *message, ssize_t len)
{
if (!g_telnet_server) {
ESP_LOGE(TAG, "server not inited");
return ESP_FAIL;
}
if (len < 0) len = strlen(message);
if (client) {
tcpd_send(client, (const uint8_t *) message, len);
} else {
tcpd_broadcast(g_telnet_server, (const uint8_t *) message, len);
}
return ESP_OK;
}
/**
* Handle received bytes
*
* @param client
* @param buf
* @param nbytes
*/
static void telnetsrv_handle(TcpdClient_t client, char *buf, int nbytes)
{
void *ctx = tcpd_get_client_ctx(client);
struct console_ioimpl *io = ctx;
if (!ctx) {
ESP_LOGE(TAG, "telnet rx with no ioctx!");
return;
}
assert(CONSOLE_IOIMPL_MAGIC == io->__magic);
int rv = xRingbufferSend(io->telnet.console_stdin_ringbuf, buf, (size_t) nbytes, pdMS_TO_TICKS(100));
if (rv != pdPASS) {
ESP_LOGE(TAG, "console ringbuf overflow");
}
}
/**
* Socket read handler
*/
esp_err_t read_fn(Tcpd_t serv, TcpdClient_t client, int sockfd)
{
char buf[64];
int nbytes = read(sockfd, buf, sizeof(buf));
if (nbytes <= 0) return ESP_FAIL;
// ESP_LOGI(TAG, "Rx %d bytes", nbytes);
telnetsrv_handle(client, buf, nbytes);
return ESP_OK;
}
static void print_motd(console_ctx_t *ctx)
{
console_printf_ctx(ctx, COLOR_RESET, "\n"
"===================================================\n"
" ESP32 node "APP_NAME" "APP_VERSION " #" GIT_HASH "\n"
" Built " BUILD_TIMESTAMP "\n"
"\n"
" Run `ls` for a list of commands.\n"
"===================================================\n\n"
);
// show the initial prompt
console_print(ctx->prompt);
}
/**
* Socket open handler - send a MOTD
*/
static esp_err_t open_fn(Tcpd_t serv, TcpdClient_t client)
{
vTaskDelay(pdMS_TO_TICKS(100));
struct console_ioimpl *io = NULL;
esp_err_t rv = console_start_tcp(&io, NULL, client);
if (rv != ESP_OK) {
return rv;
}
assert(io);
// set telnet params, unless this is the injected stdin client
if (tcpd_get_client_fd(client) != STDIN_FILENO) {
telnet_send_will(&io->ctx, OPT_SUPPRESS_GO_AHEAD);
telnet_send_will(&io->ctx, OPT_ECHO);
telnet_send_dont(&io->ctx, OPT_ECHO);
}
return ESP_OK;
}
void console_print_motd(console_ctx_t *ctx)
{
print_motd(ctx);
}
esp_err_t telnetsrv_start(uint16_t port)
{
tcpd_config_t server_config = TCPD_INIT_DEFAULT();
server_config.max_clients = 3;
server_config.task_prio = TELNET_TASK_PRIO;
server_config.task_stack = TELNET_TASK_STACK;
server_config.task_name = "TelnetSrv";
server_config.port = port;
server_config.read_fn = read_fn;
server_config.open_fn = open_fn;
// close fn is not needed, console shuts down if the FD becomes invalid (read fails)
ESP_ERROR_CHECK(tcpd_init(&server_config, &g_telnet_server));
// this deadlocks now... XXX
// cspemu_add_shutdown_handler(telnetsrv_kick_all);
return ESP_OK;
}
void telnetsrv_kick_all(void)
{
ESP_LOGI(TAG, "Kick all telnet clients");
tcpd_kick_all(g_telnet_server, false); // don't kick injected clients
ESP_LOGI(TAG, "Kicking done!");
}