224 lines
5.9 KiB
C
224 lines
5.9 KiB
C
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <esp_log.h>
|
|
#include <esp_console.h>
|
|
#include <freertos/FreeRTOS.h>
|
|
#include <freertos/task.h>
|
|
#include <freertos/queue.h>
|
|
#include <driver/uart.h>
|
|
|
|
#include <protocomm.h>
|
|
#include <protocomm_console.h>
|
|
|
|
#include "protocomm_priv.h"
|
|
|
|
static const char *TAG = "protocomm_console";
|
|
|
|
static uint32_t session_id = PROTOCOMM_NO_SESSION_ID;
|
|
static protocomm_t *pc_console = NULL; /* The global protocomm instance for console */
|
|
static TaskHandle_t console_task = NULL;
|
|
|
|
esp_err_t protocomm_console_stop(protocomm_t *pc)
|
|
{
|
|
if (pc != pc_console) {
|
|
ESP_LOGE(TAG, "Incorrect stop request");
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Stopping console...");
|
|
xTaskNotifyGive(console_task);
|
|
return ESP_OK;
|
|
}
|
|
|
|
static ssize_t hex2bin(const char *hexstr, uint8_t *bytes)
|
|
{
|
|
size_t hexstrLen = strlen(hexstr);
|
|
ssize_t bytesLen = hexstrLen / 2;
|
|
|
|
int count = 0;
|
|
const char *pos = hexstr;
|
|
|
|
for(count = 0; count < bytesLen; count++) {
|
|
sscanf(pos, "%2hhx", &bytes[count]);
|
|
pos += 2;
|
|
}
|
|
|
|
return bytesLen;
|
|
}
|
|
|
|
static bool stopped(void)
|
|
{
|
|
uint32_t flag = 0;
|
|
xTaskNotifyWait(0, 0, &flag, (TickType_t) 10/portTICK_RATE_MS);
|
|
return (flag != 0);
|
|
}
|
|
|
|
static void protocomm_console_task(void *arg)
|
|
{
|
|
int uart_num = (int) arg;
|
|
uint8_t linebuf[256];
|
|
int i, cmd_ret;
|
|
esp_err_t ret;
|
|
QueueHandle_t uart_queue;
|
|
uart_event_t event;
|
|
|
|
ESP_LOGD(TAG, "Initializing UART on port %d", uart_num);
|
|
uart_driver_install(uart_num, 256, 0, 8, &uart_queue, 0);
|
|
/* Initialize the console */
|
|
esp_console_config_t console_config = {
|
|
.max_cmdline_args = 8,
|
|
.max_cmdline_length = 256,
|
|
};
|
|
|
|
esp_console_init(&console_config);
|
|
esp_console_register_help_command();
|
|
|
|
while (!stopped()) {
|
|
uart_write_bytes(uart_num, "\n>> ", 4);
|
|
memset(linebuf, 0, sizeof(linebuf));
|
|
i = 0;
|
|
do {
|
|
ret = xQueueReceive(uart_queue, (void * )&event, (TickType_t) 10/portTICK_RATE_MS);
|
|
if (ret != pdPASS) {
|
|
if (stopped()) {
|
|
break;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
if (event.type == UART_DATA) {
|
|
while (uart_read_bytes(uart_num, (uint8_t *) &linebuf[i], 1, 0)) {
|
|
if (linebuf[i] == '\r') {
|
|
uart_write_bytes(uart_num, "\r\n", 2);
|
|
} else {
|
|
uart_write_bytes(uart_num, (char *) &linebuf[i], 1);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
} while ((i < 255) && linebuf[i-1] != '\r');
|
|
if (stopped()) {
|
|
break;
|
|
}
|
|
ret = esp_console_run((char *) linebuf, &cmd_ret);
|
|
if (ret < 0) {
|
|
ESP_LOGE(TAG, "Console dispatcher error\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
pc_console = NULL;
|
|
esp_console_deinit();
|
|
|
|
ESP_LOGI(TAG, "Console stopped");
|
|
vTaskDelete(NULL);
|
|
}
|
|
|
|
static int common_cmd_handler(int argc, char** argv)
|
|
{
|
|
if (argc < 3) {
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
|
|
int i, ret;
|
|
|
|
uint32_t cur_session_id = atoi(argv[1]);
|
|
|
|
uint8_t *buf = (uint8_t *) malloc(strlen(argv[2]));
|
|
uint8_t *outbuf;
|
|
ssize_t outlen;
|
|
ssize_t len = hex2bin(argv[2], buf);
|
|
|
|
if (cur_session_id != session_id) {
|
|
if (pc_console->sec && pc_console->sec->new_transport_session) {
|
|
ret = pc_console->sec->new_transport_session(cur_session_id);
|
|
if (ret == ESP_OK) {
|
|
session_id = cur_session_id;
|
|
}
|
|
}
|
|
}
|
|
|
|
ret = protocomm_req_handle(pc_console, argv[0], cur_session_id, buf, len, &outbuf, &outlen);
|
|
free(buf);
|
|
|
|
if (ret == ESP_OK) {
|
|
printf("\r\n");
|
|
for (i = 0; i < outlen; i++) {
|
|
printf("%02x", outbuf[i]);
|
|
}
|
|
printf("\r\n");
|
|
|
|
/* Transport is responsible for freeing the transmit buffer */
|
|
free(outbuf);
|
|
|
|
return ESP_OK;
|
|
} else {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
static esp_err_t protocomm_console_add_endpoint(const char *ep_name, protocomm_req_handler_t req_handler, void *priv_data)
|
|
{
|
|
(void) req_handler;
|
|
(void) priv_data;
|
|
|
|
esp_err_t ret;
|
|
esp_console_cmd_t cmd;
|
|
memset(&cmd, 0, sizeof(cmd));
|
|
|
|
cmd.command = ep_name;
|
|
cmd.help = "";
|
|
cmd.func = common_cmd_handler;
|
|
|
|
ret = esp_console_cmd_register(&cmd);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static esp_err_t protocomm_console_remove_endpoint(const char *ep_name)
|
|
{
|
|
/* Command deletion happens internally in esp_console_deinit function */
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t protocomm_console_start(protocomm_t *pc, const protocomm_console_config_t *config)
|
|
{
|
|
if (pc == NULL) {
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
|
|
if (pc_console != NULL) {
|
|
if (pc_console == pc) {
|
|
return ESP_ERR_INVALID_STATE;
|
|
}
|
|
else {
|
|
return ESP_ERR_NOT_SUPPORTED;
|
|
}
|
|
}
|
|
|
|
|
|
if (xTaskCreate(protocomm_console_task, "protocomm_console",
|
|
config->stack_size, NULL, config->task_priority, &console_task) != pdPASS) {
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
pc->add_endpoint = protocomm_console_add_endpoint;
|
|
pc->remove_endpoint = protocomm_console_remove_endpoint;
|
|
pc_console = pc;
|
|
return ESP_OK;
|
|
}
|