1552 views|1 replies

8

Posts

0

Resources
The OP
 

[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.

  1. Use CDK to add the ntp package to the project file.
  2. 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;
    }

  3. 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;

  4. 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.

Latest reply

Indeed, IOT is flourishing now, and I recently discovered that many of them are open source. Xuantie open source E906 open source information: https://github.com/T-head-Semi/opene906?spm=a2cl5.25269445.0.0.5da5180fmPCxYb YoC open source: https://github.com/T-head-Semi/open-yoc?spm=a2cl5.25269445.0.0.5da5180fmPCxYb Xuantie toolchain open source: https://github.com/T-head-Semi/xuantie-gnu-toolchain?spm=a2cl5.25269445.0.0.5da5180fmPCxYb   Details Published on 2022-5-11 18:47
 
 

6818

Posts

11

Resources
2
 

Indeed, IOT is flourishing now, and I recently discovered that many of them are open source.

Xuantie open source E906 open source information:
https://github.com/T-head-Semi/opene906?spm=a2cl5.25269445.0.0.5da5180fmPCxYb

YoC open source:
https://github.com/T-head-Semi/open-yoc?spm=a2cl5.25269445.0.0.5da5180fmPCxYb

Xuantie toolchain open source:
https://github.com/T-head-Semi/xuantie-gnu-toolchain?spm=a2cl5.25269445.0.0.5da5180fmPCxYb

 
 
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list