1 /* Select 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 <sys/fcntl.h>
11 #include <sys/errno.h>
12 #include <sys/unistd.h>
13 #include <sys/param.h>
14 #include <sys/select.h>
15 #include "freertos/FreeRTOS.h"
16 #include "freertos/task.h"
17 #include "esp_log.h"
18 #include "esp_vfs.h"
19 #include "esp_vfs_dev.h"
20 #include "driver/uart.h"
21 #include "esp_netif.h"
22 #include "lwip/sockets.h"
23 #include "lwip/netdb.h"
24 
25 static const char* TAG = "uart_select_example";
26 
27 static int uart_fd = -1;
28 static int socket_fd = -1;
29 
socket_deinit(void)30 static void socket_deinit(void)
31 {
32     close(socket_fd);
33     socket_fd = -1;
34 }
35 
socket_init(void)36 static void socket_init(void)
37 {
38     const struct addrinfo hints = {
39         .ai_family = AF_INET,
40         .ai_socktype = SOCK_DGRAM,
41     };
42     struct addrinfo *res;
43     int err;
44     struct sockaddr_in saddr = { 0 };
45 
46     ESP_ERROR_CHECK(esp_netif_init());
47 
48     err = getaddrinfo("localhost", "80", &hints, &res);
49 
50     if (err != 0 || res == NULL) {
51         ESP_LOGE(TAG, "DNS lookup failed: %d", errno);
52         return;
53     }
54 
55     socket_fd = socket(res->ai_family, res->ai_socktype, 0);
56 
57     if (socket_fd < 0) {
58         ESP_LOGE(TAG, "Failed to allocate socket.");
59         freeaddrinfo(res);
60         return;
61     }
62 
63     saddr.sin_family = PF_INET;
64     saddr.sin_port = htons(80);
65     saddr.sin_addr.s_addr = htonl(INADDR_ANY);
66     err = bind(socket_fd, (struct sockaddr *) &saddr, sizeof(struct sockaddr_in));
67     if (err < 0) {
68         ESP_LOGE(TAG, "Failed to bind socket");
69         freeaddrinfo(res);
70         socket_deinit();
71         return;
72     }
73 
74     if (connect(socket_fd, res->ai_addr, res->ai_addrlen) != 0) {
75         ESP_LOGE(TAG, "Socket connection failed: %d", errno);
76         freeaddrinfo(res);
77         socket_deinit();
78         return;
79     }
80 
81     freeaddrinfo(res);
82 }
83 
uart1_deinit(void)84 static void uart1_deinit(void)
85 {
86     close(uart_fd);
87     uart_fd = -1;
88     uart_driver_delete(UART_NUM_1);
89 }
90 
uart1_init(void)91 static void uart1_init(void)
92 {
93     uart_config_t uart_config = {
94         .baud_rate = 115200,
95         .data_bits = UART_DATA_8_BITS,
96         .parity    = UART_PARITY_DISABLE,
97         .stop_bits = UART_STOP_BITS_1,
98         .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
99         .source_clk = UART_SCLK_APB,
100     };
101     uart_driver_install(UART_NUM_1, 256, 0, 0, NULL, 0);
102     uart_param_config(UART_NUM_1, &uart_config);
103     uart_set_loop_back(UART_NUM_1, true);
104 
105     if ((uart_fd = open("/dev/uart/1", O_RDWR | O_NONBLOCK)) == -1) {
106         ESP_LOGE(TAG, "Cannot open UART1");
107         uart1_deinit();
108     }
109 
110     esp_vfs_dev_uart_use_driver(1);
111 }
112 
uart1_write_task(void * param)113 static void uart1_write_task(void *param)
114 {
115     char buf[20];
116 
117     uart1_init();
118 
119     for (uint8_t i = 1;; ++i) {
120         vTaskDelay(4000 / portTICK_PERIOD_MS);
121 
122         snprintf(buf, sizeof(buf), "UART message U%d", i);
123         int write_bytes = write(uart_fd, buf, strlen(buf));
124         if (write_bytes < 0) {
125             ESP_LOGE(TAG, "UART1 write error");
126         } else {
127             ESP_LOGI(TAG, "%d bytes were sent to UART1: %s", write_bytes, buf);
128         }
129     }
130 
131     uart1_deinit();
132     vTaskDelete(NULL);
133 }
134 
socket_write_task(void * param)135 static void socket_write_task(void *param)
136 {
137     char buf[20];
138 
139     socket_init();
140 
141     for (uint8_t i = 1;; ++i) {
142         vTaskDelay(3000 / portTICK_PERIOD_MS);
143 
144         snprintf(buf, sizeof(buf), "Socket message S%d", i);
145         int write_bytes = write(socket_fd, buf, strlen(buf));
146         if (write_bytes < 0) {
147             ESP_LOGE(TAG, "Socket write error");
148         } else {
149             ESP_LOGI(TAG, "%d bytes were written to socket: %s", write_bytes, buf);
150         }
151     }
152 
153     socket_deinit();
154     vTaskDelete(NULL);
155 }
156 
check_and_print(int fd,const fd_set * rfds,const char * src_msg)157 static void check_and_print(int fd, const fd_set *rfds, const char *src_msg)
158 {
159     char buf[100];
160     int read_bytes;
161 
162     if (FD_ISSET(fd, rfds)) {
163         if ((read_bytes = read(fd, buf, sizeof(buf)-1)) > 0) {
164             buf[read_bytes] = '\0';
165             ESP_LOGI(TAG, "%d bytes were received through %s: %s", read_bytes, src_msg, buf);
166         } else {
167             ESP_LOGE(TAG, "%s read error", src_msg);
168         }
169     }
170 }
171 
select_task(void * param)172 static void select_task(void *param)
173 {
174     while (1) {
175         int s;
176         fd_set rfds;
177         struct timeval tv = {
178             .tv_sec = 1,
179             .tv_usec = 0,
180         };
181 
182         FD_ZERO(&rfds);
183         FD_SET(uart_fd, &rfds);
184         FD_SET(socket_fd, &rfds);
185 
186         s = select(MAX(uart_fd, socket_fd) + 1, &rfds, NULL, NULL, &tv);
187 
188         if (s < 0) {
189             ESP_LOGE(TAG, "Select failed: errno %d", errno);
190         } else if (s == 0) {
191             ESP_LOGI(TAG, "Timeout has been reached and nothing has been received");
192         } else {
193             check_and_print(socket_fd, &rfds, "socket");
194             check_and_print(uart_fd, &rfds, "UART1");
195         }
196     }
197 
198     vTaskDelete(NULL);
199 }
200 
app_main(void)201 void app_main(void)
202 {
203     xTaskCreate(uart1_write_task, "uart1_write_task", 4*1024, NULL, 5, NULL);
204     xTaskCreate(socket_write_task, "socket_write_task", 4*1024, NULL, 5, NULL);
205     vTaskDelay(1000 / portTICK_PERIOD_MS);
206     xTaskCreate(select_task, "select_task", 4*1024, NULL, 5, NULL);
207 }
208