1 /* UART Echo Example
2 
3    This example code is in the Public Domain (or CC0 licensed, at your option.)
4 
5    Unless required by applicable law or agreed to in writing, this
6    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
7    CONDITIONS OF ANY KIND, either express or implied.
8 */
9 #include <stdio.h>
10 #include "freertos/FreeRTOS.h"
11 #include "freertos/task.h"
12 #include "driver/uart.h"
13 #include "soc/uart_periph.h"
14 #include "esp_rom_gpio.h"
15 #include "driver/gpio.h"
16 #include "hal/gpio_hal.h"
17 #include "sdkconfig.h"
18 #include "esp_console.h"
19 #include "linenoise/linenoise.h"
20 #include <string.h>
21 
22 #define DEFAULT_UART_CHANNEL    (0)
23 #define CONSOLE_UART_CHANNEL    (1 - DEFAULT_UART_CHANNEL)
24 #define DEFAULT_UART_RX_PIN     (3)
25 #define DEFAULT_UART_TX_PIN     (2)
26 #define CONSOLE_UART_RX_PIN     (4)
27 #define CONSOLE_UART_TX_PIN     (5)
28 
29 #define UARTS_BAUD_RATE         (115200)
30 #define TASK_STACK_SIZE         (2048)
31 #define READ_BUF_SIZE           (1024)
32 
33 /* Message printed by the "consoletest" command.
34  * It will also be used by the default UART to check the reply of the second
35  * UART. As end of line characters are not standard here (\n, \r\n, \r...),
36  * let's not include it in this string. */
37 const char test_message[] = "This is an example string, if you can read this, the example is a success!";
38 
39 /**
40  * @brief This function connects default UART TX to console UART RX and default
41  * UART RX to console UART TX. The purpose is to send commands to the console
42  * and get the reply directly by reading RX FIFO.
43  */
connect_uarts(void)44 static void connect_uarts(void)
45 {
46     esp_rom_gpio_connect_out_signal(DEFAULT_UART_RX_PIN, UART_PERIPH_SIGNAL(1, SOC_UART_TX_PIN_IDX), false, false);
47     esp_rom_gpio_connect_in_signal(DEFAULT_UART_RX_PIN, UART_PERIPH_SIGNAL(0, SOC_UART_RX_PIN_IDX), false);
48 
49     esp_rom_gpio_connect_out_signal(DEFAULT_UART_TX_PIN, UART_PERIPH_SIGNAL(0, SOC_UART_TX_PIN_IDX), false, false);
50     esp_rom_gpio_connect_in_signal(DEFAULT_UART_TX_PIN, UART_PERIPH_SIGNAL(1, SOC_UART_RX_PIN_IDX), false);
51 }
52 
53 /**
54  * @brief Disconnect default UART from the console UART, this is used once
55  * testing is finished, it will let us print messages on the UART without
56  * sending them back to the console UART. Else, we would get an infinite
57  * loop.
58  */
disconnect_uarts(void)59 static void disconnect_uarts(void)
60 {
61     esp_rom_gpio_connect_out_signal(CONSOLE_UART_TX_PIN, UART_PERIPH_SIGNAL(1, SOC_UART_TX_PIN_IDX), false, false);
62     esp_rom_gpio_connect_in_signal(CONSOLE_UART_RX_PIN, UART_PERIPH_SIGNAL(1, SOC_UART_RX_PIN_IDX), false);
63 }
64 
65 /**
66  * @brief Configure and install the default UART, then, connect it to the
67  * console UART.
68  */
configure_uarts(void)69 static void configure_uarts(void)
70 {
71     /* Configure parameters of an UART driver,
72      * communication pins and install the driver */
73     uart_config_t uart_config = {
74         .baud_rate = UARTS_BAUD_RATE,
75         .data_bits = UART_DATA_8_BITS,
76         .parity    = UART_PARITY_DISABLE,
77         .stop_bits = UART_STOP_BITS_1,
78         .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
79         .source_clk = UART_SCLK_APB,
80     };
81 
82     ESP_ERROR_CHECK(uart_driver_install(DEFAULT_UART_CHANNEL, READ_BUF_SIZE * 2, 0, 0, NULL, 0));
83     ESP_ERROR_CHECK(uart_param_config(DEFAULT_UART_CHANNEL, &uart_config));
84     ESP_ERROR_CHECK(uart_set_pin(DEFAULT_UART_CHANNEL, DEFAULT_UART_TX_PIN, DEFAULT_UART_RX_PIN,
85                                  UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
86 
87 
88     connect_uarts();
89 }
90 
91 /**
92  * @brief Function called when command `consoletest` will be invoked.
93  * It will simply print `test_message` defined above.
94  */
console_test(int argc,char ** argv)95 static int console_test(int argc, char **argv) {
96     printf("%s\n", test_message);
97     return 0;
98 }
99 
100 /**
101  * @brief Function executed in another task then main one (as the one main
102  * executes REPL console).
103  * It will send "consoletest" command to the console UART and then read back
104  * the response on RX.
105  * The response shall contain the test_message string.
106  */
send_commands(void * arg)107 static void send_commands(void* arg) {
108     static char data[READ_BUF_SIZE];
109     char command[] = "consoletest\n";
110     int len = 0;
111     void* substring = NULL;
112 
113     /* Discard the first messages sent by the console. */
114     do {
115         len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE, 100 / portTICK_RATE_MS);
116     } while (len == 0);
117 
118     if ( len == -1 ) {
119         goto end;
120     }
121     /* Send the command `consoletest` to the console UART. */
122     len = uart_write_bytes(DEFAULT_UART_CHANNEL, command, sizeof(command));
123     if ( len == -1 ) {
124         goto end;
125     }
126 
127     /* Get the answer back from the console, give it some delay. */
128     do {
129         len = uart_read_bytes(DEFAULT_UART_CHANNEL, data, READ_BUF_SIZE - 1, 250 / portTICK_RATE_MS);
130     } while (len == 0);
131 
132     if ( len == -1 ) {
133         goto end;
134     }
135 
136     /**
137      * Check whether we can find test_message in the received message. Before
138      * that, we need to add a NULL character to terminate the string.
139      */
140     data[len] = 0;
141     substring = strcasestr(data, test_message);
142 
143 end:
144     /* This is a must to not send anything to the console anymore! */
145     disconnect_uarts();
146     printf("Result: %s\n", substring == NULL ? "Failure" : "Success");
147     vTaskDelete(NULL);
148 }
149 
app_main(void)150 void app_main(void)
151 {
152     esp_console_repl_t *repl = NULL;
153     esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
154     repl_config.prompt = "repl >";
155     const esp_console_cmd_t cmd = {
156         .command = "consoletest",
157         .help = "Test console by sending a message",
158         .func = &console_test,
159     };
160     esp_console_dev_uart_config_t uart_config = {
161                                                     .channel = CONSOLE_UART_CHANNEL,
162                                                     .baud_rate = UARTS_BAUD_RATE,
163                                                     .tx_gpio_num = CONSOLE_UART_TX_PIN,
164                                                     .rx_gpio_num = CONSOLE_UART_RX_PIN,
165                                                 };
166     /**
167      * As we don't have a real serial terminal, (we just use default UART to
168      * send and receive commands, ) we won't handle any escape sequence, so the
169      * easiest thing to do is set the console to "dumb" mode. */
170     linenoiseSetDumbMode(1);
171 
172     ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl));
173     configure_uarts();
174 
175     ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
176 
177     /* Create a task for sending and receiving commands to and from the second UART. */
178     xTaskCreate(send_commands, "send_commands_task", TASK_STACK_SIZE, NULL, 10, NULL);
179 
180     ESP_ERROR_CHECK(esp_console_start_repl(repl));
181 }
182