/
at_uart_task.c
286 lines (251 loc) · 8.66 KB
/
at_uart_task.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sdkconfig.h"
#ifdef CONFIG_AT_BASE_ON_UART
#include "soc/io_mux_reg.h"
#include "soc/gpio_periph.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_at.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "driver/gpio.h"
#include "driver/uart.h"
#include "at_uart.h"
#include "esp_at_interface.h"
// static variables
static QueueHandle_t s_at_uart_queue = NULL;
// global variables
uint8_t g_at_cmd_port = UART_NUM_1;
at_uart_port_pins_t g_uart_port_pin;
static int32_t at_uart_write_data(uint8_t *data, int32_t len)
{
uint32_t length = 0;
length = uart_write_bytes(g_at_cmd_port, (char *)data, len);
return length;
}
static int32_t at_uart_read_data(uint8_t *buffer, int32_t len)
{
if (len == 0) {
return 0;
}
if (buffer == NULL) {
if (len == -1) {
size_t size = 0;
if (uart_get_buffered_data_len(g_at_cmd_port, &size) != ESP_OK) {
return -1;
}
len = size;
}
if (len == 0) {
return 0;
}
uint8_t *data = (uint8_t *)malloc(len);
if (data) {
len = uart_read_bytes(g_at_cmd_port, data, len, portTICK_PERIOD_MS);
free(data);
return len;
} else {
return -1;
}
} else {
return uart_read_bytes(g_at_cmd_port, buffer, len, portTICK_PERIOD_MS);
}
}
static int32_t at_uart_get_data_len(void)
{
size_t size = 0;
if (uart_get_buffered_data_len(g_at_cmd_port, &size) == ESP_OK) {
int pattern_pos = uart_pattern_get_pos(g_at_cmd_port);
if (pattern_pos >= 0) {
size = pattern_pos;
}
return size;
} else {
return 0;
}
}
static bool at_uart_wait_tx_done(int32_t ms)
{
if (uart_wait_tx_done(g_at_cmd_port, ms / portTICK_PERIOD_MS) == ESP_OK) {
return true;
}
return false;
}
static void at_uart_task(void *params)
{
uart_event_t event;
int pattern_pos = -1;
BaseType_t retry_flag = pdFALSE;
uint8_t *data = NULL;
uint32_t data_len = 0;
for (;;) {
if (xQueueReceive(s_at_uart_queue, (void *)&event, portMAX_DELAY)) {
retry:
switch (event.type) {
case UART_DATA:
case UART_BUFFER_FULL:
data_len += event.size;
// we can put all data together to process
retry_flag = pdFALSE;
while (xQueueReceive(s_at_uart_queue, (void *)&event, 0) == pdTRUE) {
if (event.type == UART_DATA) {
data_len += event.size;
} else if (event.type == UART_BUFFER_FULL) {
esp_at_port_recv_data_notify(data_len, portMAX_DELAY);
data_len = event.size;
break;
} else {
retry_flag = pdTRUE;
break;
}
}
esp_at_port_recv_data_notify(data_len, portMAX_DELAY);
data_len = 0;
if (retry_flag == pdTRUE) {
goto retry;
}
break;
case UART_PATTERN_DET:
pattern_pos = uart_pattern_pop_pos(g_at_cmd_port);
if (pattern_pos >= 0) {
data = (uint8_t *)malloc(pattern_pos + 3);
uart_read_bytes(g_at_cmd_port, data, pattern_pos + 3, 0);
free(data);
data = NULL;
} else {
uart_flush_input(g_at_cmd_port);
xQueueReset(s_at_uart_queue);
}
esp_at_transmit_terminal();
break;
case UART_FIFO_OVF:
retry_flag = pdFALSE;
while (xQueueReceive(s_at_uart_queue, (void *)&event, 0) == pdTRUE) {
if ((event.type == UART_DATA) || (event.type == UART_BUFFER_FULL) || (event.type == UART_FIFO_OVF)) {
// put all data together to process
} else {
retry_flag = pdTRUE;
break;
}
}
esp_at_port_recv_data_notify(at_uart_get_data_len(), portMAX_DELAY);
data_len = 0;
if (retry_flag == pdTRUE) {
goto retry;
}
break;
default:
break;
}
}
}
vTaskDelete(NULL);
}
static void at_uart_init(void)
{
// get uart port and uart pins
at_mfg_uart_port_pins_get(&g_uart_port_pin);
g_at_cmd_port = g_uart_port_pin.number;
// install uart driver
uart_driver_install(g_at_cmd_port, AT_UART_RX_BUFFER_SIZE, AT_UART_TX_BUFFER_SIZE, AT_UART_QUEUE_SIZE, &s_at_uart_queue, 0);
// set uart configuration
uart_config_t config;
at_uart_config_init(&config);
if (!at_nvs_uart_config_get(&config)) {
at_nvs_uart_config_set(&config);
}
uart_param_config(g_at_cmd_port, &config);
// set uart pins
uart_set_pin(g_at_cmd_port, g_uart_port_pin.tx_pin, g_uart_port_pin.rx_pin, g_uart_port_pin.rts_pin, g_uart_port_pin.cts_pin);
// set uart interrupt
at_uart_intr_config();
// do some possible uart workarounds
at_uart_workaround();
printf("AT cmd port:uart%d tx:%d rx:%d cts:%d rts:%d baudrate:%d\r\n",
g_at_cmd_port, g_uart_port_pin.tx_pin, g_uart_port_pin.rx_pin,
g_uart_port_pin.cts_pin, g_uart_port_pin.rts_pin, config.baud_rate);
xTaskCreate(at_uart_task, "uTask", 1024, NULL, 1, NULL);
}
void at_uart_transmit_mode_switch_cb(esp_at_status_type status)
{
switch (status) {
case ESP_AT_STATUS_NORMAL:
uart_disable_pattern_det_intr(g_at_cmd_port);
break;
case ESP_AT_STATUS_TRANSMIT: {
/**
* As the implement of API uart_enable_pattern_det_baud_intr() in esp-idf,
* the last three timeout parameters is different on ESP32 and non ESP32 platform.
*
* That is, on ESP32 platform, it uses the APB clocks as the unit;
* on non ESP32 platform (ESP32-C3, ..), it uses the UART baud rate clocks as the unit.
*
* Notes:
* on non ESP32 platform, due to the value of input parameters have a limit of 0xFFFF (see as macro: UART_RX_GAP_TOUT_V..),
* so the maximum uart baud rate is recommended to be less than (0xFFFF * 1000 / AT_UART_PATTERN_TIMEOUT_MS) = 3276750 ~= 3.2Mbps
* otherwise, this uart_enable_pattern_det_baud_intr() will not work.
*/
#ifdef CONFIG_IDF_TARGET_ESP32
int apb_clocks = (uint32_t)APB_CLK_FREQ * AT_UART_PATTERN_TIMEOUT_MS / 1000;
uart_enable_pattern_det_baud_intr(g_at_cmd_port, '+', 3, apb_clocks, apb_clocks, apb_clocks);
#else
uint32_t uart_baud = 0;
uart_get_baudrate(g_at_cmd_port, &uart_baud);
int uart_clocks = (uint32_t)uart_baud * AT_UART_PATTERN_TIMEOUT_MS / 1000;
uart_enable_pattern_det_baud_intr(g_at_cmd_port, '+', 3, uart_clocks, uart_clocks, uart_clocks);
#endif
}
break;
}
}
void at_uart_deepsleep_before_cb(void)
{
// disable uart pins for power saving, in case of leakage current
if (g_uart_port_pin.tx_pin >= 0) {
gpio_set_direction(g_uart_port_pin.tx_pin, GPIO_MODE_DISABLE);
}
if (g_uart_port_pin.rx_pin >= 0) {
gpio_set_direction(g_uart_port_pin.rx_pin, GPIO_MODE_DISABLE);
}
if (g_uart_port_pin.cts_pin >= 0) {
gpio_set_direction(g_uart_port_pin.cts_pin, GPIO_MODE_DISABLE);
}
if (g_uart_port_pin.rts_pin >= 0) {
gpio_set_direction(g_uart_port_pin.rts_pin, GPIO_MODE_DISABLE);
}
}
void at_uart_restart_before_cb(void)
{
uart_disable_rx_intr(g_at_cmd_port);
}
void at_interface_init(void)
{
// init interface driver
at_uart_init();
// init interface operations
esp_at_device_ops_struct uart_ops = {
.read_data = at_uart_read_data,
.write_data = at_uart_write_data,
.get_data_length = at_uart_get_data_len,
.wait_write_complete = at_uart_wait_tx_done,
};
at_interface_ops_init(&uart_ops);
// init interface hooks
esp_at_custom_ops_struct uart_hooks = {
.status_callback = at_uart_transmit_mode_switch_cb,
.pre_sleep_callback = NULL,
.pre_deepsleep_callback = at_uart_deepsleep_before_cb,
.pre_restart_callback = at_uart_restart_before_cb,
.pre_active_write_data_callback = NULL,
};
at_interface_hooks(&uart_hooks);
}
#endif