diff --git a/components/wifi/esp8266-driver/ESP8266/ESP8266.cpp b/components/wifi/esp8266-driver/ESP8266/ESP8266.cpp index fa2676c1b8..1520027335 100644 --- a/components/wifi/esp8266-driver/ESP8266/ESP8266.cpp +++ b/components/wifi/esp8266-driver/ESP8266/ESP8266.cpp @@ -1114,6 +1114,130 @@ void ESP8266::attach(Callback status_cb) _conn_stat_cb = status_cb; } +bool ESP8266::set_sntp_config(bool enable, int timezone, const char *server0, + const char *server1, const char *server2) +{ + bool done = false; + _smutex.lock(); + if ((server0 == nullptr || server0[0] == '\0')) { + done = _parser.send("AT+CIPSNTPCFG=%d,%d", + enable ? 1 : 0, timezone); + } else if ((server0 != nullptr || server0[0] != '\0') + && (server1 == nullptr && server1[0] == '\0')) { + done = _parser.send("AT+CIPSNTPCFG=%d,%d,%s", + enable ? 1 : 0, timezone, server0); + } else if ((server0 != nullptr || server0[0] != '\0') + && (server1 != nullptr && server1[0] != '\0') + && (server2 == nullptr && server2[0] == '\0')) { + done = _parser.send("AT+CIPSNTPCFG=%d,%d,%s,%s", + enable ? 1 : 0, timezone, server0, server1); + } else { + done = _parser.send("AT+CIPSNTPCFG=%d,%d,%s,%s,%s", + enable ? 1 : 0, timezone, server0, server1, server2); + } + done &= _parser.recv("OK\n"); + _smutex.unlock(); + return done; +} + +bool ESP8266::get_sntp_config(bool *enable, int *timezone, char *server0, + char *server1, char *server2) +{ + _smutex.lock(); + unsigned int tmp; + bool done = _parser.send("AT+CIPSNTPCFG?") + && _parser.scanf("+CIPSNTPCFG:%d,%d,\"%32[^\"]\",\"%32[^\"]\",\"%32[^\"]\"", + &tmp, timezone, server0, server1, server2) + && _parser.recv("OK\n"); + _smutex.unlock(); + *enable = tmp ? true : false; + return done; +} + +bool ESP8266::get_sntp_time(std::tm *t) +{ + _smutex.lock(); + char buf[25]; // Thu Aug 04 14:48:05 2016 (always 24 chars + \0) + memset(buf, 0, 25); + + bool done = _parser.send("AT+CIPSNTPTIME?") + && _parser.scanf("+CIPSNTPTIME:%24c", &buf) + && _parser.recv("OK\n"); + _smutex.unlock(); + + if (!done) { + return false; + } + + char wday[4] = "\0", mon[4] = "\0"; + int mday = 0, hour = 0, min = 0, sec = 0, year = 0; + int ret = sscanf(buf, "%s %s %d %d:%d:%d %d", + wday, mon, &mday, &hour, &min, &sec, &year); + if (ret != 7) { + tr_debug("get_sntp_time(): sscanf returned %d", ret); + return false; + } + + t->tm_sec = sec; + t->tm_min = min; + t->tm_hour = hour; + t->tm_mday = mday; + + t->tm_wday = 0; + if (strcmp(wday, "Mon") == 0) { + t->tm_wday = 0; + } else if (strcmp(wday, "Tue") == 0) { + t->tm_wday = 1; + } else if (strcmp(wday, "Wed") == 0) { + t->tm_wday = 2; + } else if (strcmp(wday, "Thu") == 0) { + t->tm_wday = 3; + } else if (strcmp(wday, "Fri") == 0) { + t->tm_wday = 4; + } else if (strcmp(wday, "Sat") == 0) { + t->tm_wday = 5; + } else if (strcmp(wday, "Sun") == 0) { + t->tm_wday = 6; + } else { + tr_debug("get_sntp_time(): Invalid weekday: %s", wday); + return false; + } + + t->tm_mon = 0; + if (strcmp(mon, "Jan") == 0) { + t->tm_mon = 0; + } else if (strcmp(mon, "Feb") == 0) { + t->tm_mon = 1; + } else if (strcmp(mon, "Mar") == 0) { + t->tm_mon = 2; + } else if (strcmp(mon, "Apr") == 0) { + t->tm_mon = 3; + } else if (strcmp(mon, "May") == 0) { + t->tm_mon = 4; + } else if (strcmp(mon, "Jun") == 0) { + t->tm_mon = 5; + } else if (strcmp(mon, "Jul") == 0) { + t->tm_mon = 6; + } else if (strcmp(mon, "Aug") == 0) { + t->tm_mon = 7; + } else if (strcmp(mon, "Sep") == 0) { + t->tm_mon = 8; + } else if (strcmp(mon, "Oct") == 0) { + t->tm_mon = 9; + } else if (strcmp(mon, "Nov") == 0) { + t->tm_mon = 10; + } else if (strcmp(mon, "Dec") == 0) { + t->tm_mon = 11; + } else { + tr_debug("get_sntp_time(): Invalid month: %s", mon); + return false; + } + + t->tm_year = (year - 1900); + + return true; +} + bool ESP8266::_recv_ap(nsapi_wifi_ap_t *ap) { int sec = NSAPI_SECURITY_UNKNOWN; diff --git a/components/wifi/esp8266-driver/ESP8266/ESP8266.h b/components/wifi/esp8266-driver/ESP8266/ESP8266.h index b2601f7dd8..e93c5cc956 100644 --- a/components/wifi/esp8266-driver/ESP8266/ESP8266.h +++ b/components/wifi/esp8266-driver/ESP8266/ESP8266.h @@ -20,6 +20,7 @@ #if DEVICE_SERIAL && DEVICE_INTERRUPTIN && defined(MBED_CONF_EVENTS_PRESENT) && defined(MBED_CONF_NSAPI_PRESENT) && defined(MBED_CONF_RTOS_API_PRESENT) #include +#include #include "drivers/BufferedSerial.h" #include "features/netsocket/nsapi_types.h" @@ -354,6 +355,47 @@ public: */ void attach(mbed::Callback status_cb); + /** + * Configure SNTP (Simple Network Time Protocol) + * + * @param enable true to enable SNTP or false to disable it + * @param timezone timezone offset [-11,13] (0 by default) + * @param server0 optional parameter indicating the first SNTP server ("cn.ntp.org.cn" by default) + * @param server1 optional parameter indicating the second SNTP server ("ntp.sjtu.edu.cn" by default) + * @param server2 optional parameter indicating the third SNTP server ("us.pool.ntp.org" by default) + * + * @retval true if successful, false otherwise + */ + bool set_sntp_config(bool enable, int timezone = 0, const char *server0 = nullptr, + const char *server1 = nullptr, const char *server2 = nullptr); + + /** + * Read out the configuration of SNTP (Simple Network Time Protocol) + * + * @param enable true if SNTP is enabled + * @param timezone timezone offset [-11,13] + * @param server0 name of the first SNTP server + * @param server1 name of the second SNTP server (optional, nullptr if not set) + * @param server2 name of the third SNTP server (optional, nullptr if not set) + * + * @retval true if successful, false otherwise + */ + bool get_sntp_config(bool *enable, int *timezone, char *server0, + char *server1, char *server2); + + /** + * Read out SNTP time from ESP8266. + * + * @param t std::tm structure to be filled in + * @retval true on success, false otherwise + * + * @note ESP8266 must be connected and needs a couple of seconds + * before returning correct time. It may return 1 Jan 1970 if it is not ready. + * + * @note esp8266.sntp-enable must be set to true in mbed_app.json file. + */ + bool get_sntp_time(std::tm *t); + template void attach(T *obj, M method) { diff --git a/components/wifi/esp8266-driver/ESP8266Interface.cpp b/components/wifi/esp8266-driver/ESP8266Interface.cpp index 257ce74319..8c83e2aaba 100644 --- a/components/wifi/esp8266-driver/ESP8266Interface.cpp +++ b/components/wifi/esp8266-driver/ESP8266Interface.cpp @@ -583,6 +583,12 @@ const char *ESP8266Interface::get_netmask() return _conn_stat != NSAPI_STATUS_DISCONNECTED ? _esp.netmask() : NULL; } +nsapi_error_t ESP8266Interface::get_time(std::tm *t) +{ + _init(); + return _esp.get_sntp_time(t) ? NSAPI_ERROR_OK : NSAPI_ERROR_TIMEOUT; +} + char *ESP8266Interface::get_interface_name(char *interface_name) { memcpy(interface_name, ESP8266_WIFI_IF_NAME, sizeof(ESP8266_WIFI_IF_NAME)); @@ -709,7 +715,13 @@ nsapi_error_t ESP8266Interface::_init(void) if (!_esp.startup(ESP8266::WIFIMODE_STATION)) { return NSAPI_ERROR_DEVICE_ERROR; } - + if (!_esp.set_sntp_config(MBED_CONF_ESP8266_SNTP_ENABLE, + MBED_CONF_ESP8266_SNTP_TIMEZONE, + MBED_CONF_ESP8266_SNTP_SERVER0, + MBED_CONF_ESP8266_SNTP_SERVER1, + MBED_CONF_ESP8266_SNTP_SERVER2)) { + return NSAPI_ERROR_DEVICE_ERROR; + } _initialized = true; } return NSAPI_ERROR_OK; diff --git a/components/wifi/esp8266-driver/ESP8266Interface.h b/components/wifi/esp8266-driver/ESP8266Interface.h index 8ab42f3967..d371bb457b 100644 --- a/components/wifi/esp8266-driver/ESP8266Interface.h +++ b/components/wifi/esp8266-driver/ESP8266Interface.h @@ -167,6 +167,15 @@ public: MBED_DEPRECATED_SINCE("mbed-os-5.15", "String-based APIs are deprecated") virtual const char *get_netmask(); + /** Get the current time. + * + * @retval NSAPI_ERROR_UNSUPPORTED if the function is not supported + * @retval NSAPI_ERROR_OK on success + * + * @note esp8266.sntp-enable must be set to true in mbed_app.json. + */ + nsapi_error_t get_time(std::tm *t); + /** Get the network interface name * * @return Null-terminated representation of the network interface name diff --git a/components/wifi/esp8266-driver/mbed_lib.json b/components/wifi/esp8266-driver/mbed_lib.json index 541bb02bd5..ccf91b6a49 100644 --- a/components/wifi/esp8266-driver/mbed_lib.json +++ b/components/wifi/esp8266-driver/mbed_lib.json @@ -59,16 +59,36 @@ "value": null }, "channel-start": { - "help": "the channel number to start at, 1 by default", + "help": "The channel number to start at, 1 by default", "value": null }, "channels": { - "help": "channel count, 13 by default", + "help": "Channel count, 13 by default", "value": null }, "built-in-dns": { "help": "use built-in CIPDOMAIN AT command to resolve address to IP", "value": false + }, + "sntp-enable": { + "help": "Enable SNTP. This allows application to use get_sntp_time()", + "value": false + }, + "sntp-timezone": { + "help": "SNTP timezone", + "value": 0 + }, + "sntp-server0": { + "help": "First SNTP server. Empty string will let ESP8266 use its default.", + "value": "\"\"" + }, + "sntp-server1": { + "help": "Second SNTP server. Empty string will let ESP8266 use its default.", + "value": "\"\"" + }, + "sntp-server2": { + "help": "Third SNTP server. Empty string will let ESP8266 use its default.", + "value": "\"\"" } }, "target_overrides": {