1 #include <twr_esp8266.h>
4 #define _TWR_ESP8266_DELAY_INITIALIZATION_AT_COMMAND 100
5 #define _TWR_ESP8266_DELAY_SEND_RESPONSE 100
6 #define _TWR_ESP8266_DELAY_WIFI_CONNECT 1000
7 #define _TWR_ESP8266_DELAY_SOCKET_CONNECT 300
8 #define _TWR_ESP8266_TIMEOUT_WIFI_CONNECT 20
9 #define _TWR_ESP8266_TIMEOUT_SOCKET_CONNECT 10
12 static const char *_esp8266_init_commands[] =
23 "AT+CWAUTOCONN=0\r\n",
27 "AT+CIPSSLSIZE=4096\r\n",
31 static void _twr_esp8266_task(
void *param);
33 static bool _twr_esp8266_read_socket_data(
twr_esp8266_t *
self);
35 static void _twr_esp8266_set_rtc_time(
char *str);
39 memset(
self, 0,
sizeof(*
self));
41 self->_uart_channel = uart_channel;
43 self->_config.mode = TWR_ESP8266_CONFIG_MODE_STATION;
44 self->_config.ssid[0] =
'\0';
45 self->_config.password[0] =
'\0';
46 self->_config.sntp_enabled = 0;
58 twr_fifo_init(&self->_tx_fifo, self->_tx_fifo_buffer,
sizeof(self->_tx_fifo_buffer));
59 twr_fifo_init(&self->_rx_fifo, self->_rx_fifo_buffer,
sizeof(self->_rx_fifo_buffer));
62 self->_state = TWR_ESP8266_STATE_DISCONNECTED;
73 self->_state = TWR_ESP8266_STATE_RECEIVE;
100 self->_event_handler = event_handler;
101 self->_event_param = event_param;
106 self->_config.mode = TWR_ESP8266_CONFIG_MODE_STATION;
107 strncpy(self->_config.ssid, ssid, 63);
108 strncpy(self->_config.password, password, 63);
118 self->_config.sntp_enabled = 1;
119 self->_config.sntp_timezone = timezone;
120 if (sntp_server1 != NULL)
122 strncpy(self->_config.sntp_server1, sntp_server1, 127);
126 strcpy(self->_config.sntp_server1,
"0.pool.ntp.org");
128 if (sntp_server2 != NULL)
130 strncpy(self->_config.sntp_server2, sntp_server2, 127);
134 strcpy(self->_config.sntp_server2,
"1.pool.ntp.org");
136 if (sntp_server3 != NULL)
138 strncpy(self->_config.sntp_server3, sntp_server3, 127);
142 strcpy(self->_config.sntp_server3,
"2.pool.ntp.org");
148 if (self->_state == TWR_ESP8266_STATE_READY || self->_state == TWR_ESP8266_STATE_IDLE)
158 if (self->_state != TWR_ESP8266_STATE_DISCONNECTED ||
159 self->_config.ssid[0] ==
'\0' || self->_config.password[0] ==
'\0')
164 _twr_esp8266_enable(
self);
166 self->_state = TWR_ESP8266_STATE_INITIALIZE;
167 self->_state_after_init = TWR_ESP8266_STATE_WIFI_CONNECT_COMMAND;
176 _twr_esp8266_disable(
self);
178 self->_state = TWR_ESP8266_STATE_DISCONNECTED;
180 if (self->_event_handler != NULL)
182 self->_event_handler(
self, TWR_ESP8266_EVENT_DISCONNECTED, self->_event_param);
188 bool twr_esp8266_socket_connect(
twr_esp8266_t *
self,
const char *type,
const char *host, uint16_t port)
191 (strlen(host) + 15) > TWR_ESP8266_TX_MAX_PACKET_SIZE)
196 static char buffer[TWR_ESP8266_TX_MAX_PACKET_SIZE];
197 sprintf(buffer,
"\"%s\",\"%s\",%d", type, host, port);
199 self->_message_length = strlen(buffer);
201 memcpy(self->_message_buffer, buffer, self->_message_length);
203 self->_state = TWR_ESP8266_STATE_SOCKET_CONNECT_COMMAND;
212 return twr_esp8266_socket_connect(
self,
"TCP", host, port);
217 return twr_esp8266_socket_connect(
self,
"UDP", host, port);
222 return twr_esp8266_socket_connect(
self,
"SSL", host, port);
232 self->_message_length = length;
234 memcpy(self->_message_buffer, buffer, self->_message_length);
236 self->_state = TWR_ESP8266_STATE_SOCKET_SEND_COMMAND;
243 static void _twr_esp8266_task(
void *param)
249 switch (self->_state)
251 case TWR_ESP8266_STATE_READY:
253 self->_state = TWR_ESP8266_STATE_IDLE;
255 if (self->_event_handler != NULL)
262 case TWR_ESP8266_STATE_IDLE:
263 case TWR_ESP8266_STATE_DISCONNECTED:
267 case TWR_ESP8266_STATE_RECEIVE:
269 self->_state = TWR_ESP8266_STATE_IDLE;
271 while (_twr_esp8266_read_response(
self))
273 if (memcmp(self->_response,
"+IPD", 4) == 0)
276 char *comma_search = strchr(self->_response,
',');
277 if (comma_search == NULL)
282 char *colon_search = strchr(self->_response,
':');
283 if (colon_search == NULL)
287 if ((colon_search - comma_search) > 9)
291 char length_text[10];
292 memcpy(length_text, comma_search, colon_search - comma_search);
293 length_text[colon_search - comma_search] =
'\0';
294 self->_message_length = atoi(length_text);
296 self->_message_part_length = (strlen(self->_response) - 1) - (colon_search - self->_response);
298 memcpy(self->_message_buffer, colon_search, self->_message_part_length);
300 if (self->_message_length >
sizeof(self->_message_buffer))
302 self->_message_length =
sizeof(
self->_message_buffer);
305 self->_state = TWR_ESP8266_STATE_SOCKET_RECEIVE;
314 case TWR_ESP8266_STATE_ERROR:
316 if (self->_event_handler != NULL)
321 self->_state = TWR_ESP8266_STATE_INITIALIZE;
325 case TWR_ESP8266_STATE_INITIALIZE:
327 self->_init_command_index = 0;
328 self->_state = TWR_ESP8266_STATE_INITIALIZE_COMMAND_SEND;
332 case TWR_ESP8266_STATE_INITIALIZE_COMMAND_SEND:
334 self->_state = TWR_ESP8266_STATE_ERROR;
342 strcpy(self->_command, _esp8266_init_commands[self->_init_command_index]);
343 size_t length = strlen(self->_command);
350 self->_state = TWR_ESP8266_STATE_INITIALIZE_COMMAND_RESPONSE;
355 case TWR_ESP8266_STATE_INITIALIZE_COMMAND_RESPONSE:
357 self->_state = TWR_ESP8266_STATE_ERROR;
359 if (!_twr_esp8266_read_response(
self))
365 if (memcmp(self->_response,
"AT", 2) == 0 && !_twr_esp8266_read_response(
self))
370 if (memcmp(self->_response,
"OK", 2) != 0)
375 self->_init_command_index++;
377 if (_esp8266_init_commands[self->_init_command_index] == NULL)
379 self->_state =
self->_state_after_init;
383 self->_state = TWR_ESP8266_STATE_INITIALIZE_COMMAND_SEND;
388 case TWR_ESP8266_STATE_WIFI_CONNECT_COMMAND:
389 case TWR_ESP8266_STATE_AP_AVAILABILITY_OPT_COMMAND:
390 case TWR_ESP8266_STATE_AP_AVAILABILITY_COMMAND:
391 case TWR_ESP8266_STATE_SNTP_CONFIG_COMMAND:
392 case TWR_ESP8266_STATE_SNTP_TIME_COMMAND:
393 case TWR_ESP8266_STATE_SOCKET_CONNECT_COMMAND:
394 case TWR_ESP8266_STATE_SOCKET_SEND_COMMAND:
396 twr_esp8266_state_t response_state;
398 if (self->_state == TWR_ESP8266_STATE_WIFI_CONNECT_COMMAND)
400 sprintf(self->_command,
"AT+CWJAP_CUR=\"%s\",\"%s\"\r\n", self->_config.ssid, self->_config.password);
401 response_state = TWR_ESP8266_STATE_WIFI_CONNECT_RESPONSE;
403 else if (self->_state == TWR_ESP8266_STATE_AP_AVAILABILITY_OPT_COMMAND)
405 strcpy(self->_command,
"AT+CWLAPOPT=1,6\r\n");
406 response_state = TWR_ESP8266_STATE_AP_AVAILABILITY_OPT_RESPONSE;
408 else if (self->_state == TWR_ESP8266_STATE_AP_AVAILABILITY_COMMAND)
410 strcpy(self->_command,
"AT+CWLAP\r\n");
412 self->_ap_available =
false;
413 response_state = TWR_ESP8266_STATE_AP_AVAILABILITY_RESPONSE;
415 else if (self->_state == TWR_ESP8266_STATE_SNTP_CONFIG_COMMAND)
417 sprintf(self->_command,
"AT+CIPSNTPCFG=%u,%d,\"%s\",\"%s\",\"%s\"\r\n",
418 self->_config.sntp_enabled,
419 self->_config.sntp_timezone,
420 self->_config.sntp_server1,
421 self->_config.sntp_server2,
422 self->_config.sntp_server3);
423 response_state = TWR_ESP8266_STATE_SNTP_CONFIG_RESPONSE;
425 else if (self->_state == TWR_ESP8266_STATE_SNTP_TIME_COMMAND)
427 strcpy(self->_command,
"AT+CIPSNTPTIME?\r\n");
428 response_state = TWR_ESP8266_STATE_SNTP_TIME_RESPONSE;
430 else if (self->_state == TWR_ESP8266_STATE_SOCKET_CONNECT_COMMAND)
432 strcpy(self->_command,
"AT+CIPSTART=");
433 response_state = TWR_ESP8266_STATE_SOCKET_CONNECT_RESPONSE;
437 sprintf(self->_command,
"AT+CIPSEND=%d\r\n", self->_message_length);
438 response_state = TWR_ESP8266_STATE_SOCKET_SEND_DATA;
441 self->_state = TWR_ESP8266_STATE_ERROR;
443 uint8_t command_length = strlen(self->_command);
444 size_t length = command_length;
446 if (response_state == TWR_ESP8266_STATE_SOCKET_CONNECT_RESPONSE)
448 for (
size_t i = 0; i <
self->_message_length; i++)
451 self->_command[command_length + i] =
self->_message_buffer[i];
453 self->_command[command_length +
self->_message_length] =
'\r';
454 self->_command[command_length +
self->_message_length + 1] =
'\n';
456 length = command_length +
self->_message_length + 2;
464 self->_state = response_state;
465 self->_timeout_cnt = 0;
471 case TWR_ESP8266_STATE_SOCKET_SEND_DATA:
473 self->_state = TWR_ESP8266_STATE_ERROR;
475 if (
twr_uart_async_write(self->_uart_channel, self->_message_buffer, self->_message_length) != self->_message_length)
480 self->_state = TWR_ESP8266_STATE_SOCKET_SEND_RESPONSE;
486 case TWR_ESP8266_STATE_WIFI_CONNECT_RESPONSE:
497 self->_timeout_cnt++;
498 if (self->_timeout_cnt > _TWR_ESP8266_TIMEOUT_WIFI_CONNECT)
500 self->_state = TWR_ESP8266_STATE_WIFI_CONNECT_ERROR;
504 if (!_twr_esp8266_read_response(
self))
510 if (strcmp(self->_response,
"OK\r") == 0)
512 if (self->_config.sntp_enabled)
514 self->_state = TWR_ESP8266_STATE_SNTP_CONFIG_COMMAND;
518 self->_state = TWR_ESP8266_STATE_READY;
519 if (self->_event_handler != NULL)
521 self->_event_handler(
self, TWR_ESP8266_EVENT_WIFI_CONNECT_SUCCESS, self->_event_param);
525 else if (strcmp(self->_response,
"FAIL\r") == 0)
527 self->_state = TWR_ESP8266_STATE_WIFI_CONNECT_ERROR;
537 case TWR_ESP8266_STATE_WIFI_CONNECT_ERROR:
539 self->_state = TWR_ESP8266_STATE_DISCONNECTED;
541 if (self->_event_handler != NULL)
543 self->_event_handler(
self, TWR_ESP8266_EVENT_WIFI_CONNECT_ERROR, self->_event_param);
548 case TWR_ESP8266_STATE_SNTP_CONFIG_RESPONSE:
550 self->_state = TWR_ESP8266_STATE_ERROR;
552 if (!_twr_esp8266_read_response(
self))
557 if (memcmp(self->_response,
"OK", 2) != 0)
562 self->_state = TWR_ESP8266_STATE_SNTP_TIME_COMMAND;
566 case TWR_ESP8266_STATE_SNTP_TIME_RESPONSE:
574 self->_timeout_cnt++;
575 if (self->_timeout_cnt > _TWR_ESP8266_TIMEOUT_SOCKET_CONNECT)
577 self->_state = TWR_ESP8266_STATE_WIFI_CONNECT_ERROR;
581 if (!_twr_esp8266_read_response(
self))
587 if (strcmp(self->_response,
"OK\r") == 0)
589 self->_state = TWR_ESP8266_STATE_READY;
590 if (self->_event_handler != NULL)
592 self->_event_handler(
self, TWR_ESP8266_EVENT_WIFI_CONNECT_SUCCESS, self->_event_param);
595 else if (memcmp(self->_response,
"+CIPSNTPTIME:", 13) == 0)
597 _twr_esp8266_set_rtc_time(self->_response + 13);
607 case TWR_ESP8266_STATE_SOCKET_CONNECT_RESPONSE:
616 self->_timeout_cnt++;
617 if (self->_timeout_cnt > _TWR_ESP8266_TIMEOUT_SOCKET_CONNECT)
619 self->_state = TWR_ESP8266_STATE_SOCKET_CONNECT_ERROR;
623 if (!_twr_esp8266_read_response(
self))
629 if (strcmp(self->_response,
"OK\r") == 0)
631 self->_state = TWR_ESP8266_STATE_READY;
632 if (self->_event_handler != NULL)
634 self->_event_handler(
self, TWR_ESP8266_EVENT_SOCKET_CONNECT_SUCCESS, self->_event_param);
637 else if (strcmp(self->_response,
"ERROR\r") == 0)
639 self->_state = TWR_ESP8266_STATE_SOCKET_CONNECT_ERROR;
649 case TWR_ESP8266_STATE_SOCKET_CONNECT_ERROR:
651 self->_state = TWR_ESP8266_STATE_READY;
653 if (self->_event_handler != NULL)
655 self->_event_handler(
self, TWR_ESP8266_EVENT_SOCKET_CONNECT_ERROR, self->_event_param);
660 case TWR_ESP8266_STATE_SOCKET_SEND_RESPONSE:
662 self->_state = TWR_ESP8266_STATE_SOCKET_SEND_ERROR;
664 if (!_twr_esp8266_read_response(
self))
669 if (strcmp(self->_response,
"OK\r") != 0)
674 self->_state = TWR_ESP8266_STATE_RECEIVE;
676 if (self->_event_handler != NULL)
678 self->_event_handler(
self, TWR_ESP8266_EVENT_SOCKET_SEND_SUCCESS, self->_event_param);
683 case TWR_ESP8266_STATE_SOCKET_SEND_ERROR:
685 self->_state = TWR_ESP8266_STATE_READY;
687 if (self->_event_handler != NULL)
689 self->_event_handler(
self, TWR_ESP8266_EVENT_SOCKET_SEND_ERROR, self->_event_param);
694 case TWR_ESP8266_STATE_SOCKET_RECEIVE:
696 if (!_twr_esp8266_read_socket_data(
self))
701 self->_state = TWR_ESP8266_STATE_READY;
703 if (self->_event_handler != NULL)
705 self->_event_handler(
self, TWR_ESP8266_EVENT_DATA_RECEIVED, self->_event_param);
710 case TWR_ESP8266_STATE_AP_AVAILABILITY_OPT_RESPONSE:
712 if (!_twr_esp8266_read_response(
self) || memcmp(self->_response,
"OK", 2) != 0)
718 self->_state = TWR_ESP8266_STATE_AP_AVAILABILITY_COMMAND;
722 case TWR_ESP8266_STATE_AP_AVAILABILITY_RESPONSE:
731 self->_timeout_cnt++;
732 if (self->_timeout_cnt > _TWR_ESP8266_TIMEOUT_WIFI_CONNECT)
738 if (!_twr_esp8266_read_response(
self))
744 if (strcmp(self->_response,
"OK\r") == 0)
748 if (self->_event_handler != NULL)
750 self->_event_handler(
self, TWR_ESP8266_EVENT_AP_AVAILABILITY_RESULT, self->_event_param);
754 else if (strcmp(self->_response,
"ERROR\r") == 0)
762 sprintf(text,
"+CWLAP:(\"%s\",", self->_config.ssid);
763 size_t text_len = strlen(text);
764 if (strncmp(self->_response, text, text_len) == 0)
766 char *rssi =
self->_response + text_len;
767 char *end = strchr(rssi,
')');
771 self->_rssi = atoi(rssi);
772 self->_ap_available =
true;
792 return self->_message_length;
797 if (self->_message_length > buffer_size)
802 memcpy(buffer, self->_message_buffer, self->_message_length);
804 return self->_message_length;
820 if (rx_character ==
'\n')
825 self->_response[length++] = rx_character;
827 if (rx_character ==
'\r')
836 self->_response[length] =
'\0';
841 if (length ==
sizeof(self->_response) - 1)
850 static bool _twr_esp8266_read_socket_data(
twr_esp8266_t *
self)
861 self->_message_buffer[
self->_message_part_length++] = rx_character;
863 if (self->_message_part_length == self->_message_length)
872 static void _twr_esp8266_set_rtc_time(
char *str)
878 size_t length = strlen(str);
879 for (
size_t i = 0; i <= length; i++)
882 if (c ==
' ' || c ==
':' || c ==
'\0' || j == 4)
889 if (strcmp(token,
"Jan") == 0)
893 else if (strcmp(token,
"Feb") == 0)
897 else if (strcmp(token,
"Mar") == 0)
901 else if (strcmp(token,
"Apr") == 0)
905 else if (strcmp(token,
"May") == 0)
909 else if (strcmp(token,
"Jun") == 0)
913 else if (strcmp(token,
"Jul") == 0)
917 else if (strcmp(token,
"Aug") == 0)
921 else if (strcmp(token,
"Sep") == 0)
925 else if (strcmp(token,
"Oct") == 0)
929 else if (strcmp(token,
"Nov") == 0)
933 else if (strcmp(token,
"Dec") == 0)
941 tm.tm_mday = atoi(token);
946 tm.tm_hour = atoi(token);
951 tm.tm_min = atoi(token);
956 tm.tm_sec = atoi(token);
961 if (strcmp(token,
"1970") == 0)
965 tm.tm_year = atoi(token) - 1900;
981 if (self->_state != TWR_ESP8266_STATE_DISCONNECTED || self->_config.ssid[0] ==
'\0')
986 _twr_esp8266_enable(
self);
988 self->_state = TWR_ESP8266_STATE_INITIALIZE;
989 self->_state_after_init = TWR_ESP8266_STATE_AP_AVAILABILITY_OPT_COMMAND;
998 *available =
self->_ap_available;
1004 strncpy(ssid, self->_config.ssid, 64);
1009 strncpy(self->_config.ssid, ssid, 64);
1014 strncpy(password, self->_config.password, 64);
1019 strncpy(self->_config.password, password, 64);
bool twr_esp8266_connect(twr_esp8266_t *self)
Enable ESP8266 and connect to WiFi.
void twr_esp8266_get_ap_availability(twr_esp8266_t *self, bool *available, int *rssi)
Get AP availability result.
uint32_t twr_esp8266_get_received_message_data(twr_esp8266_t *self, uint8_t *buffer, uint32_t buffer_size)
Get received message data.
uint32_t twr_esp8266_get_received_message_length(twr_esp8266_t *self)
Get length of the received message.
bool twr_esp8266_ssl_connect(twr_esp8266_t *self, const char *host, uint16_t port)
Establish SSL Connection.
void twr_esp8266_get_ssid(twr_esp8266_t *self, char *ssid)
Get SSID.
bool twr_esp8266_udp_connect(twr_esp8266_t *self, const char *host, uint16_t port)
Establish UDP Connection.
void twr_esp8266_set_station_mode(twr_esp8266_t *self, char *ssid, char *password)
Set station mode.
bool twr_esp8266_send_data(twr_esp8266_t *self, const void *buffer, size_t length)
Send data.
bool twr_esp8266_is_ready(twr_esp8266_t *self)
Check if modem is ready for commands.
bool twr_esp8266_disconnect(twr_esp8266_t *self)
Disable ESP8266 and disconnect.
bool twr_esp8266_tcp_connect(twr_esp8266_t *self, const char *host, uint16_t port)
Establish TCP Connection.
void twr_esp8266_init(twr_esp8266_t *self, twr_uart_channel_t uart_channel)
Initialize ESP8266.
void twr_esp8266_set_password(twr_esp8266_t *self, char *password)
Set password.
void twr_esp8266_set_event_handler(twr_esp8266_t *self, void(*event_handler)(twr_esp8266_t *, twr_esp8266_event_t, void *), void *event_param)
Set callback function.
bool twr_esp8266_check_ap_availability(twr_esp8266_t *self)
Check AP availability.
void twr_esp8266_set_sntp(twr_esp8266_t *self, int timezone)
Enable SNTP and set time zone.
void twr_esp8266_get_password(twr_esp8266_t *self, char *password)
Get password.
twr_esp8266_event_t
Callback events.
void twr_esp8266_set_ssid(twr_esp8266_t *self, char *ssid)
Set SSID.
void twr_esp8266_set_sntp_with_servers(twr_esp8266_t *self, int timezone, char *sntp_server1, char *sntp_server2, char *sntp_server3)
Enable SNTP and set configuration.
@ TWR_ESP8266_EVENT_READY
Ready event.
@ TWR_ESP8266_EVENT_ERROR
Error event.
void twr_fifo_init(twr_fifo_t *fifo, void *buffer, size_t size)
Initialize FIFO buffer.
void twr_gpio_set_output(twr_gpio_channel_t channel, int state)
Set output state for GPIO channel.
void twr_gpio_init(twr_gpio_channel_t channel)
Initialize GPIO channel.
void twr_gpio_set_mode(twr_gpio_channel_t channel, twr_gpio_mode_t mode)
Set mode of operation for GPIO channel.
@ TWR_GPIO_MODE_OUTPUT
GPIO channel operates as output.
@ TWR_GPIO_P8
GPIO channel P8.
@ TWR_GPIO_P6
GPIO channel P6.
int twr_rtc_set_datetime(struct tm *tm, int ms)
void twr_scheduler_plan_current_from_now(twr_tick_t tick)
Schedule current task to tick relative from now.
void twr_scheduler_plan_now(twr_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
void twr_scheduler_plan_current_now(void)
Schedule current task for immediate execution.
void twr_scheduler_plan_relative(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to tick relative from current spin.
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
#define TWR_TICK_INFINITY
Maximum timestamp value.
twr_uart_channel_t
UART channels.
void twr_uart_init(twr_uart_channel_t channel, twr_uart_baudrate_t baudrate, twr_uart_setting_t setting)
Initialize UART channel.
size_t twr_uart_async_write(twr_uart_channel_t channel, const void *buffer, size_t length)
Add data to be transmited in async mode.
void twr_uart_set_async_fifo(twr_uart_channel_t channel, twr_fifo_t *write_fifo, twr_fifo_t *read_fifo)
Set buffers for async transfers.
bool twr_uart_async_read_start(twr_uart_channel_t channel, twr_tick_t timeout)
Start async reading.
twr_uart_event_t
Callback events.
void twr_uart_set_event_handler(twr_uart_channel_t channel, void(*event_handler)(twr_uart_channel_t, twr_uart_event_t, void *), void *event_param)
Set callback function.
size_t twr_uart_async_read(twr_uart_channel_t channel, void *buffer, size_t length)
Get data that has been received in async mode.
void twr_uart_deinit(twr_uart_channel_t channel)
Deinitialize UART channel.
@ TWR_UART_EVENT_ASYNC_READ_DATA
Event is reading done.
@ TWR_UART_BAUDRATE_115200
UART baudrat 115200 bps.
@ TWR_UART_SETTING_8N1
8N1: 8 data bits, none parity bit, 1 stop bit