sntp/lwip: Add some modes for time synchronization

Closes: IDF-236
Closes: https://github.com/espressif/esp-idf/pull/1668
Closes: https://github.com/espressif/esp-idf/pull/4103
This commit is contained in:
Konstantin Kondrashov
2019-03-02 02:12:11 +08:00
committed by bot
parent 626684578a
commit 07a3eca372
10 changed files with 350 additions and 10 deletions

View File

@@ -1,5 +1,6 @@
set(COMPONENT_ADD_INCLUDEDIRS
include/apps
include/apps/sntp
lwip/src/include
port/esp32/include
port/esp32/include/arch
@@ -9,6 +10,7 @@ set(COMPONENT_ADD_INCLUDEDIRS
set(COMPONENT_SRCS "apps/dhcpserver/dhcpserver.c"
"apps/ping/esp_ping.c"
"apps/ping/ping.c"
"apps/sntp/sntp.c"
"lwip/src/api/api_lib.c"
"lwip/src/api/api_msg.c"
"lwip/src/api/err.c"

View File

@@ -0,0 +1,93 @@
// 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 <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#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;
}

View File

@@ -5,6 +5,7 @@ COMPONENT_SUBMODULES += lwip
COMPONENT_ADD_INCLUDEDIRS := \
include/apps \
include/apps/sntp \
lwip/src/include \
port/esp32/include \
port/esp32/include/arch \
@@ -13,6 +14,7 @@ COMPONENT_ADD_INCLUDEDIRS := \
COMPONENT_SRCDIRS := \
apps/dhcpserver \
apps/ping \
apps/sntp \
lwip/src/api \
lwip/src/apps/sntp \
lwip/src/core \

View File

@@ -0,0 +1,22 @@
// 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.
#ifndef __ESP_SNTP_H__
#define __ESP_SNTP_H__
#include "lwip/err.h"
#include "lwip/apps/sntp.h"
#include "sntp.h"
#endif // __ESP_SNTP_H__

View File

@@ -0,0 +1,119 @@
// 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.
#ifndef __SNTP_H__
#define __SNTP_H__
/*
* The time update takes place in the sntp_sync_time() function.
* The user has the ability to redefine this function in order
* to re-define its functionality. This function has two time update modes,
* which can be set via the sntp_set_sync_mode() function.
* Two modes are available:
* - the first is an immediate update when receiving time from the sntp server,
* - the second is a smooth time update (if the time error is no more than 35 minutes,
* and an immediate update if the error is more than 35 minutes).
*
* To receive notification of time synchronization,
* you can use the callback function or get the synchronization status
* via the sntp_get_sync_status() function.
*
* To determine the time synchronization time on the device, you can use:
* 1) sntp_set_time_sync_notification_cb() function to set the callback function,
* which is convenient to use to receive notification of the update time.
* 2) sntp_get_sync_status() function for getting time synchronization status.
* After the time synchronization is completed, the status will be
* SNTP_SYNC_STATUS_COMPLETED, after, it will be reseted to SNTP_SYNC_STATUS_RESET
* to wait for the next sync cycle.
*/
/// SNTP time update mode
typedef enum {
SNTP_SYNC_MODE_IMMED, /*!< Update system time immediately when receiving a response from the SNTP server. */
SNTP_SYNC_MODE_SMOOTH, /*!< Smooth time updating. Time error is gradually reduced using adjtime function. If the difference between SNTP response time and system time is large (more than 35 minutes) then update immediately. */
} sntp_sync_mode_t;
/// SNTP sync status
typedef enum {
SNTP_SYNC_STATUS_RESET, // Reset status.
SNTP_SYNC_STATUS_COMPLETED, // Time is synchronized.
SNTP_SYNC_STATUS_IN_PROGRESS, // Smooth time sync in progress.
} sntp_sync_status_t;
/**
* @brief SNTP callback function for notifying about time sync event
*
* @param tv Time received from SNTP server.
*/
typedef void (*sntp_sync_time_cb_t) (struct timeval *tv);
/**
* @brief This function updates the system time.
*
* This is a weak-linked function. It is possible to replace all SNTP update functionality
* by placing a sntp_sync_time() function in the app firmware source.
* If the default implementation is used, calling sntp_set_sync_mode() allows
* the time synchronization mode to be changed to instant or smooth.
* If a callback function is registered via sntp_set_time_sync_notification_cb(),
* it will be called following time synchronization.
*
* @param tv Time received from SNTP server.
*/
void sntp_sync_time(struct timeval *tv);
/**
* @brief Set the sync mode
*
* Allowable two mode: SNTP_SYNC_MODE_IMMED and SNTP_SYNC_MODE_SMOOTH.
* @param sync_mode Sync mode.
*/
void sntp_set_sync_mode(sntp_sync_mode_t sync_mode);
/**
* @brief Get set sync mode
*
* @return SNTP_SYNC_MODE_IMMED: Update time immediately.
* SNTP_SYNC_MODE_SMOOTH: Smooth time updating.
*/
sntp_sync_mode_t sntp_get_sync_mode(void);
/**
* @brief Get status of time sync
*
* After the update is completed, the status will be returned as SNTP_SYNC_STATUS_COMPLETED.
* After that, the status will be reset to SNTP_SYNC_STATUS_RESET.
* If the update operation is not completed yet, the status will be SNTP_SYNC_STATUS_RESET.
* If a smooth mode was chosen and the synchronization is still continuing (adjtime works), then it will be SNTP_SYNC_STATUS_IN_PROGRESS.
*
* @return SNTP_SYNC_STATUS_RESET: Reset status.
* SNTP_SYNC_STATUS_COMPLETED: Time is synchronized.
* SNTP_SYNC_STATUS_IN_PROGRESS: Smooth time sync in progress.
*/
sntp_sync_status_t sntp_get_sync_status(void);
/**
* @brief Set status of time sync
*
* @param sync_status status of time sync (see sntp_sync_status_t)
*/
void sntp_set_sync_status(sntp_sync_status_t sync_status);
/**
* @brief Set a callback function for time synchronization notification
*
* @param callback a callback function
*/
void sntp_set_time_sync_notification_cb(sntp_sync_time_cb_t callback);
#endif // __SNTP_H__

View File

@@ -1,3 +1,3 @@
#pragma once
#warning "This header file is deprecated, please include lwip/apps/sntp.h instead."
#include "lwip/apps/sntp.h"
#warning "This header file is deprecated, please include esp_sntp.h instead."
#include "esp_sntp.h"

View File

@@ -43,7 +43,7 @@
#include "esp_task.h"
#include "esp_system.h"
#include "sdkconfig.h"
#include "sntp.h"
#include "netif/dhcp_state.h"
/* Enable all Espressif-only options */
@@ -836,7 +836,7 @@ enum {
#define SNTP_SET_SYSTEM_TIME_US(sec, us) \
do { \
struct timeval tv = { .tv_sec = sec, .tv_usec = us }; \
settimeofday(&tv, NULL); \
sntp_sync_time(&tv); \
} while (0);
#define SNTP_GET_SYSTEM_TIME(sec, us) \
@@ -845,6 +845,7 @@ enum {
gettimeofday(&tv, NULL); \
(sec) = tv.tv_sec; \
(us) = tv.tv_usec; \
sntp_set_sync_status(SNTP_SYNC_STATUS_RESET); \
} while (0);
#define SOC_SEND_LOG //printf