[RVB2601 Creative Application Development] Dynamically load MBRE A fast implementation code of NTP with second-level accuracy
[Copy link]
NTP is a commonly used function in IOT MCU, and RVB2601 also provides NTP package for use. Due to the lack of SDK perfection, the connection between NTP in 7.4.3 and the system RTC module may cause stuck phenomenon.
In fact, since the RTC of the 2601 development board does not have its own power supply, the RTC cannot save the time after power failure. Therefore, this RTC has certain limitations in use. At the same time, some defects in the SDK also bring troubles to the NTP and GETTIME APIs. Because the actual accuracy of NTP is originally affected by network conditions, the accuracy range is between tens of ms and 500ms (see the introduction of NTP accuracy ). Therefore, for daily applications (such as electronic clocks, etc.), a second-level clock is sufficient. The following introduces a quick implementation code of a second-level NTP for reference by forum friends.
- Use CDK to add the ntp package to the project file.
- In the NTP.C code, add the following function
int mbre_simple_ntp_proc(char *server, int32_t *totalSeconds)
{
char buf[BUFSIZE];
size_t nbytes;
int sockfd, maxfd1;
struct sockaddr_in servaddr = {0,};
fd_set readfds;
struct timeval timeout, recvtv, tv, rcvtimeout = {3, 0};
double offset;
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(NTP_PORT);
//MBRE初始化返回值,错误情况下totaoSeconds值为0
if(!totalSeconds) return -1;
*totalSeconds = 0;
if (server == NULL) {
//1.cn.pool.ntp.org is more reliable
servaddr.sin_addr.s_addr = inet_host("ntp1.aliyun.com");
LOGD(TAG, "ntp1.aliyun.com");
} else {
servaddr.sin_addr.s_addr = inet_host(server);
LOGD(TAG, "%s", server);
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
LOGE(TAG, "socket error");
return -1;
}
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &rcvtimeout, sizeof(struct timeval));
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) != 0) {
LOGE(TAG, "connect error");
close(sockfd);
return -errno;
}
nbytes = BUFSIZE;
if (get_ntp_packet(buf, &nbytes) != 0) {
LOGE(TAG, "construct ntp request errorr");
close(sockfd);
return -1;
}
send(sockfd, buf, nbytes, 0);
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
maxfd1 = sockfd + 1;
timeout.tv_sec = TIMEOUT;
timeout.tv_usec = 0;
if (select(maxfd1, &readfds, NULL, NULL, &timeout) > 0) {
if (FD_ISSET(sockfd, &readfds)) {
if ((nbytes = recv(sockfd, buf, BUFSIZE, 0)) < 0) {
LOGE(TAG, "recv error");
close(sockfd);
return -1;
}
if(nbytes < 43) return -1;
//MBRE简单获取中国(8时区)的NTP秒数(自1900开始)
{
unsigned long secsSince1900, u1, u2;
// convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long)buf[40] << 24;
secsSince1900 |= (unsigned long)buf[41] << 16;
secsSince1900 |= (unsigned long)buf[42] << 8;
secsSince1900 |= (unsigned long)buf[43];
//减去1900秒数起始;同时加上了8时区的秒数偏移
*totalSeconds = secsSince1900 - 2208988800UL + 8 * 3600UL;
}
} else {
LOGE(TAG, "select timeout");
return -1;
}
} else {
LOGE(TAG, "FD_ISSET");
close(sockfd);
return -1;
}
close(sockfd);
return 0;
}
- The calling logic is very simple. After obtaining the ntp time, record the machine milliseconds of the acquisition point. You can directly calculate it later. This is essentially the same as using RTC, but much simpler.
//C文件中的引用处extern说明
extern int mbre_simple_ntp_proc(char *server, int32_t *totalSeconds);
...
int32_t totalSeconds = 0;
int32_t startMicroSecs = 0;
int rtn;
//调用函数,返回成功后,totalSeconds存放的是自1900年起的秒数值
rtn = mbre_simple_ntp_proc("ntp1.aliyun.com", &totalSeconds);
//记下获取ntp的毫秒时间
startMicroSecs = csi_tick_get_ms();
if(0 == rtn) printf("从1900年起算的秒数 = %d\r\n", totalSeconds);
else printf("NTP失败,错误码 %d\r\n", rtn);
...
//在任何需要获取当前时间的地方, 只需要根据当前系统ms数,计算出与获取ntp的偏移即可得到有效秒数
int32_t currentMicroSecs = csi_tick_get_ms();
int32_t currentSecsSince1900 = totalSeconds + (currentMicroSecs - startMicroSecs)/1000;
-
The following is the relevant processing code in the time library used by Arduino, which can easily calculate the year, month, day, hour, minute and other data
typedef struct {
uint8_t Second;
uint8_t Minute;
uint8_t Hour;
uint8_t Wday; // day of week, sunday is day 1
uint8_t Day;
uint8_t Month;
uint8_t Year; // offset from 1970;
} tmElements_t, TimeElements, *tmElementsPtr_t;
/* 从系统时间转换为年、月、日、时、分、秒的实际代码 */
// 润年润月计算
#define LEAP_YEAR(Y) ( ((1970+(Y))>0) && !((1970+(Y))%4) && ( ((1970+(Y))%100) || !((1970+(Y))%400) ) )
static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0
void breakTime(time_t timeInput, tmElements_t &tm){
// break the given time_t into time components
// this is a more compact version of the C library localtime function
// note that year is offset from 1970 !!!
uint8_t year;
uint8_t month, monthLength;
uint32_t time;
unsigned long days;
time = (uint32_t)timeInput;
tm.Second = time % 60;
time /= 60; // now it is minutes
tm.Minute = time % 60;
time /= 60; // now it is hours
tm.Hour = time % 24;
time /= 24; // now it is days
tm.Wday = ((time + 4) % 7) + 1; // Sunday is day 1
year = 0;
days = 0;
while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) {
year++;
}
tm.Year = year; // year is offset from 1970
days -= LEAP_YEAR(year) ? 366 : 365;
time -= days; // now it is days in this year, starting at 0
days=0;
month=0;
monthLength=0;
for (month=0; month<12; month++) {
if (month==1) { // february
if (LEAP_YEAR(year)) {
monthLength=29;
} else {
monthLength=28;
}
} else {
monthLength = monthDays[month];
}
if (time >= monthLength) {
time -= monthLength;
} else {
break;
}
}
tm.Month = month + 1; // jan is month 1
tm.Day = time + 1; // day of month
}
In the Arduino related libraries, there are many convenient ready-made libraries for time operations and other functional development. If the Tietouge series can provide Arduino adaptation libraries like other domestic IOT MCU companies (such as Lex), it will be a very important boost for IOT APP development. After all, if it is just a simple connection to sensors, many chips are enough. The obvious advantage of domestic IOT MCU is stronger FLASH and RAM. In the field of IOT, where applications are king, there is relatively mature expansion support, which will surely play a positive role in promoting the entire Alibaba MCU ecosystem.
|