Firmware SDK
twr_esp8266.c
1 #include <twr_esp8266.h>
2 #include <twr_rtc.h>
3 
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
10 
11 // Apply changes to the factory configuration
12 static const char *_esp8266_init_commands[] =
13 {
14  // Disable AT Commands Echoing
15  "ATE0\r\n",
16  // Set Station mode
17  "AT+CWMODE=1\r\n",
18  // Disable Multiple Connections
19  "AT+CIPMUX=0\r\n",
20  // Does not Show the Remote IP and Port with +IPD
21  "AT+CIPDINFO=0\r\n",
22  // Disable Auto-Connect
23  "AT+CWAUTOCONN=0\r\n",
24  // Enable DHCP
25  "AT+CWDHCP=1,1\r\n",
26  // Sets the Size of SSL Buffer
27  "AT+CIPSSLSIZE=4096\r\n",
28  NULL
29 };
30 
31 static void _twr_esp8266_task(void *param);
32 static bool _twr_esp8266_read_response(twr_esp8266_t *self);
33 static bool _twr_esp8266_read_socket_data(twr_esp8266_t *self);
34 static void _uart_event_handler(twr_uart_channel_t channel, twr_uart_event_t event, void *param);
35 static void _twr_esp8266_set_rtc_time(char *str);
36 
38 {
39  memset(self, 0, sizeof(*self));
40 
41  self->_uart_channel = uart_channel;
42 
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;
47 
48  // CH_PD of ESP8266
52 
53  // RESET of ESP8266
57 
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));
60 
61  self->_task_id = twr_scheduler_register(_twr_esp8266_task, self, TWR_TICK_INFINITY);
62  self->_state = TWR_ESP8266_STATE_DISCONNECTED;
63 }
64 
65 static void _uart_event_handler(twr_uart_channel_t channel, twr_uart_event_t event, void *param)
66 {
67  (void) channel;
68  twr_esp8266_t *self = (twr_esp8266_t*)param;
69 
70  if (event == TWR_UART_EVENT_ASYNC_READ_DATA && self->_state == TWR_ESP8266_STATE_IDLE)
71  {
72  twr_scheduler_plan_relative(self->_task_id, 100);
73  self->_state = TWR_ESP8266_STATE_RECEIVE;
74  }
75 }
76 
77 void _twr_esp8266_enable(twr_esp8266_t *self)
78 {
79  // Initialize UART
81  twr_uart_set_async_fifo(self->_uart_channel, &self->_tx_fifo, &self->_rx_fifo);
82  twr_uart_async_read_start(self->_uart_channel, TWR_TICK_INFINITY);
83  twr_uart_set_event_handler(self->_uart_channel, _uart_event_handler, self);
84 
85  // Enable CH_PD
87 }
88 
89 void _twr_esp8266_disable(twr_esp8266_t *self)
90 {
91  // Disable CH_PD
93 
94  // Deinitialize UART
95  twr_uart_deinit(self->_uart_channel);
96 }
97 
98 void twr_esp8266_set_event_handler(twr_esp8266_t *self, void (*event_handler)(twr_esp8266_t *, twr_esp8266_event_t, void *), void *event_param)
99 {
100  self->_event_handler = event_handler;
101  self->_event_param = event_param;
102 }
103 
104 void twr_esp8266_set_station_mode(twr_esp8266_t *self, char *ssid, char *password)
105 {
106  self->_config.mode = TWR_ESP8266_CONFIG_MODE_STATION;
107  strncpy(self->_config.ssid, ssid, 63);
108  strncpy(self->_config.password, password, 63);
109 }
110 
111 void twr_esp8266_set_sntp(twr_esp8266_t *self, int timezone)
112 {
113  twr_esp8266_set_sntp_with_servers(self, timezone, NULL, NULL, NULL);
114 }
115 
116 void twr_esp8266_set_sntp_with_servers(twr_esp8266_t *self, int timezone, char *sntp_server1, char *sntp_server2, char *sntp_server3)
117 {
118  self->_config.sntp_enabled = 1;
119  self->_config.sntp_timezone = timezone;
120  if (sntp_server1 != NULL)
121  {
122  strncpy(self->_config.sntp_server1, sntp_server1, 127);
123  }
124  else
125  {
126  strcpy(self->_config.sntp_server1, "0.pool.ntp.org");
127  }
128  if (sntp_server2 != NULL)
129  {
130  strncpy(self->_config.sntp_server2, sntp_server2, 127);
131  }
132  else
133  {
134  strcpy(self->_config.sntp_server2, "1.pool.ntp.org");
135  }
136  if (sntp_server3 != NULL)
137  {
138  strncpy(self->_config.sntp_server3, sntp_server3, 127);
139  }
140  else
141  {
142  strcpy(self->_config.sntp_server3, "2.pool.ntp.org");
143  }
144 }
145 
147 {
148  if (self->_state == TWR_ESP8266_STATE_READY || self->_state == TWR_ESP8266_STATE_IDLE)
149  {
150  return true;
151  }
152 
153  return false;
154 }
155 
157 {
158  if (self->_state != TWR_ESP8266_STATE_DISCONNECTED ||
159  self->_config.ssid[0] == '\0' || self->_config.password[0] == '\0')
160  {
161  return false;
162  }
163 
164  _twr_esp8266_enable(self);
165 
166  self->_state = TWR_ESP8266_STATE_INITIALIZE;
167  self->_state_after_init = TWR_ESP8266_STATE_WIFI_CONNECT_COMMAND;
168 
169  twr_scheduler_plan_now(self->_task_id);
170 
171  return true;
172 }
173 
175 {
176  _twr_esp8266_disable(self);
177 
178  self->_state = TWR_ESP8266_STATE_DISCONNECTED;
179 
180  if (self->_event_handler != NULL)
181  {
182  self->_event_handler(self, TWR_ESP8266_EVENT_DISCONNECTED, self->_event_param);
183  }
184 
185  return true;
186 }
187 
188 bool twr_esp8266_socket_connect(twr_esp8266_t *self, const char *type, const char *host, uint16_t port)
189 {
190  if (!twr_esp8266_is_ready(self) || host == NULL || port == 0 || strlen(host) == 0 ||
191  (strlen(host) + 15) > TWR_ESP8266_TX_MAX_PACKET_SIZE)
192  {
193  return false;
194  }
195 
196  static char buffer[TWR_ESP8266_TX_MAX_PACKET_SIZE];
197  sprintf(buffer, "\"%s\",\"%s\",%d", type, host, port);
198 
199  self->_message_length = strlen(buffer);
200 
201  memcpy(self->_message_buffer, buffer, self->_message_length);
202 
203  self->_state = TWR_ESP8266_STATE_SOCKET_CONNECT_COMMAND;
204 
205  twr_scheduler_plan_now(self->_task_id);
206 
207  return true;
208 }
209 
210 bool twr_esp8266_tcp_connect(twr_esp8266_t *self, const char *host, uint16_t port)
211 {
212  return twr_esp8266_socket_connect(self, "TCP", host, port);
213 }
214 
215 bool twr_esp8266_udp_connect(twr_esp8266_t *self, const char *host, uint16_t port)
216 {
217  return twr_esp8266_socket_connect(self, "UDP", host, port);
218 }
219 
220 bool twr_esp8266_ssl_connect(twr_esp8266_t *self, const char *host, uint16_t port)
221 {
222  return twr_esp8266_socket_connect(self, "SSL", host, port);
223 }
224 
225 bool twr_esp8266_send_data(twr_esp8266_t *self, const void *buffer, size_t length)
226 {
227  if (!twr_esp8266_is_ready(self) || length == 0 || length > TWR_ESP8266_TX_MAX_PACKET_SIZE)
228  {
229  return false;
230  }
231 
232  self->_message_length = length;
233 
234  memcpy(self->_message_buffer, buffer, self->_message_length);
235 
236  self->_state = TWR_ESP8266_STATE_SOCKET_SEND_COMMAND;
237 
238  twr_scheduler_plan_now(self->_task_id);
239 
240  return true;
241 }
242 
243 static void _twr_esp8266_task(void *param)
244 {
245  twr_esp8266_t *self = param;
246 
247  while (true)
248  {
249  switch (self->_state)
250  {
251  case TWR_ESP8266_STATE_READY:
252  {
253  self->_state = TWR_ESP8266_STATE_IDLE;
254 
255  if (self->_event_handler != NULL)
256  {
257  self->_event_handler(self, TWR_ESP8266_EVENT_READY, self->_event_param);
258  }
259 
260  continue;
261  }
262  case TWR_ESP8266_STATE_IDLE:
263  case TWR_ESP8266_STATE_DISCONNECTED:
264  {
265  return;
266  }
267  case TWR_ESP8266_STATE_RECEIVE:
268  {
269  self->_state = TWR_ESP8266_STATE_IDLE;
270 
271  while (_twr_esp8266_read_response(self))
272  {
273  if (memcmp(self->_response, "+IPD", 4) == 0)
274  {
275  // Data length is between "," and ":"
276  char *comma_search = strchr(self->_response, ',');
277  if (comma_search == NULL)
278  {
279  continue;
280  }
281  comma_search++;
282  char *colon_search = strchr(self->_response, ':');
283  if (colon_search == NULL)
284  {
285  continue;
286  }
287  if ((colon_search - comma_search) > 9)
288  {
289  continue;
290  }
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);
295 
296  self->_message_part_length = (strlen(self->_response) - 1) - (colon_search - self->_response);
297  colon_search++;
298  memcpy(self->_message_buffer, colon_search, self->_message_part_length);
299 
300  if (self->_message_length > sizeof(self->_message_buffer))
301  {
302  self->_message_length = sizeof(self->_message_buffer);
303  }
304 
305  self->_state = TWR_ESP8266_STATE_SOCKET_RECEIVE;
306 
308  return;
309  }
310  }
311 
312  return;
313  }
314  case TWR_ESP8266_STATE_ERROR:
315  {
316  if (self->_event_handler != NULL)
317  {
318  self->_event_handler(self, TWR_ESP8266_EVENT_ERROR, self->_event_param);
319  }
320 
321  self->_state = TWR_ESP8266_STATE_INITIALIZE;
322 
323  continue;
324  }
325  case TWR_ESP8266_STATE_INITIALIZE:
326  {
327  self->_init_command_index = 0;
328  self->_state = TWR_ESP8266_STATE_INITIALIZE_COMMAND_SEND;
329 
330  continue;
331  }
332  case TWR_ESP8266_STATE_INITIALIZE_COMMAND_SEND:
333  {
334  self->_state = TWR_ESP8266_STATE_ERROR;
335 
336  // Purge RX FIFO
337  char rx_character;
338  while (twr_uart_async_read(self->_uart_channel, &rx_character, 1) != 0)
339  {
340  }
341 
342  strcpy(self->_command, _esp8266_init_commands[self->_init_command_index]);
343  size_t length = strlen(self->_command);
344 
345  if (twr_uart_async_write(self->_uart_channel, self->_command, length) != length)
346  {
347  continue;
348  }
349 
350  self->_state = TWR_ESP8266_STATE_INITIALIZE_COMMAND_RESPONSE;
351  twr_scheduler_plan_current_from_now(_TWR_ESP8266_DELAY_INITIALIZATION_AT_COMMAND);
352 
353  return;
354  }
355  case TWR_ESP8266_STATE_INITIALIZE_COMMAND_RESPONSE:
356  {
357  self->_state = TWR_ESP8266_STATE_ERROR;
358 
359  if (!_twr_esp8266_read_response(self))
360  {
361  continue;
362  }
363 
364  // repeated command, continue reading response
365  if (memcmp(self->_response, "AT", 2) == 0 && !_twr_esp8266_read_response(self))
366  {
367  continue;
368  }
369 
370  if (memcmp(self->_response, "OK", 2) != 0)
371  {
372  continue;
373  }
374 
375  self->_init_command_index++;
376 
377  if (_esp8266_init_commands[self->_init_command_index] == NULL)
378  {
379  self->_state = self->_state_after_init;
380  }
381  else
382  {
383  self->_state = TWR_ESP8266_STATE_INITIALIZE_COMMAND_SEND;
384  }
385 
386  continue;
387  }
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:
395  {
396  twr_esp8266_state_t response_state;
397 
398  if (self->_state == TWR_ESP8266_STATE_WIFI_CONNECT_COMMAND)
399  {
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;
402  }
403  else if (self->_state == TWR_ESP8266_STATE_AP_AVAILABILITY_OPT_COMMAND)
404  {
405  strcpy(self->_command, "AT+CWLAPOPT=1,6\r\n");
406  response_state = TWR_ESP8266_STATE_AP_AVAILABILITY_OPT_RESPONSE;
407  }
408  else if (self->_state == TWR_ESP8266_STATE_AP_AVAILABILITY_COMMAND)
409  {
410  strcpy(self->_command, "AT+CWLAP\r\n");
411  self->_rssi = 0;
412  self->_ap_available = false;
413  response_state = TWR_ESP8266_STATE_AP_AVAILABILITY_RESPONSE;
414  }
415  else if (self->_state == TWR_ESP8266_STATE_SNTP_CONFIG_COMMAND)
416  {
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;
424  }
425  else if (self->_state == TWR_ESP8266_STATE_SNTP_TIME_COMMAND)
426  {
427  strcpy(self->_command, "AT+CIPSNTPTIME?\r\n");
428  response_state = TWR_ESP8266_STATE_SNTP_TIME_RESPONSE;
429  }
430  else if (self->_state == TWR_ESP8266_STATE_SOCKET_CONNECT_COMMAND)
431  {
432  strcpy(self->_command, "AT+CIPSTART=");
433  response_state = TWR_ESP8266_STATE_SOCKET_CONNECT_RESPONSE;
434  }
435  else
436  {
437  sprintf(self->_command, "AT+CIPSEND=%d\r\n", self->_message_length);
438  response_state = TWR_ESP8266_STATE_SOCKET_SEND_DATA;
439  }
440 
441  self->_state = TWR_ESP8266_STATE_ERROR;
442 
443  uint8_t command_length = strlen(self->_command);
444  size_t length = command_length;
445 
446  if (response_state == TWR_ESP8266_STATE_SOCKET_CONNECT_RESPONSE)
447  {
448  for (size_t i = 0; i < self->_message_length; i++)
449  {
450  // put binary data directly to the "string" buffer
451  self->_command[command_length + i] = self->_message_buffer[i];
452  }
453  self->_command[command_length + self->_message_length] = '\r';
454  self->_command[command_length + self->_message_length + 1] = '\n';
455 
456  length = command_length + self->_message_length + 2;
457  }
458 
459  if (twr_uart_async_write(self->_uart_channel, self->_command, length) != length)
460  {
461  continue;
462  }
463 
464  self->_state = response_state;
465  self->_timeout_cnt = 0;
466 
467  twr_scheduler_plan_current_from_now(_TWR_ESP8266_DELAY_SEND_RESPONSE);
468 
469  return;
470  }
471  case TWR_ESP8266_STATE_SOCKET_SEND_DATA:
472  {
473  self->_state = TWR_ESP8266_STATE_ERROR;
474 
475  if (twr_uart_async_write(self->_uart_channel, self->_message_buffer, self->_message_length) != self->_message_length)
476  {
477  continue;
478  }
479 
480  self->_state = TWR_ESP8266_STATE_SOCKET_SEND_RESPONSE;
481 
482  twr_scheduler_plan_current_from_now(_TWR_ESP8266_DELAY_SEND_RESPONSE);
483 
484  return;
485  }
486  case TWR_ESP8266_STATE_WIFI_CONNECT_RESPONSE:
487  {
488  /*
489  Success response:
490  WIFI DISCONNECT
491  WIFI CONNECTED
492  WIFI GOT IP
493 
494  OK
495  */
496 
497  self->_timeout_cnt++;
498  if (self->_timeout_cnt > _TWR_ESP8266_TIMEOUT_WIFI_CONNECT)
499  {
500  self->_state = TWR_ESP8266_STATE_WIFI_CONNECT_ERROR;
501  continue;
502  }
503 
504  if (!_twr_esp8266_read_response(self))
505  {
506  twr_scheduler_plan_current_from_now(_TWR_ESP8266_DELAY_WIFI_CONNECT);
507  return;
508  }
509 
510  if (strcmp(self->_response, "OK\r") == 0)
511  {
512  if (self->_config.sntp_enabled)
513  {
514  self->_state = TWR_ESP8266_STATE_SNTP_CONFIG_COMMAND;
515  }
516  else
517  {
518  self->_state = TWR_ESP8266_STATE_READY;
519  if (self->_event_handler != NULL)
520  {
521  self->_event_handler(self, TWR_ESP8266_EVENT_WIFI_CONNECT_SUCCESS, self->_event_param);
522  }
523  }
524  }
525  else if (strcmp(self->_response, "FAIL\r") == 0)
526  {
527  self->_state = TWR_ESP8266_STATE_WIFI_CONNECT_ERROR;
528  }
529  else
530  {
531  twr_scheduler_plan_current_from_now(_TWR_ESP8266_DELAY_WIFI_CONNECT);
532  return;
533  }
534 
535  continue;
536  }
537  case TWR_ESP8266_STATE_WIFI_CONNECT_ERROR:
538  {
539  self->_state = TWR_ESP8266_STATE_DISCONNECTED;
540 
541  if (self->_event_handler != NULL)
542  {
543  self->_event_handler(self, TWR_ESP8266_EVENT_WIFI_CONNECT_ERROR, self->_event_param);
544  }
545 
546  continue;
547  }
548  case TWR_ESP8266_STATE_SNTP_CONFIG_RESPONSE:
549  {
550  self->_state = TWR_ESP8266_STATE_ERROR;
551 
552  if (!_twr_esp8266_read_response(self))
553  {
554  continue;
555  }
556 
557  if (memcmp(self->_response, "OK", 2) != 0)
558  {
559  continue;
560  }
561 
562  self->_state = TWR_ESP8266_STATE_SNTP_TIME_COMMAND;
563 
564  continue;
565  }
566  case TWR_ESP8266_STATE_SNTP_TIME_RESPONSE:
567  {
568  /*
569  Success response:
570  +CIPSNTPTIME:Sun Jul 21 12:02:06 2019
571  OK
572  */
573 
574  self->_timeout_cnt++;
575  if (self->_timeout_cnt > _TWR_ESP8266_TIMEOUT_SOCKET_CONNECT)
576  {
577  self->_state = TWR_ESP8266_STATE_WIFI_CONNECT_ERROR;
578  continue;
579  }
580 
581  if (!_twr_esp8266_read_response(self))
582  {
583  twr_scheduler_plan_current_from_now(_TWR_ESP8266_DELAY_SOCKET_CONNECT);
584  return;
585  }
586 
587  if (strcmp(self->_response, "OK\r") == 0)
588  {
589  self->_state = TWR_ESP8266_STATE_READY;
590  if (self->_event_handler != NULL)
591  {
592  self->_event_handler(self, TWR_ESP8266_EVENT_WIFI_CONNECT_SUCCESS, self->_event_param);
593  }
594  }
595  else if (memcmp(self->_response, "+CIPSNTPTIME:", 13) == 0)
596  {
597  _twr_esp8266_set_rtc_time(self->_response + 13);
598  }
599  else
600  {
601  twr_scheduler_plan_current_from_now(_TWR_ESP8266_DELAY_SOCKET_CONNECT);
602  return;
603  }
604 
605  continue;
606  }
607  case TWR_ESP8266_STATE_SOCKET_CONNECT_RESPONSE:
608  {
609  /*
610  Success response:
611  CONNECT
612 
613  OK
614  */
615 
616  self->_timeout_cnt++;
617  if (self->_timeout_cnt > _TWR_ESP8266_TIMEOUT_SOCKET_CONNECT)
618  {
619  self->_state = TWR_ESP8266_STATE_SOCKET_CONNECT_ERROR;
620  continue;
621  }
622 
623  if (!_twr_esp8266_read_response(self))
624  {
625  twr_scheduler_plan_current_from_now(_TWR_ESP8266_DELAY_SOCKET_CONNECT);
626  return;
627  }
628 
629  if (strcmp(self->_response, "OK\r") == 0)
630  {
631  self->_state = TWR_ESP8266_STATE_READY;
632  if (self->_event_handler != NULL)
633  {
634  self->_event_handler(self, TWR_ESP8266_EVENT_SOCKET_CONNECT_SUCCESS, self->_event_param);
635  }
636  }
637  else if (strcmp(self->_response, "ERROR\r") == 0)
638  {
639  self->_state = TWR_ESP8266_STATE_SOCKET_CONNECT_ERROR;
640  }
641  else
642  {
643  twr_scheduler_plan_current_from_now(_TWR_ESP8266_DELAY_SOCKET_CONNECT);
644  return;
645  }
646 
647  continue;
648  }
649  case TWR_ESP8266_STATE_SOCKET_CONNECT_ERROR:
650  {
651  self->_state = TWR_ESP8266_STATE_READY;
652 
653  if (self->_event_handler != NULL)
654  {
655  self->_event_handler(self, TWR_ESP8266_EVENT_SOCKET_CONNECT_ERROR, self->_event_param);
656  }
657 
658  continue;
659  }
660  case TWR_ESP8266_STATE_SOCKET_SEND_RESPONSE:
661  {
662  self->_state = TWR_ESP8266_STATE_SOCKET_SEND_ERROR;
663 
664  if (!_twr_esp8266_read_response(self))
665  {
666  continue;
667  }
668 
669  if (strcmp(self->_response, "OK\r") != 0)
670  {
671  continue;
672  }
673 
674  self->_state = TWR_ESP8266_STATE_RECEIVE;
675 
676  if (self->_event_handler != NULL)
677  {
678  self->_event_handler(self, TWR_ESP8266_EVENT_SOCKET_SEND_SUCCESS, self->_event_param);
679  }
680 
681  continue;
682  }
683  case TWR_ESP8266_STATE_SOCKET_SEND_ERROR:
684  {
685  self->_state = TWR_ESP8266_STATE_READY;
686 
687  if (self->_event_handler != NULL)
688  {
689  self->_event_handler(self, TWR_ESP8266_EVENT_SOCKET_SEND_ERROR, self->_event_param);
690  }
691 
692  continue;
693  }
694  case TWR_ESP8266_STATE_SOCKET_RECEIVE:
695  {
696  if (!_twr_esp8266_read_socket_data(self))
697  {
698  continue;
699  }
700 
701  self->_state = TWR_ESP8266_STATE_READY;
702 
703  if (self->_event_handler != NULL)
704  {
705  self->_event_handler(self, TWR_ESP8266_EVENT_DATA_RECEIVED, self->_event_param);
706  }
707 
708  continue;
709  }
710  case TWR_ESP8266_STATE_AP_AVAILABILITY_OPT_RESPONSE:
711  {
712  if (!_twr_esp8266_read_response(self) || memcmp(self->_response, "OK", 2) != 0)
713  {
715  return;
716  }
717 
718  self->_state = TWR_ESP8266_STATE_AP_AVAILABILITY_COMMAND;
719 
720  continue;
721  }
722  case TWR_ESP8266_STATE_AP_AVAILABILITY_RESPONSE:
723  {
724  /*
725  Success response:
726  +CWLAP:("Internet_7E",-74)
727  +CWLAP:("WLAN1-R87LDH",-77)
728  OK
729  */
730 
731  self->_timeout_cnt++;
732  if (self->_timeout_cnt > _TWR_ESP8266_TIMEOUT_WIFI_CONNECT)
733  {
735  return;
736  }
737 
738  if (!_twr_esp8266_read_response(self))
739  {
740  twr_scheduler_plan_current_from_now(_TWR_ESP8266_DELAY_WIFI_CONNECT);
741  return;
742  }
743 
744  if (strcmp(self->_response, "OK\r") == 0)
745  {
747 
748  if (self->_event_handler != NULL)
749  {
750  self->_event_handler(self, TWR_ESP8266_EVENT_AP_AVAILABILITY_RESULT, self->_event_param);
751  }
752  return;
753  }
754  else if (strcmp(self->_response, "ERROR\r") == 0)
755  {
757  return;
758  }
759  else
760  {
761  char text[76];
762  sprintf(text, "+CWLAP:(\"%s\",", self->_config.ssid);
763  size_t text_len = strlen(text);
764  if (strncmp(self->_response, text, text_len) == 0)
765  {
766  char *rssi = self->_response + text_len;
767  char *end = strchr(rssi, ')');
768  if (end != NULL)
769  {
770  end[0] = '\0';
771  self->_rssi = atoi(rssi);
772  self->_ap_available = true;
773  }
774  }
775 
776  twr_scheduler_plan_current_from_now(_TWR_ESP8266_DELAY_WIFI_CONNECT);
777  return;
778  }
779 
780  continue;
781  }
782  default:
783  {
784  break;
785  }
786  }
787  }
788 }
789 
791 {
792  return self->_message_length;
793 }
794 
795 uint32_t twr_esp8266_get_received_message_data(twr_esp8266_t *self, uint8_t *buffer, uint32_t buffer_size)
796 {
797  if (self->_message_length > buffer_size)
798  {
799  return 0;
800  }
801 
802  memcpy(buffer, self->_message_buffer, self->_message_length);
803 
804  return self->_message_length;
805 }
806 
807 static bool _twr_esp8266_read_response(twr_esp8266_t *self)
808 {
809  size_t length = 0;
810 
811  while (true)
812  {
813  char rx_character;
814 
815  if (twr_uart_async_read(self->_uart_channel, &rx_character, 1) == 0)
816  {
817  return false;
818  }
819 
820  if (rx_character == '\n')
821  {
822  continue;
823  }
824 
825  self->_response[length++] = rx_character;
826 
827  if (rx_character == '\r')
828  {
829  if (length == 1)
830  {
831  length = 0;
832 
833  continue;
834  }
835 
836  self->_response[length] = '\0';
837 
838  break;
839  }
840 
841  if (length == sizeof(self->_response) - 1)
842  {
843  return false;
844  }
845  }
846 
847  return true;
848 }
849 
850 static bool _twr_esp8266_read_socket_data(twr_esp8266_t *self)
851 {
852  while (true)
853  {
854  char rx_character;
855 
856  if (twr_uart_async_read(self->_uart_channel, &rx_character, 1) == 0)
857  {
858  return false;
859  }
860 
861  self->_message_buffer[self->_message_part_length++] = rx_character;
862 
863  if (self->_message_part_length == self->_message_length)
864  {
865  break;
866  }
867  }
868 
869  return true;
870 }
871 
872 static void _twr_esp8266_set_rtc_time(char *str)
873 {
874  struct tm tm;
875  char token[5];
876  uint8_t j = 0;
877  uint8_t state = 0;
878  size_t length = strlen(str);
879  for (size_t i = 0; i <= length; i++)
880  {
881  char c = str[i];
882  if (c == ' ' || c == ':' || c == '\0' || j == 4)
883  {
884  token[j] = '\0';
885 
886  // Month
887  if (state == 1)
888  {
889  if (strcmp(token, "Jan") == 0)
890  {
891  tm.tm_mon = 0;
892  }
893  else if (strcmp(token, "Feb") == 0)
894  {
895  tm.tm_mon = 1;
896  }
897  else if (strcmp(token, "Mar") == 0)
898  {
899  tm.tm_mon = 2;
900  }
901  else if (strcmp(token, "Apr") == 0)
902  {
903  tm.tm_mon = 3;
904  }
905  else if (strcmp(token, "May") == 0)
906  {
907  tm.tm_mon = 4;
908  }
909  else if (strcmp(token, "Jun") == 0)
910  {
911  tm.tm_mon = 5;
912  }
913  else if (strcmp(token, "Jul") == 0)
914  {
915  tm.tm_mon = 6;
916  }
917  else if (strcmp(token, "Aug") == 0)
918  {
919  tm.tm_mon = 7;
920  }
921  else if (strcmp(token, "Sep") == 0)
922  {
923  tm.tm_mon = 8;
924  }
925  else if (strcmp(token, "Oct") == 0)
926  {
927  tm.tm_mon = 9;
928  }
929  else if (strcmp(token, "Nov") == 0)
930  {
931  tm.tm_mon = 10;
932  }
933  else if (strcmp(token, "Dec") == 0)
934  {
935  tm.tm_mon = 11;
936  }
937  }
938  // Day
939  else if (state == 2)
940  {
941  tm.tm_mday = atoi(token);
942  }
943  // Hours
944  else if (state == 3)
945  {
946  tm.tm_hour = atoi(token);
947  }
948  // Minutes
949  else if (state == 4)
950  {
951  tm.tm_min = atoi(token);
952  }
953  // Seconds
954  else if (state == 5)
955  {
956  tm.tm_sec = atoi(token);
957  }
958  // Year
959  else if (state == 6)
960  {
961  if (strcmp(token, "1970") == 0)
962  {
963  return;
964  }
965  tm.tm_year = atoi(token) - 1900;
966  }
967 
968  j = 0;
969  state++;
970  }
971  else
972  {
973  token[j++] = c;
974  }
975  }
976  twr_rtc_set_datetime(&tm, 0);
977 }
978 
980 {
981  if (self->_state != TWR_ESP8266_STATE_DISCONNECTED || self->_config.ssid[0] == '\0')
982  {
983  return false;
984  }
985 
986  _twr_esp8266_enable(self);
987 
988  self->_state = TWR_ESP8266_STATE_INITIALIZE;
989  self->_state_after_init = TWR_ESP8266_STATE_AP_AVAILABILITY_OPT_COMMAND;
990 
991  twr_scheduler_plan_now(self->_task_id);
992 
993  return true;
994 }
995 
996 void twr_esp8266_get_ap_availability(twr_esp8266_t *self, bool *available, int *rssi)
997 {
998  *available = self->_ap_available;
999  *rssi = self->_rssi;
1000 }
1001 
1002 void twr_esp8266_get_ssid(twr_esp8266_t *self, char *ssid)
1003 {
1004  strncpy(ssid, self->_config.ssid, 64);
1005 }
1006 
1007 void twr_esp8266_set_ssid(twr_esp8266_t *self, char *ssid)
1008 {
1009  strncpy(self->_config.ssid, ssid, 64);
1010 }
1011 
1012 void twr_esp8266_get_password(twr_esp8266_t *self, char *password)
1013 {
1014  strncpy(password, self->_config.password, 64);
1015 }
1016 
1017 void twr_esp8266_set_password(twr_esp8266_t *self, char *password)
1018 {
1019  strncpy(self->_config.password, password, 64);
1020 }
bool twr_esp8266_connect(twr_esp8266_t *self)
Enable ESP8266 and connect to WiFi.
Definition: twr_esp8266.c:156
void twr_esp8266_get_ap_availability(twr_esp8266_t *self, bool *available, int *rssi)
Get AP availability result.
Definition: twr_esp8266.c:996
uint32_t twr_esp8266_get_received_message_data(twr_esp8266_t *self, uint8_t *buffer, uint32_t buffer_size)
Get received message data.
Definition: twr_esp8266.c:795
uint32_t twr_esp8266_get_received_message_length(twr_esp8266_t *self)
Get length of the received message.
Definition: twr_esp8266.c:790
bool twr_esp8266_ssl_connect(twr_esp8266_t *self, const char *host, uint16_t port)
Establish SSL Connection.
Definition: twr_esp8266.c:220
void twr_esp8266_get_ssid(twr_esp8266_t *self, char *ssid)
Get SSID.
Definition: twr_esp8266.c:1002
bool twr_esp8266_udp_connect(twr_esp8266_t *self, const char *host, uint16_t port)
Establish UDP Connection.
Definition: twr_esp8266.c:215
void twr_esp8266_set_station_mode(twr_esp8266_t *self, char *ssid, char *password)
Set station mode.
Definition: twr_esp8266.c:104
bool twr_esp8266_send_data(twr_esp8266_t *self, const void *buffer, size_t length)
Send data.
Definition: twr_esp8266.c:225
bool twr_esp8266_is_ready(twr_esp8266_t *self)
Check if modem is ready for commands.
Definition: twr_esp8266.c:146
bool twr_esp8266_disconnect(twr_esp8266_t *self)
Disable ESP8266 and disconnect.
Definition: twr_esp8266.c:174
bool twr_esp8266_tcp_connect(twr_esp8266_t *self, const char *host, uint16_t port)
Establish TCP Connection.
Definition: twr_esp8266.c:210
void twr_esp8266_init(twr_esp8266_t *self, twr_uart_channel_t uart_channel)
Initialize ESP8266.
Definition: twr_esp8266.c:37
void twr_esp8266_set_password(twr_esp8266_t *self, char *password)
Set password.
Definition: twr_esp8266.c:1017
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.
Definition: twr_esp8266.c:98
bool twr_esp8266_check_ap_availability(twr_esp8266_t *self)
Check AP availability.
Definition: twr_esp8266.c:979
void twr_esp8266_set_sntp(twr_esp8266_t *self, int timezone)
Enable SNTP and set time zone.
Definition: twr_esp8266.c:111
void twr_esp8266_get_password(twr_esp8266_t *self, char *password)
Get password.
Definition: twr_esp8266.c:1012
twr_esp8266_event_t
Callback events.
Definition: twr_esp8266.h:24
void twr_esp8266_set_ssid(twr_esp8266_t *self, char *ssid)
Set SSID.
Definition: twr_esp8266.c:1007
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.
Definition: twr_esp8266.c:116
@ TWR_ESP8266_EVENT_READY
Ready event.
Definition: twr_esp8266.h:26
@ TWR_ESP8266_EVENT_ERROR
Error event.
Definition: twr_esp8266.h:29
void twr_fifo_init(twr_fifo_t *fifo, void *buffer, size_t size)
Initialize FIFO buffer.
Definition: twr_fifo.c:4
void twr_gpio_set_output(twr_gpio_channel_t channel, int state)
Set output state for GPIO channel.
Definition: twr_gpio.c:471
void twr_gpio_init(twr_gpio_channel_t channel)
Initialize GPIO channel.
Definition: twr_gpio.c:325
void twr_gpio_set_mode(twr_gpio_channel_t channel, twr_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: twr_gpio.c:367
@ TWR_GPIO_MODE_OUTPUT
GPIO channel operates as output.
Definition: twr_gpio.h:108
@ TWR_GPIO_P8
GPIO channel P8.
Definition: twr_gpio.h:39
@ TWR_GPIO_P6
GPIO channel P6.
Definition: twr_gpio.h:33
int twr_rtc_set_datetime(struct tm *tm, int ms)
Definition: twr_rtc.c:270
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.
Definition: twr_scheduler.c:53
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
twr_uart_channel_t
UART channels.
Definition: twr_uart.h:14
void twr_uart_init(twr_uart_channel_t channel, twr_uart_baudrate_t baudrate, twr_uart_setting_t setting)
Initialize UART channel.
Definition: twr_uart.c:54
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.
Definition: twr_uart.c:418
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.
Definition: twr_uart.c:412
bool twr_uart_async_read_start(twr_uart_channel_t channel, twr_tick_t timeout)
Start async reading.
Definition: twr_uart.c:465
twr_uart_event_t
Callback events.
Definition: twr_uart.h:128
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.
Definition: twr_uart.c:406
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.
Definition: twr_uart.c:561
void twr_uart_deinit(twr_uart_channel_t channel)
Deinitialize UART channel.
Definition: twr_uart.c:237
@ TWR_UART_EVENT_ASYNC_READ_DATA
Event is reading done.
Definition: twr_uart.h:133
@ TWR_UART_BAUDRATE_115200
UART baudrat 115200 bps.
Definition: twr_uart.h:43
@ TWR_UART_SETTING_8N1
8N1: 8 data bits, none parity bit, 1 stop bit
Definition: twr_uart.h:70