// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include #include "esp_log.h" #include "sntp.h" static const char *TAG = "sntp"; static volatile sntp_sync_mode_t sntp_sync_mode = SNTP_SYNC_MODE_IMMED; static volatile sntp_sync_status_t sntp_sync_status = SNTP_SYNC_STATUS_RESET; static sntp_sync_time_cb_t time_sync_notification_cb = NULL; inline void sntp_set_sync_status(sntp_sync_status_t sync_status) { sntp_sync_status = sync_status; } void __attribute__((weak)) sntp_sync_time(struct timeval *tv) { if (sntp_sync_mode == SNTP_SYNC_MODE_IMMED) { settimeofday(tv, NULL); sntp_set_sync_status(SNTP_SYNC_STATUS_COMPLETED); } else if (sntp_sync_mode == SNTP_SYNC_MODE_SMOOTH) { struct timeval tv_now; gettimeofday(&tv_now, NULL); int64_t cpu_time = (int64_t)tv_now.tv_sec * 1000000L + (int64_t)tv_now.tv_usec; int64_t sntp_time = (int64_t)tv->tv_sec * 1000000L + (int64_t)tv->tv_usec; int64_t delta = sntp_time - cpu_time; struct timeval tv_delta = { .tv_sec = delta / 1000000L, .tv_usec = delta % 1000000L }; if (adjtime(&tv_delta, NULL) == -1) { ESP_LOGD(TAG, "Function adjtime don't update time because the error is very big"); settimeofday(tv, NULL); ESP_LOGD(TAG, "Time was synchronized through settimeofday"); sntp_set_sync_status(SNTP_SYNC_STATUS_COMPLETED); } else { sntp_set_sync_status(SNTP_SYNC_STATUS_IN_PROGRESS); } } if (time_sync_notification_cb) { time_sync_notification_cb(tv); } } void sntp_set_sync_mode(sntp_sync_mode_t sync_mode) { sntp_sync_mode = sync_mode; } sntp_sync_mode_t sntp_get_sync_mode(void) { return sntp_sync_mode; } // set a callback function for time synchronization notification void sntp_set_time_sync_notification_cb(sntp_sync_time_cb_t callback) { time_sync_notification_cb = callback; } sntp_sync_status_t sntp_get_sync_status(void) { sntp_sync_status_t ret_sync_status = SNTP_SYNC_STATUS_RESET; sntp_sync_status_t sync_status = sntp_sync_status; if (sync_status == SNTP_SYNC_STATUS_COMPLETED) { sntp_set_sync_status(SNTP_SYNC_STATUS_RESET); ret_sync_status = SNTP_SYNC_STATUS_COMPLETED; } else if (sync_status == SNTP_SYNC_STATUS_IN_PROGRESS) { struct timeval outdelta; adjtime(NULL, &outdelta); if (outdelta.tv_sec == 0 && outdelta.tv_usec == 0) { sntp_set_sync_status(SNTP_SYNC_STATUS_RESET); ret_sync_status = SNTP_SYNC_STATUS_COMPLETED; } else { ret_sync_status = SNTP_SYNC_STATUS_IN_PROGRESS; } } return ret_sync_status; }