Mistake on this page?
Report an issue in GitHub or email us
ESP8266.h
1 /* ESP8266Interface Example
2  * Copyright (c) 2015 ARM Limited
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #ifndef ESP8266_H
19 #define ESP8266_H
20 
21 #if DEVICE_SERIAL && DEVICE_INTERRUPTIN && defined(MBED_CONF_EVENTS_PRESENT) && defined(MBED_CONF_NSAPI_PRESENT) && defined(MBED_CONF_RTOS_API_PRESENT)
22 #include <stdint.h>
23 #include <ctime>
24 
25 #include "drivers/BufferedSerial.h"
26 #include "netsocket/nsapi_types.h"
27 #include "netsocket/WiFiAccessPoint.h"
28 #include "PinNames.h"
29 #include "platform/ATCmdParser.h"
30 #include "platform/Callback.h"
31 #include "platform/mbed_chrono.h"
32 #include "platform/mbed_error.h"
33 #include "rtos/Mutex.h"
34 #include "rtos/ThisThread.h"
36 
37 // Various timeouts for different ESP8266 operations
38 // (some of these can't use literal form as they're needed for defaults in this header, where
39 // we shouldn't add a using directive for them. Defines only used in the C++ file can use literals).
40 #ifndef ESP8266_CONNECT_TIMEOUT
41 #define ESP8266_CONNECT_TIMEOUT 15s
42 #endif
43 #ifndef ESP8266_SEND_TIMEOUT
44 #define ESP8266_SEND_TIMEOUT 2s
45 #endif
46 #ifndef ESP8266_RECV_TIMEOUT
47 #define ESP8266_RECV_TIMEOUT std::chrono::seconds(2)
48 #endif
49 #ifndef ESP8266_MISC_TIMEOUT
50 #define ESP8266_MISC_TIMEOUT std::chrono::seconds(2)
51 #endif
52 #ifndef ESP8266_DNS_TIMEOUT
53 #define ESP8266_DNS_TIMEOUT 15s
54 #endif
55 
56 #define ESP8266_SCAN_TIME_MIN 0ms
57 #define ESP8266_SCAN_TIME_MAX 1500ms
58 #define ESP8266_SCAN_TIME_MIN_DEFAULT 120ms
59 #define ESP8266_SCAN_TIME_MAX_DEFAULT 360ms
60 
61 // Firmware version
62 #define ESP8266_SDK_VERSION 2000000
63 #define ESP8266_SDK_VERSION_MAJOR ESP8266_SDK_VERSION/1000000
64 
65 #define ESP8266_AT_VERSION 1000000
66 #define ESP8266_AT_VERSION_MAJOR ESP8266_AT_VERSION/1000000
67 #define ESP8266_AT_VERSION_TCP_PASSIVE_MODE 1070000
68 #define ESP8266_AT_VERSION_WIFI_SCAN_CHANGE 1060000
69 
70 #define FW_AT_LEAST_VERSION(MAJOR,MINOR,PATCH,NUSED/*Not used*/,REF) \
71  (((MAJOR)*1000000+(MINOR)*10000+(PATCH)*100) >= REF ? true : false)
72 
73 struct esp8266_socket {
74  int id;
75  nsapi_protocol_t proto;
76  bool connected;
77  bool bound;
78  SocketAddress addr;
79  int keepalive; // TCP
80 };
81 
82 /** ESP8266Interface class.
83  This is an interface to a ESP8266 radio.
84  */
85 class ESP8266 {
86 public:
87  ESP8266(PinName tx, PinName rx, bool debug = false, PinName rts = NC, PinName cts = NC);
88 
89  /**
90  * ESP8266 firmware SDK version
91  *
92  * @param major Major version number
93  * @param minor Minor version number
94  * @param patch Patch version number
95  */
96  struct fw_sdk_version {
97  int major;
98  int minor;
99  int patch;
100  fw_sdk_version(int major, int minor, int patch) : major(major), minor(minor), patch(patch) {}
101  };
102 
103  /**
104  * ESP8266 firmware AT version
105  *
106  * @param major Major version number
107  * @param minor Minor version number
108  * @param patch Patch version number
109  */
110  struct fw_at_version {
111  int major;
112  int minor;
113  int patch;
114  fw_at_version(int major, int minor, int patch) : major(major), minor(minor), patch(patch) {}
115  };
116 
117  /**
118  * Check AT command interface of ESP8266
119  *
120  * @return true if ready to respond on AT commands
121  */
122  bool at_available(void);
123 
124  /**
125  * Disable echo - required for OOB processing to work
126  *
127  * @return true if echo was successfully disabled
128  */
129  bool echo_off(void);
130 
131  /**
132  * Check sdk version from which firmware is created
133  *
134  * @return fw_sdk_version which tells major, minor and patch version
135  */
136  struct fw_sdk_version sdk_version(void);
137 
138  /**
139  * Check AT instruction set version from which firmware is created
140  *
141  * @return fw_at_version which tells major, minor and patch version
142  */
143  struct fw_at_version at_version(void);
144 
145  /**
146  * Startup the ESP8266
147  *
148  * @param mode mode of WIFI 1-client, 2-host, 3-both
149  * @return true only if ESP8266 was setup correctly
150  */
151  bool startup(int mode);
152 
153  /**
154  * Reset ESP8266
155  *
156  * @return true only if ESP8266 resets successfully
157  */
158  bool reset(void);
159 
160  /**
161  * Enable/Disable DHCP
162  *
163  * @param enabled DHCP enabled when true
164  * @param mode mode of DHCP 0-softAP, 1-station, 2-both
165  * @return true only if ESP8266 enables/disables DHCP successfully
166  */
167  bool dhcp(bool enabled, int mode);
168 
169  /**
170  * Connect ESP8266 to AP
171  *
172  * @param ap the name of the AP
173  * @param passPhrase the password of AP
174  * @return NSAPI_ERROR_OK in success, negative error code in failure
175  */
176  nsapi_error_t connect(const char *ap, const char *passPhrase);
177 
178  /**
179  * Disconnect ESP8266 from AP
180  *
181  * @return true only if ESP8266 is disconnected successfully
182  */
183  bool disconnect(void);
184 
185  /**
186  * Enable or disable Remote IP and Port printing with +IPD
187  *
188  * @param enable, 1 on, 0 off
189  * @return true only if ESP8266 is disconnected successfully
190  */
191  bool ip_info_print(int enable);
192 
193  /**
194  * Get the IP address of ESP8266
195  *
196  * @return null-teriminated IP address or null if no IP address is assigned
197  */
198  const char *ip_addr(void);
199 
200  /**
201  * Set static IP address, gateway and netmask
202  *
203  * @param ip IP address to set
204  * @param gateway (optional) gateway to set
205  * @param netmask (optional) netmask to set
206  *
207  * @return true if operation was successful and flase otherwise
208  */
209  bool set_ip_addr(const char *ip, const char *gateway, const char *netmask);
210 
211  /**
212  * Get the MAC address of ESP8266
213  *
214  * @return null-terminated MAC address or null if no MAC address is assigned
215  */
216  const char *mac_addr(void);
217 
218  /** Get the local gateway
219  *
220  * @return Null-terminated representation of the local gateway
221  * or null if no network mask has been recieved
222  */
223  const char *gateway();
224 
225  /** Get the local network mask
226  *
227  * @return Null-terminated representation of the local network mask
228  * or null if no network mask has been recieved
229  */
230  const char *netmask();
231 
232  /* Return RSSI for active connection
233  *
234  * @return Measured RSSI
235  */
236  int8_t rssi();
237 
238  /** Scan mode
239  */
240  enum scan_mode {
241  SCANMODE_ACTIVE = 0, /*!< active mode */
242  SCANMODE_PASSIVE = 1 /*!< passive mode */
243  };
244 
245  /** Scan for available networks
246  *
247  * @param ap Pointer to allocated array to store discovered AP
248  * @param limit Size of allocated @a res array, or 0 to only count available AP
249  * @param t_max Maximum scan time per channel
250  * @param t_min Minimum scan time per channel in active mode, can be omitted in passive mode
251  * @return Number of entries in @a res, or if @a count was 0 number of available networks, negative on error
252  * see @a nsapi_error
253  */
254  int scan(WiFiAccessPoint *res, unsigned limit, scan_mode mode,
255  std::chrono::duration<unsigned, std::milli> t_max,
256  std::chrono::duration<unsigned, std::milli> t_min);
257 
258  /**Perform a dns query
259  *
260  * @param name Hostname to resolve
261  * @param ip Buffer to store IP address
262  * @return 0 true on success, false on failure
263  */
264  bool dns_lookup(const char *name, char *ip);
265 
266  /**
267  * Open a socketed connection
268  *
269  * @param type the type of socket to open "UDP" or "TCP"
270  * @param id id to give the new socket, valid 0-4
271  * @param port port to open connection with
272  * @param addr the IP address of the destination
273  * @param port the port on the destination
274  * @param local_port UDP socket's local port, zero means any
275  * @param udp_mode UDP socket's mode, zero means can't change remote, 1 can change once, 2 can change multiple times
276  * @return NSAPI_ERROR_OK in success, negative error code in failure
277  */
278  nsapi_error_t open_udp(int id, const char *addr, int port, int local_port = 0, int udp_mode = 0);
279 
280  /**
281  * Open a socketed connection
282  *
283  * @param type the type of socket to open "UDP" or "TCP"
284  * @param id id to give the new socket, valid 0-4
285  * @param port port to open connection with
286  * @param addr the IP address of the destination
287  * @param port the port on the destination
288  * @param tcp_keepalive TCP connection's keep alive time, zero means disabled
289  * @return NSAPI_ERROR_OK in success, negative error code in failure
290  */
291  nsapi_error_t open_tcp(int id, const char *addr, int port, int keepalive = 0);
292 
293  /**
294  * Sends data to an open socket
295  *
296  * @param id id of socket to send to
297  * @param data data to be sent
298  * @param amount amount of data to be sent - max 2048
299  * @return number of bytes on success, negative error code in failure
300  */
301  nsapi_size_or_error_t send(int id, const void *data, uint32_t amount);
302 
303  /**
304  * Receives datagram from an open UDP socket
305  *
306  * @param id id to receive from
307  * @param data placeholder for returned information
308  * @param amount number of bytes to be received
309  * @return the number of bytes received
310  */
311  int32_t recv_udp(struct esp8266_socket *socket, void *data, uint32_t amount, mbed::chrono::milliseconds_u32 timeout = ESP8266_RECV_TIMEOUT);
312 
313  /**
314  * Receives stream data from an open TCP socket
315  *
316  * @param id id to receive from
317  * @param data placeholder for returned information
318  * @param amount number of bytes to be received
319  * @return the number of bytes received
320  */
321  int32_t recv_tcp(int id, void *data, uint32_t amount, mbed::chrono::milliseconds_u32 timeout = ESP8266_RECV_TIMEOUT);
322 
323  /**
324  * Closes a socket
325  *
326  * @param id id of socket to close, valid only 0-4
327  * @return true only if socket is closed successfully
328  */
329  bool close(int id);
330 
331  /**
332  * Allows timeout to be changed between commands
333  *
334  * @param timeout_ms timeout of the connection
335  */
336  void set_timeout(mbed::chrono::milliseconds_u32 timeout = ESP8266_MISC_TIMEOUT);
337 
338  /**
339  * Checks if data is available
340  */
341  bool readable();
342 
343  /**
344  * Checks if data can be written
345  */
346  bool writeable();
347 
348  /**
349  * Attach a function to call whenever sigio happens in the serial
350  *
351  * @param func A pointer to a void function, or 0 to set as none
352  */
353  void sigio(mbed::Callback<void()> func);
354 
355  /**
356  * Attach a function to call whenever sigio happens in the serial
357  *
358  * @param obj pointer to the object to call the member function on
359  * @param method pointer to the member function to call
360  */
361  template <typename T, typename M>
362  void sigio(T *obj, M method)
363  {
364  sigio(mbed::Callback<void()>(obj, method));
365  }
366 
367  /**
368  * Attach a function to call whenever network state has changed.
369  *
370  * @param func A pointer to a void function, or 0 to set as none
371  */
372  void attach(mbed::Callback<void()> status_cb);
373 
374  /**
375  * Configure SNTP (Simple Network Time Protocol)
376  *
377  * @param enable true to enable SNTP or false to disable it
378  * @param timezone timezone offset [-11,13] (0 by default)
379  * @param server0 optional parameter indicating the first SNTP server ("cn.ntp.org.cn" by default)
380  * @param server1 optional parameter indicating the second SNTP server ("ntp.sjtu.edu.cn" by default)
381  * @param server2 optional parameter indicating the third SNTP server ("us.pool.ntp.org" by default)
382  *
383  * @retval true if successful, false otherwise
384  */
385  bool set_sntp_config(bool enable, int timezone = 0, const char *server0 = nullptr,
386  const char *server1 = nullptr, const char *server2 = nullptr);
387 
388  /**
389  * Read out the configuration of SNTP (Simple Network Time Protocol)
390  *
391  * @param enable true if SNTP is enabled
392  * @param timezone timezone offset [-11,13]
393  * @param server0 name of the first SNTP server
394  * @param server1 name of the second SNTP server (optional, nullptr if not set)
395  * @param server2 name of the third SNTP server (optional, nullptr if not set)
396  *
397  * @retval true if successful, false otherwise
398  */
399  bool get_sntp_config(bool *enable, int *timezone, char *server0,
400  char *server1, char *server2);
401 
402  /**
403  * Read out SNTP time from ESP8266.
404  *
405  * @param t std::tm structure to be filled in
406  * @retval true on success, false otherwise
407  *
408  * @note ESP8266 must be connected and needs a couple of seconds
409  * before returning correct time. It may return 1 Jan 1970 if it is not ready.
410  *
411  * @note esp8266.sntp-enable must be set to true in mbed_app.json file.
412  */
413  bool get_sntp_time(std::tm *t);
414 
415  template <typename T, typename M>
416  void attach(T *obj, M method)
417  {
418  attach(mbed::Callback<void()>(obj, method));
419  }
420 
421  /**
422  * Read default Wifi mode from flash
423  *
424  * return Station, SoftAP or SoftAP+Station - 0 on failure
425  */
426  int8_t default_wifi_mode();
427 
428  /**
429  * Default Wifi mode written to flash only if changes
430  */
431  bool set_default_wifi_mode(const int8_t mode);
432 
433  /**
434  * @param track_ap if TRUE, sets the county code to be the same as the AP's that ESP is connected to,
435  * if FALSE the code will not change
436  * @param country_code ISO 3166-1 Alpha-2 coded country code
437  * @param channel_start the channel number to start at
438  * @param channels number of channels
439  */
440  bool set_country_code_policy(bool track_ap, const char *country_code, int channel_start, int channels);
441 
442  /** Get the connection status
443  *
444  * @return The connection status according to ConnectionStatusType
445  */
446  nsapi_connection_status_t connection_status() const;
447 
448  /**
449  * Start board's and ESP8266's UART flow control
450  *
451  * @return true if started
452  */
453  bool start_uart_hw_flow_ctrl();
454 
455  /**
456  * Stop board's and ESP8266's UART flow control
457  *
458  * @return true if started
459  */
460  bool stop_uart_hw_flow_ctrl();
461 
462  /*
463  * From AT firmware v1.7.0.0 onwards enables TCP passive mode
464  */
465  bool cond_enable_tcp_passive_mode();
466 
467  /**
468  * For executing OOB processing on background
469  *
470  * @param timeout AT parser receive timeout
471  * @param if TRUE, process all OOBs instead of only one
472  */
473  void bg_process_oob(std::chrono::duration<uint32_t, std::milli> timeout, bool all);
474 
475  /**
476  * Flush the serial port input buffers.
477  *
478  * If you do HW reset for ESP module, you should
479  * flush the input buffers from existing responses
480  * from the device.
481  */
482  void flush();
483 
484  static const int8_t WIFIMODE_STATION = 1;
485  static const int8_t WIFIMODE_SOFTAP = 2;
486  static const int8_t WIFIMODE_STATION_SOFTAP = 3;
487  static const int8_t SOCKET_COUNT = 5;
488 
489  /**
490  * Enables or disables uart input and deep sleep
491  *
492  * @param lock if TRUE, uart input is enabled and deep sleep is locked
493  * if FALSE, uart input is disabled and deep sleep is unlocked
494  */
495  int uart_enable_input(bool lock);
496 
497 private:
498  // FW version
499  struct fw_sdk_version _sdk_v;
500  struct fw_at_version _at_v;
501 
502  // FW version specific settings and functionalities
503  bool _tcp_passive;
504  int32_t _recv_tcp_passive(int id, void *data, uint32_t amount, std::chrono::duration<uint32_t, std::milli> timeout);
505  mbed::Callback<void()> _callback;
506 
507  // UART settings
508  mbed::BufferedSerial _serial;
509  PinName _serial_rts;
510  PinName _serial_cts;
511  rtos::Mutex _smutex; // Protect serial port access
512 
513  // AT Command Parser
514  mbed::ATCmdParser _parser;
515 
516  // Wifi scan result handling
517  bool _recv_ap(nsapi_wifi_ap_t *ap);
518 
519  // Socket data buffer
520  struct packet {
521  struct packet *next;
522  int id;
523  char remote_ip[16];
524  int remote_port;
525  uint32_t len; // Remaining length
526  uint32_t alloc_len; // Original length
527  // data follows
528  } *_packets, * *_packets_end;
529  void _clear_socket_packets(int id);
530  void _clear_socket_sending(int id);
531  int _sock_active_id;
532 
533  // Memory statistics
534  size_t _heap_usage; // (Socket data buffer usage)
535 
536  // OOB processing
537  void _process_oob(std::chrono::duration<uint32_t, std::milli> timeout, bool all);
538 
539  // OOB message handlers
540  void _oob_packet_hdlr();
541  void _oob_connect_err();
542  void _oob_conn_already();
543  void _oob_err();
544  void _oob_socket0_closed();
545  void _oob_socket1_closed();
546  void _oob_socket2_closed();
547  void _oob_socket3_closed();
548  void _oob_socket4_closed();
549  void _oob_connection_status();
550  void _oob_socket_close_err();
551  void _oob_watchdog_reset();
552  void _oob_busy();
553  void _oob_tcp_data_hdlr();
554  void _oob_ready();
555  void _oob_scan_results();
556  void _oob_send_ok_received();
557  void _oob_send_fail_received();
558 
559  // OOB state variables
560  int _connect_error;
561  bool _disconnect;
562  bool _fail;
563  bool _sock_already;
564  bool _closed;
565  bool _error;
566  bool _busy;
567  bool _reset_done;
568  int _sock_sending_id;
569 
570  // Modem's address info
571  char _ip_buffer[16];
572  char _gateway_buffer[16];
573  char _netmask_buffer[16];
574  char _mac_buffer[18];
575 
576  // Modem's socket info
577  struct _sock_info {
578  bool open;
579  nsapi_protocol_t proto;
580  char *tcp_data;
581  int32_t tcp_data_avbl; // Data waiting on modem
582  int32_t tcp_data_rcvd;
583  bool send_fail; // Received 'SEND FAIL'. Expect user will close the socket.
584  };
585  struct _sock_info _sock_i[SOCKET_COUNT];
586 
587  // Scan results
588  struct _scan_results {
589  WiFiAccessPoint *res;
590  unsigned limit;
591  unsigned cnt;
592  };
593  struct _scan_results _scan_r;
594 
595  // Connection state reporting
596  nsapi_connection_status_t _conn_status;
597  mbed::Callback<void()> _conn_stat_cb; // ESP8266Interface registered
598 };
599 #endif
600 #endif
SocketAddress class.
signed int nsapi_error_t
Type used to represent error codes.
Definition: nsapi_types.h:140
signed int nsapi_size_or_error_t
Type used to represent either a size or error passed through sockets.
Definition: nsapi_types.h:151
nsapi_wifi_ap structure
Definition: nsapi_types.h:354
SocketAddress class.
Definition: SocketAddress.h:37
The Mutex class is used to synchronize the execution of threads.
Definition: Mutex.h:70
Class providing buffered UART communication functionality using separate circular buffer for send and...
Parser class for parsing AT commands.
Definition: ATCmdParser.h:56
static void debug(const char *format,...) MBED_PRINTF(1
Output a debug message.
Definition: mbed_debug.h:44
Callback class based on template specialization.
Definition: Callback.h:53
WiFiAccessPoint class.
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.