Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_esp8266.c
1 #include <bc_esp8266.h>
2 #include <bc_rtc.h>
3 
4 #define _BC_ESP8266_DELAY_INITIALIZATION_AT_COMMAND 100
5 #define _BC_ESP8266_DELAY_SEND_RESPONSE 100
6 #define _BC_ESP8266_DELAY_WIFI_CONNECT 1000
7 #define _BC_ESP8266_DELAY_SOCKET_CONNECT 300
8 #define _BC_ESP8266_TIMEOUT_WIFI_CONNECT 20
9 #define _BC_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 _bc_esp8266_task(void *param);
32 static bool _bc_esp8266_read_response(bc_esp8266_t *self);
33 static bool _bc_esp8266_read_socket_data(bc_esp8266_t *self);
34 static void _uart_event_handler(bc_uart_channel_t channel, bc_uart_event_t event, void *param);
35 static void _bc_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 = BC_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  bc_fifo_init(&self->_tx_fifo, self->_tx_fifo_buffer, sizeof(self->_tx_fifo_buffer));
59  bc_fifo_init(&self->_rx_fifo, self->_rx_fifo_buffer, sizeof(self->_rx_fifo_buffer));
60 
61  self->_task_id = bc_scheduler_register(_bc_esp8266_task, self, BC_TICK_INFINITY);
62  self->_state = BC_ESP8266_STATE_DISCONNECTED;
63 }
64 
65 static void _uart_event_handler(bc_uart_channel_t channel, bc_uart_event_t event, void *param)
66 {
67  (void) channel;
68  bc_esp8266_t *self = (bc_esp8266_t*)param;
69 
70  if (event == BC_UART_EVENT_ASYNC_READ_DATA && self->_state == BC_ESP8266_STATE_IDLE)
71  {
72  bc_scheduler_plan_relative(self->_task_id, 100);
73  self->_state = BC_ESP8266_STATE_RECEIVE;
74  }
75 }
76 
77 void _bc_esp8266_enable(bc_esp8266_t *self)
78 {
79  // Initialize UART
81  bc_uart_set_async_fifo(self->_uart_channel, &self->_tx_fifo, &self->_rx_fifo);
82  bc_uart_async_read_start(self->_uart_channel, BC_TICK_INFINITY);
83  bc_uart_set_event_handler(self->_uart_channel, _uart_event_handler, self);
84 
85  // Enable CH_PD
87 }
88 
89 void _bc_esp8266_disable(bc_esp8266_t *self)
90 {
91  // Disable CH_PD
93 
94  // Deinitialize UART
95  bc_uart_deinit(self->_uart_channel);
96 }
97 
98 void bc_esp8266_set_event_handler(bc_esp8266_t *self, void (*event_handler)(bc_esp8266_t *, bc_esp8266_event_t, void *), void *event_param)
99 {
100  self->_event_handler = event_handler;
101  self->_event_param = event_param;
102 }
103 
104 void bc_esp8266_set_station_mode(bc_esp8266_t *self, char *ssid, char *password)
105 {
106  self->_config.mode = BC_ESP8266_CONFIG_MODE_STATION;
107  strncpy(self->_config.ssid, ssid, 63);
108  strncpy(self->_config.password, password, 63);
109 }
110 
111 void bc_esp8266_set_sntp(bc_esp8266_t *self, int timezone)
112 {
113  bc_esp8266_set_sntp_with_servers(self, timezone, NULL, NULL, NULL);
114 }
115 
116 void bc_esp8266_set_sntp_with_servers(bc_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 == BC_ESP8266_STATE_READY || self->_state == BC_ESP8266_STATE_IDLE)
149  {
150  return true;
151  }
152 
153  return false;
154 }
155 
157 {
158  if (self->_state != BC_ESP8266_STATE_DISCONNECTED ||
159  self->_config.ssid[0] == '\0' || self->_config.password[0] == '\0')
160  {
161  return false;
162  }
163 
164  _bc_esp8266_enable(self);
165 
166  self->_state = BC_ESP8266_STATE_INITIALIZE;
167  self->_state_after_init = BC_ESP8266_STATE_WIFI_CONNECT_COMMAND;
168 
169  bc_scheduler_plan_now(self->_task_id);
170 
171  return true;
172 }
173 
175 {
176  _bc_esp8266_disable(self);
177 
178  self->_state = BC_ESP8266_STATE_DISCONNECTED;
179 
180  if (self->_event_handler != NULL)
181  {
182  self->_event_handler(self, BC_ESP8266_EVENT_DISCONNECTED, self->_event_param);
183  }
184 
185  return true;
186 }
187 
188 bool bc_esp8266_socket_connect(bc_esp8266_t *self, const char *type, const char *host, uint16_t port)
189 {
190  if (!bc_esp8266_is_ready(self) || host == NULL || port == 0 || strlen(host) == 0 ||
191  (strlen(host) + 15) > BC_ESP8266_TX_MAX_PACKET_SIZE)
192  {
193  return false;
194  }
195 
196  static char buffer[BC_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 = BC_ESP8266_STATE_SOCKET_CONNECT_COMMAND;
204 
205  bc_scheduler_plan_now(self->_task_id);
206 
207  return true;
208 }
209 
210 bool bc_esp8266_tcp_connect(bc_esp8266_t *self, const char *host, uint16_t port)
211 {
212  return bc_esp8266_socket_connect(self, "TCP", host, port);
213 }
214 
215 bool bc_esp8266_udp_connect(bc_esp8266_t *self, const char *host, uint16_t port)
216 {
217  return bc_esp8266_socket_connect(self, "UDP", host, port);
218 }
219 
220 bool bc_esp8266_ssl_connect(bc_esp8266_t *self, const char *host, uint16_t port)
221 {
222  return bc_esp8266_socket_connect(self, "SSL", host, port);
223 }
224 
225 bool bc_esp8266_send_data(bc_esp8266_t *self, const void *buffer, size_t length)
226 {
227  if (!bc_esp8266_is_ready(self) || length == 0 || length > BC_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 = BC_ESP8266_STATE_SOCKET_SEND_COMMAND;
237 
238  bc_scheduler_plan_now(self->_task_id);
239 
240  return true;
241 }
242 
243 static void _bc_esp8266_task(void *param)
244 {
245  bc_esp8266_t *self = param;
246 
247  while (true)
248  {
249  switch (self->_state)
250  {
251  case BC_ESP8266_STATE_READY:
252  {
253  self->_state = BC_ESP8266_STATE_IDLE;
254 
255  if (self->_event_handler != NULL)
256  {
257  self->_event_handler(self, BC_ESP8266_EVENT_READY, self->_event_param);
258  }
259 
260  continue;
261  }
262  case BC_ESP8266_STATE_IDLE:
263  case BC_ESP8266_STATE_DISCONNECTED:
264  {
265  return;
266  }
267  case BC_ESP8266_STATE_RECEIVE:
268  {
269  self->_state = BC_ESP8266_STATE_IDLE;
270 
271  while (_bc_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 = BC_ESP8266_STATE_SOCKET_RECEIVE;
306 
308  return;
309  }
310  }
311 
312  return;
313  }
314  case BC_ESP8266_STATE_ERROR:
315  {
316  if (self->_event_handler != NULL)
317  {
318  self->_event_handler(self, BC_ESP8266_EVENT_ERROR, self->_event_param);
319  }
320 
321  self->_state = BC_ESP8266_STATE_INITIALIZE;
322 
323  continue;
324  }
325  case BC_ESP8266_STATE_INITIALIZE:
326  {
327  self->_init_command_index = 0;
328  self->_state = BC_ESP8266_STATE_INITIALIZE_COMMAND_SEND;
329 
330  continue;
331  }
332  case BC_ESP8266_STATE_INITIALIZE_COMMAND_SEND:
333  {
334  self->_state = BC_ESP8266_STATE_ERROR;
335 
336  // Purge RX FIFO
337  char rx_character;
338  while (bc_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 (bc_uart_async_write(self->_uart_channel, self->_command, length) != length)
346  {
347  continue;
348  }
349 
350  self->_state = BC_ESP8266_STATE_INITIALIZE_COMMAND_RESPONSE;
351  bc_scheduler_plan_current_from_now(_BC_ESP8266_DELAY_INITIALIZATION_AT_COMMAND);
352 
353  return;
354  }
355  case BC_ESP8266_STATE_INITIALIZE_COMMAND_RESPONSE:
356  {
357  self->_state = BC_ESP8266_STATE_ERROR;
358 
359  if (!_bc_esp8266_read_response(self))
360  {
361  continue;
362  }
363 
364  // repeated command, continue reading response
365  if (memcmp(self->_response, "AT", 2) == 0 && !_bc_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 = BC_ESP8266_STATE_INITIALIZE_COMMAND_SEND;
384  }
385 
386  continue;
387  }
388  case BC_ESP8266_STATE_WIFI_CONNECT_COMMAND:
389  case BC_ESP8266_STATE_AP_AVAILABILITY_OPT_COMMAND:
390  case BC_ESP8266_STATE_AP_AVAILABILITY_COMMAND:
391  case BC_ESP8266_STATE_SNTP_CONFIG_COMMAND:
392  case BC_ESP8266_STATE_SNTP_TIME_COMMAND:
393  case BC_ESP8266_STATE_SOCKET_CONNECT_COMMAND:
394  case BC_ESP8266_STATE_SOCKET_SEND_COMMAND:
395  {
396  bc_esp8266_state_t response_state;
397 
398  if (self->_state == BC_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 = BC_ESP8266_STATE_WIFI_CONNECT_RESPONSE;
402  }
403  else if (self->_state == BC_ESP8266_STATE_AP_AVAILABILITY_OPT_COMMAND)
404  {
405  strcpy(self->_command, "AT+CWLAPOPT=1,6\r\n");
406  response_state = BC_ESP8266_STATE_AP_AVAILABILITY_OPT_RESPONSE;
407  }
408  else if (self->_state == BC_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 = BC_ESP8266_STATE_AP_AVAILABILITY_RESPONSE;
414  }
415  else if (self->_state == BC_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 = BC_ESP8266_STATE_SNTP_CONFIG_RESPONSE;
424  }
425  else if (self->_state == BC_ESP8266_STATE_SNTP_TIME_COMMAND)
426  {
427  strcpy(self->_command, "AT+CIPSNTPTIME?\r\n");
428  response_state = BC_ESP8266_STATE_SNTP_TIME_RESPONSE;
429  }
430  else if (self->_state == BC_ESP8266_STATE_SOCKET_CONNECT_COMMAND)
431  {
432  strcpy(self->_command, "AT+CIPSTART=");
433  response_state = BC_ESP8266_STATE_SOCKET_CONNECT_RESPONSE;
434  }
435  else
436  {
437  sprintf(self->_command, "AT+CIPSEND=%d\r\n", self->_message_length);
438  response_state = BC_ESP8266_STATE_SOCKET_SEND_DATA;
439  }
440 
441  self->_state = BC_ESP8266_STATE_ERROR;
442 
443  uint8_t command_length = strlen(self->_command);
444  size_t length = command_length;
445 
446  if (response_state == BC_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 (bc_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  bc_scheduler_plan_current_from_now(_BC_ESP8266_DELAY_SEND_RESPONSE);
468 
469  return;
470  }
471  case BC_ESP8266_STATE_SOCKET_SEND_DATA:
472  {
473  self->_state = BC_ESP8266_STATE_ERROR;
474 
475  if (bc_uart_async_write(self->_uart_channel, self->_message_buffer, self->_message_length) != self->_message_length)
476  {
477  continue;
478  }
479 
480  self->_state = BC_ESP8266_STATE_SOCKET_SEND_RESPONSE;
481 
482  bc_scheduler_plan_current_from_now(_BC_ESP8266_DELAY_SEND_RESPONSE);
483 
484  return;
485  }
486  case BC_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 > _BC_ESP8266_TIMEOUT_WIFI_CONNECT)
499  {
500  self->_state = BC_ESP8266_STATE_WIFI_CONNECT_ERROR;
501  continue;
502  }
503 
504  if (!_bc_esp8266_read_response(self))
505  {
506  bc_scheduler_plan_current_from_now(_BC_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 = BC_ESP8266_STATE_SNTP_CONFIG_COMMAND;
515  }
516  else
517  {
518  self->_state = BC_ESP8266_STATE_READY;
519  if (self->_event_handler != NULL)
520  {
521  self->_event_handler(self, BC_ESP8266_EVENT_WIFI_CONNECT_SUCCESS, self->_event_param);
522  }
523  }
524  }
525  else if (strcmp(self->_response, "FAIL\r") == 0)
526  {
527  self->_state = BC_ESP8266_STATE_WIFI_CONNECT_ERROR;
528  }
529  else
530  {
531  bc_scheduler_plan_current_from_now(_BC_ESP8266_DELAY_WIFI_CONNECT);
532  return;
533  }
534 
535  continue;
536  }
537  case BC_ESP8266_STATE_WIFI_CONNECT_ERROR:
538  {
539  self->_state = BC_ESP8266_STATE_DISCONNECTED;
540 
541  if (self->_event_handler != NULL)
542  {
543  self->_event_handler(self, BC_ESP8266_EVENT_WIFI_CONNECT_ERROR, self->_event_param);
544  }
545 
546  continue;
547  }
548  case BC_ESP8266_STATE_SNTP_CONFIG_RESPONSE:
549  {
550  self->_state = BC_ESP8266_STATE_ERROR;
551 
552  if (!_bc_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 = BC_ESP8266_STATE_SNTP_TIME_COMMAND;
563 
564  continue;
565  }
566  case BC_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 > _BC_ESP8266_TIMEOUT_SOCKET_CONNECT)
576  {
577  self->_state = BC_ESP8266_STATE_WIFI_CONNECT_ERROR;
578  continue;
579  }
580 
581  if (!_bc_esp8266_read_response(self))
582  {
583  bc_scheduler_plan_current_from_now(_BC_ESP8266_DELAY_SOCKET_CONNECT);
584  return;
585  }
586 
587  if (strcmp(self->_response, "OK\r") == 0)
588  {
589  self->_state = BC_ESP8266_STATE_READY;
590  if (self->_event_handler != NULL)
591  {
592  self->_event_handler(self, BC_ESP8266_EVENT_WIFI_CONNECT_SUCCESS, self->_event_param);
593  }
594  }
595  else if (memcmp(self->_response, "+CIPSNTPTIME:", 13) == 0)
596  {
597  _bc_esp8266_set_rtc_time(self->_response + 13);
598  }
599  else
600  {
601  bc_scheduler_plan_current_from_now(_BC_ESP8266_DELAY_SOCKET_CONNECT);
602  return;
603  }
604 
605  continue;
606  }
607  case BC_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 > _BC_ESP8266_TIMEOUT_SOCKET_CONNECT)
618  {
619  self->_state = BC_ESP8266_STATE_SOCKET_CONNECT_ERROR;
620  continue;
621  }
622 
623  if (!_bc_esp8266_read_response(self))
624  {
625  bc_scheduler_plan_current_from_now(_BC_ESP8266_DELAY_SOCKET_CONNECT);
626  return;
627  }
628 
629  if (strcmp(self->_response, "OK\r") == 0)
630  {
631  self->_state = BC_ESP8266_STATE_READY;
632  if (self->_event_handler != NULL)
633  {
634  self->_event_handler(self, BC_ESP8266_EVENT_SOCKET_CONNECT_SUCCESS, self->_event_param);
635  }
636  }
637  else if (strcmp(self->_response, "ERROR\r") == 0)
638  {
639  self->_state = BC_ESP8266_STATE_SOCKET_CONNECT_ERROR;
640  }
641  else
642  {
643  bc_scheduler_plan_current_from_now(_BC_ESP8266_DELAY_SOCKET_CONNECT);
644  return;
645  }
646 
647  continue;
648  }
649  case BC_ESP8266_STATE_SOCKET_CONNECT_ERROR:
650  {
651  self->_state = BC_ESP8266_STATE_READY;
652 
653  if (self->_event_handler != NULL)
654  {
655  self->_event_handler(self, BC_ESP8266_EVENT_SOCKET_CONNECT_ERROR, self->_event_param);
656  }
657 
658  continue;
659  }
660  case BC_ESP8266_STATE_SOCKET_SEND_RESPONSE:
661  {
662  self->_state = BC_ESP8266_STATE_SOCKET_SEND_ERROR;
663 
664  if (!_bc_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 = BC_ESP8266_STATE_RECEIVE;
675 
676  if (self->_event_handler != NULL)
677  {
678  self->_event_handler(self, BC_ESP8266_EVENT_SOCKET_SEND_SUCCESS, self->_event_param);
679  }
680 
681  continue;
682  }
683  case BC_ESP8266_STATE_SOCKET_SEND_ERROR:
684  {
685  self->_state = BC_ESP8266_STATE_READY;
686 
687  if (self->_event_handler != NULL)
688  {
689  self->_event_handler(self, BC_ESP8266_EVENT_SOCKET_SEND_ERROR, self->_event_param);
690  }
691 
692  continue;
693  }
694  case BC_ESP8266_STATE_SOCKET_RECEIVE:
695  {
696  if (!_bc_esp8266_read_socket_data(self))
697  {
698  continue;
699  }
700 
701  self->_state = BC_ESP8266_STATE_READY;
702 
703  if (self->_event_handler != NULL)
704  {
705  self->_event_handler(self, BC_ESP8266_EVENT_DATA_RECEIVED, self->_event_param);
706  }
707 
708  continue;
709  }
710  case BC_ESP8266_STATE_AP_AVAILABILITY_OPT_RESPONSE:
711  {
712  if (!_bc_esp8266_read_response(self) || memcmp(self->_response, "OK", 2) != 0)
713  {
714  bc_esp8266_disconnect(self);
715  return;
716  }
717 
718  self->_state = BC_ESP8266_STATE_AP_AVAILABILITY_COMMAND;
719 
720  continue;
721  }
722  case BC_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 > _BC_ESP8266_TIMEOUT_WIFI_CONNECT)
733  {
734  bc_esp8266_disconnect(self);
735  return;
736  }
737 
738  if (!_bc_esp8266_read_response(self))
739  {
740  bc_scheduler_plan_current_from_now(_BC_ESP8266_DELAY_WIFI_CONNECT);
741  return;
742  }
743 
744  if (strcmp(self->_response, "OK\r") == 0)
745  {
746  bc_esp8266_disconnect(self);
747 
748  if (self->_event_handler != NULL)
749  {
750  self->_event_handler(self, BC_ESP8266_EVENT_AP_AVAILABILITY_RESULT, self->_event_param);
751  }
752  return;
753  }
754  else if (strcmp(self->_response, "ERROR\r") == 0)
755  {
756  bc_esp8266_disconnect(self);
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  bc_scheduler_plan_current_from_now(_BC_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 bc_esp8266_get_received_message_data(bc_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 _bc_esp8266_read_response(bc_esp8266_t *self)
808 {
809  size_t length = 0;
810 
811  while (true)
812  {
813  char rx_character;
814 
815  if (bc_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 _bc_esp8266_read_socket_data(bc_esp8266_t *self)
851 {
852  while (true)
853  {
854  char rx_character;
855 
856  if (bc_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 _bc_esp8266_set_rtc_time(char *str)
873 {
874  bc_rtc_t rtc;
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  rtc.month = 1;
892  }
893  else if (strcmp(token, "Feb") == 0)
894  {
895  rtc.month = 2;
896  }
897  else if (strcmp(token, "Mar") == 0)
898  {
899  rtc.month = 3;
900  }
901  else if (strcmp(token, "Apr") == 0)
902  {
903  rtc.month = 4;
904  }
905  else if (strcmp(token, "May") == 0)
906  {
907  rtc.month = 5;
908  }
909  else if (strcmp(token, "Jun") == 0)
910  {
911  rtc.month = 6;
912  }
913  else if (strcmp(token, "Jul") == 0)
914  {
915  rtc.month = 7;
916  }
917  else if (strcmp(token, "Aug") == 0)
918  {
919  rtc.month = 8;
920  }
921  else if (strcmp(token, "Sep") == 0)
922  {
923  rtc.month = 9;
924  }
925  else if (strcmp(token, "Oct") == 0)
926  {
927  rtc.month = 10;
928  }
929  else if (strcmp(token, "Nov") == 0)
930  {
931  rtc.month = 11;
932  }
933  else if (strcmp(token, "Dec") == 0)
934  {
935  rtc.month = 12;
936  }
937  }
938  // Day
939  else if (state == 2)
940  {
941  rtc.date = atoi(token);
942  }
943  // Hours
944  else if (state == 3)
945  {
946  rtc.hours = atoi(token);
947  }
948  // Minutes
949  else if (state == 4)
950  {
951  rtc.minutes = atoi(token);
952  }
953  // Seconds
954  else if (state == 5)
955  {
956  rtc.seconds = atoi(token);
957  }
958  // Year
959  else if (state == 6)
960  {
961  if (strcmp(token, "1970") == 0)
962  {
963  return;
964  }
965  rtc.year = atoi(token);
966  }
967 
968  j = 0;
969  state++;
970  }
971  else
972  {
973  token[j++] = c;
974  }
975  }
976  bc_rtc_set_date_time(&rtc);
977 }
978 
980 {
981  if (self->_state != BC_ESP8266_STATE_DISCONNECTED || self->_config.ssid[0] == '\0')
982  {
983  return false;
984  }
985 
986  _bc_esp8266_enable(self);
987 
988  self->_state = BC_ESP8266_STATE_INITIALIZE;
989  self->_state_after_init = BC_ESP8266_STATE_AP_AVAILABILITY_OPT_COMMAND;
990 
991  bc_scheduler_plan_now(self->_task_id);
992 
993  return true;
994 }
995 
996 void bc_esp8266_get_ap_availability(bc_esp8266_t *self, bool *available, int *rssi)
997 {
998  *available = self->_ap_available;
999  *rssi = self->_rssi;
1000 }
1001 
1002 void bc_esp8266_get_ssid(bc_esp8266_t *self, char *ssid)
1003 {
1004  strncpy(ssid, self->_config.ssid, 64);
1005 }
1006 
1007 void bc_esp8266_set_ssid(bc_esp8266_t *self, char *ssid)
1008 {
1009  strncpy(self->_config.ssid, ssid, 64);
1010 }
1011 
1012 void bc_esp8266_get_password(bc_esp8266_t *self, char *password)
1013 {
1014  strncpy(password, self->_config.password, 64);
1015 }
1016 
1017 void bc_esp8266_set_password(bc_esp8266_t *self, char *password)
1018 {
1019  strncpy(self->_config.password, password, 64);
1020 }
void bc_esp8266_set_station_mode(bc_esp8266_t *self, char *ssid, char *password)
Set station mode.
Definition: bc_esp8266.c:104
Ready event.
Definition: bc_esp8266.h:26
bc_uart_channel_t
UART channels.
Definition: bc_uart.h:13
void bc_esp8266_get_password(bc_esp8266_t *self, char *password)
Get password.
Definition: bc_esp8266.c:1012
uint8_t seconds
Seconds parameter, from 00 to 59.
Definition: bc_rtc.h:17
uint8_t hours
Hours parameter, 24Hour mode, 00 to 23.
Definition: bc_rtc.h:20
bool bc_esp8266_disconnect(bc_esp8266_t *self)
Disable ESP8266 and disconnect.
Definition: bc_esp8266.c:174
bc_esp8266_event_t
Callback events.
Definition: bc_esp8266.h:23
Error event.
Definition: bc_esp8266.h:29
uint32_t bc_esp8266_get_received_message_length(bc_esp8266_t *self)
Get length of the received message.
Definition: bc_esp8266.c:790
bool bc_uart_async_read_start(bc_uart_channel_t channel, bc_tick_t timeout)
Start async reading.
Definition: bc_uart.c:475
uint32_t bc_esp8266_get_received_message_data(bc_esp8266_t *self, uint8_t *buffer, uint32_t buffer_size)
Get received message data.
Definition: bc_esp8266.c:795
Event is reading done.
Definition: bc_uart.h:133
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
void bc_esp8266_set_event_handler(bc_esp8266_t *self, void(*event_handler)(bc_esp8266_t *, bc_esp8266_event_t, void *), void *event_param)
Set callback function.
Definition: bc_esp8266.c:98
8N1: 8 data bits, none parity bit, 1 stop bit
Definition: bc_uart.h:70
void bc_scheduler_plan_now(bc_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
Definition: bc_scheduler.c:119
void bc_esp8266_set_ssid(bc_esp8266_t *self, char *ssid)
Set SSID.
Definition: bc_esp8266.c:1007
bool bc_esp8266_udp_connect(bc_esp8266_t *self, const char *host, uint16_t port)
Establish UDP Connection.
Definition: bc_esp8266.c:215
void bc_gpio_set_output(bc_gpio_channel_t channel, int state)
Set output state for GPIO channel.
Definition: bc_gpio.c:442
bool bc_esp8266_ssl_connect(bc_esp8266_t *self, const char *host, uint16_t port)
Establish SSL Connection.
Definition: bc_esp8266.c:220
void bc_gpio_set_mode(bc_gpio_channel_t channel, bc_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: bc_gpio.c:340
bool bc_esp8266_send_data(bc_esp8266_t *self, const void *buffer, size_t length)
Send data.
Definition: bc_esp8266.c:225
void bc_uart_init(bc_uart_channel_t channel, bc_uart_baudrate_t baudrate, bc_uart_setting_t setting)
Initialize UART channel.
Definition: bc_uart.c:53
bc_uart_event_t
Callback events.
Definition: bc_uart.h:127
void bc_uart_deinit(bc_uart_channel_t channel)
Deinitialize UART channel.
Definition: bc_uart.c:248
GPIO channel P8.
Definition: bc_gpio.h:39
void bc_esp8266_set_sntp(bc_esp8266_t *self, int timezone)
Enable SNTP and set time zone.
Definition: bc_esp8266.c:111
void bc_fifo_init(bc_fifo_t *fifo, void *buffer, size_t size)
Initialize FIFO buffer.
Definition: bc_fifo.c:4
GPIO channel P6.
Definition: bc_gpio.h:33
bool bc_esp8266_connect(bc_esp8266_t *self)
Enable ESP8266 and connect to WiFi.
Definition: bc_esp8266.c:156
void bc_scheduler_plan_relative(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to tick relative from current spin.
Definition: bc_scheduler.c:129
void bc_esp8266_set_password(bc_esp8266_t *self, char *password)
Set password.
Definition: bc_esp8266.c:1017
uint8_t minutes
Minutes parameter, from 00 to 59.
Definition: bc_rtc.h:19
uint8_t month
Month in a year, 1 to 12.
Definition: bc_rtc.h:23
void bc_scheduler_plan_current_from_now(bc_tick_t tick)
Schedule current task to tick relative from now.
Definition: bc_scheduler.c:154
void bc_esp8266_get_ap_availability(bc_esp8266_t *self, bool *available, int *rssi)
Get AP availability result.
Definition: bc_esp8266.c:996
size_t bc_uart_async_write(bc_uart_channel_t channel, const void *buffer, size_t length)
Add data to be transmited in async mode.
Definition: bc_uart.c:428
void bc_uart_set_async_fifo(bc_uart_channel_t channel, bc_fifo_t *write_fifo, bc_fifo_t *read_fifo)
Set buffers for async transfers.
Definition: bc_uart.c:422
void bc_uart_set_event_handler(bc_uart_channel_t channel, void(*event_handler)(bc_uart_channel_t, bc_uart_event_t, void *), void *event_param)
Set callback function.
Definition: bc_uart.c:416
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
size_t bc_uart_async_read(bc_uart_channel_t channel, void *buffer, size_t length)
Get data that has been received in async mode.
Definition: bc_uart.c:571
void bc_esp8266_init(bc_esp8266_t *self, bc_uart_channel_t uart_channel)
Initialize ESP8266.
Definition: bc_esp8266.c:37
bool bc_esp8266_tcp_connect(bc_esp8266_t *self, const char *host, uint16_t port)
Establish TCP Connection.
Definition: bc_esp8266.c:210
UART baudrat 115200 bps.
Definition: bc_uart.h:43
bool bc_esp8266_check_ap_availability(bc_esp8266_t *self)
Check AP availability.
Definition: bc_esp8266.c:979
uint8_t date
Date in a month, 1 to 31.
Definition: bc_rtc.h:22
bool bc_rtc_set_date_time(bc_rtc_t *rtc)
Set gate and time to RTC.
Definition: bc_rtc.c:77
void bc_scheduler_plan_current_now(void)
Schedule current task for immediate execution.
Definition: bc_scheduler.c:139
void bc_gpio_init(bc_gpio_channel_t channel)
Initialize GPIO channel.
Definition: bc_gpio.c:301
uint16_t year
Year parameter, 2000 to 2099.
Definition: bc_rtc.h:24
RTC date and time structure.
Definition: bc_rtc.h:15
GPIO channel operates as output.
Definition: bc_gpio.h:102
void bc_esp8266_set_sntp_with_servers(bc_esp8266_t *self, int timezone, char *sntp_server1, char *sntp_server2, char *sntp_server3)
Enable SNTP and set configuration.
Definition: bc_esp8266.c:116
void bc_esp8266_get_ssid(bc_esp8266_t *self, char *ssid)
Get SSID.
Definition: bc_esp8266.c:1002
bool bc_esp8266_is_ready(bc_esp8266_t *self)
Check if modem is ready for commands.
Definition: bc_esp8266.c:146