This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C129ENCPDT: NTP server help

Part Number: TM4C129ENCPDT

Tool/software:

Hello, I am learning how to program NTP time that uses a statically defined hostname. I am reading the user guide and I'm having some confusion on where I should be expected to call the CfgAddEntry( hCfg, CFGTAG_SYSINFO, CFGITEM_DHCP_DOMAINNAMESERVER, 0, sizeof(IPTmp), (UINT8 *)&IPTmp, 0 ); through callback as described. Any help would be appreciated.

  • Hi Kevin,

      I'm not an expert on how to use CfgAddEntry. Reading the NDK user's guide, there is a example snippet of code calling CfgAddEntry inside a ServiceReport hook function which is described in section 2.1.4.1.3 Using a Statically Defined DNS Server. 

      In the .cfg file, you can add the Status Report Hook function. See below. 

    Please also refer to these posts that maybe useful. 

    https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1248260/tm4c129encpdt-netipaddrhook-function-doesn-t-execute-after-a-specific-time

      https://e2e.ti.com/support/processors-group/processors/f/processors-forum/505226/handling-dhcp-client-timeout

  • Hi Charles. Yes I do believe I have it set up in a similar way. I am using a callback hook function similarly described the the NDK user's guide.

    I am going through the debugger on this section, and I am getting a situation where I am unable to access this condition due to not satisfying the Report conditions. I am receiving a Report value of 256 integer, but if I am right, these two conditions are looking for integer values 273 and 275?

    (Status == CIS_SRV_STATUS_ENABLED &&
    (Report == (NETTOOLS_STAT_RUNNING|DHCPCODE_IPADD) ||
    Report == (NETTOOLS_STAT_RUNNING|DHCPCODE_IPRENEW)))

    I am a bit confused as to how I can further read into the Report values and what I am receiving.

  • Hi Kevin,

    I am receiving a Report value of 256 integer, but if I am right, these two conditions are looking for integer values 273 and 275?

    When you are in the ServiceReport function, what is the TaskName? What does it print out when calling:

    static void ServiceReport( uint32_t Item, uint32_t Status, uint32_t Report, void *h )
    {
    printf( "Service Status: %-9s: %-9s: %-9s: %03d\n",
    TaskName[Item-1], StatusStr[Status], ReportStr[Report/256], Report&0xFF );

      I think the example  code in the NDK user's guide is merely to show how to manually add a DNS server address when the DHCP client is in use.  Therefore, it is checking if Item == CFGITEM_SERVICE_DHCPCLIENT as follows. 

    //
    // Service Status Reports
    //
    static char *TaskName[] = { "Telnet","HTTP","NAT","DHCPS","DHCPC","DNS" };
    static char *ReportStr[] = { "","Running","Updated","Complete","Fault" };
    static char *StatusStr[] = { "Disabled","Waiting","IPTerm", "Failed","Enabled" };
    static void ServiceReport( uint32_t Item, uint32_t Status, uint32_t Report, void *h )
    {
    printf( "Service Status: %-9s: %-9s: %-9s: %03d\n",
    TaskName[Item-1], StatusStr[Status], ReportStr[Report/256], Report&0xFF );

    // Example of adding to the DHCP configuration space
    //
    // When using the DHCP client, the client has full control over access
    // to the first 256 entries in the CFGTAG_SYSINFO space. Here, we want
    // to manually add a DNS server to the configuration, but we can only
    // do it once DHCP has finished its programming.
    //
    if( Item == CFGITEM_SERVICE_DHCPCLIENT &&
    Status == CIS_SRV_STATUS_ENABLED &&
    (Report == (NETTOOLS_STAT_RUNNING|DHCPCODE_IPADD) ||
    Report == (NETTOOLS_STAT_RUNNING|DHCPCODE_IPRENEW)) )

    While I'm not an expert in NTP and the various NDK services, I find several posts about using sntp. I hope they may be helpful to you. 

    https://e2e.ti.com/support/wireless-connectivity/wi-fi-group/wifi/f/wi-fi-forum/725932/cc3220sf-launchxl-cc3220sf-sntp-server/2678374#2678374

    https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/684349/tm4c1294ncpdt-how-to-call-startntp-function/2521942#2521942

    https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/695654/rtos-msp432e401y-looking-for-sntp-client-that-can-achieve-10-ms-accuracy

    I also find the below example that uses SNTP. 

    /*
     *  ======== sntp.c ========
     *  SNTP Client example application
     */
    #include <string.h>
    #include <time.h>
    
    /* XDCtools Header files */
    #include <xdc/runtime/Error.h>
    #include <xdc/runtime/System.h>
    
    /* TI-RTOS Header files */
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/hal/Seconds.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/drivers/GPIO.h>
    #include <ti/net/http/httpcli.h>
    #include <ti/net/sntp/sntp.h>
    
    /* Example/Board Header file */
    #include "Board.h"
    
    #include <sys/socket.h>
    
    /*
     * NTP server and port to obtain network time and number of servers to attempt
     */
    #define NTP_HOSTNAME "north-america.pool.ntp.org"
    #define NTP_PORT         "123"
    #define NTP_SERVERS      3
    #define NTP_SERVERS_SIZE (NTP_SERVERS * sizeof(struct sockaddr_in))
    #define NTPTASKSTACKSIZE 2048
    
    /*
     * Time Zone Adjustment.
     * TODO: Adjust your local time zone with respect to Greenwich Mean Time (GMT)
     * For example, North America Central Time Zone is 6 hours behind GMT
     */
    #define CENTRAL_TIME_ADJUST -6*60*60
    #define TIME_ZONE_ADJUST CENTRAL_TIME_ADJUST
    
    unsigned char ntpServers[NTP_SERVERS_SIZE];
    static Semaphore_Handle semHandle = NULL;
    
    /*
     *  ======== printError ========
     */
    void printError(char *errString, int code)
    {
        System_printf("Error! code = %d, desc = %s\n", code, errString);
        BIOS_exit(code);
    }
    
    /*
     *  ======== timeUpdateHook ========
     *  Called after NTP time sync
     */
    void timeUpdateHook(void *p)
    {
        Semaphore_post(semHandle);
    }
    
    /*
     *  ======== startNTP ========
     *  This is the function that generates the request to the NTP server for network time.
     */
    void startNTP(void)
    {
        int ret;
        int currPos;
        time_t ts;
        struct sockaddr_in ntpAddr;
        struct addrinfo hints;
        struct addrinfo *addrs;
        struct addrinfo *currAddr;
        Semaphore_Params semParams;
    
        /*
         * Clear the addrinfo first.
         */
        memset(&hints, 0, sizeof(struct addrinfo));
    
        /*
         * Use SOCK_DGRAM (UDP) as the socket type
         */
        hints.ai_family = AF_INET;
        hints.ai_socktype = SOCK_DGRAM;
    
        /*
         * First resolve the IP Address of the NTP server using the DNS service..
         * The getaddrinfo can return a linked-list of IP addresses
         */
        ret = getaddrinfo(NTP_HOSTNAME, NTP_PORT, NULL, &addrs);
        if (ret != 0) {
            printError("startNTP: NTP host cannot be resolved!", ret);
        }
    
        currPos = 0;
    
        /*
         * Loop through the NTP servers
         */
        for (currAddr = addrs; currAddr != NULL; currAddr = currAddr->ai_next) {
            if (currPos < NTP_SERVERS_SIZE) {
                ntpAddr = *(struct sockaddr_in *)(currAddr->ai_addr);
                /*
                 * Copy the list of NTP servers to netServers
                 */
                memcpy(ntpServers + currPos, &ntpAddr, sizeof(struct sockaddr_in));
                currPos += sizeof(struct sockaddr_in);
            }
            else {
                break;
            }
        }
    
        freeaddrinfo(addrs);
    
        /*
         * Initialize and start the SNTP client Task. Called to create and start SNTP
         * client Task and Semaphores. User must pass in pointers to functions for
         * getting and setting the current time and the list of NTP servers to
         * communicate with. timeUpdateHook() is called upon successful time
         * synchronization.
         */
        ret = SNTP_start(Seconds_get, Seconds_set, timeUpdateHook,
                (struct sockaddr *)&ntpServers, NTP_SERVERS, 0);
        if (ret == 0) {
            printError("startNTP: SNTP cannot be started!", -1);
        }
    
        /*
         * Create a semaphore that will block until after successful NTP time
         * synchronization.  Once unblocked, we will print the current time to the
         * console.
         */
        Semaphore_Params_init(&semParams);
        semParams.mode = Semaphore_Mode_BINARY;
        semHandle = Semaphore_create(0, &semParams, NULL);
        if (semHandle == NULL) {
            printError("startNTP: Cannot create semaphore!", -1);
        }
    
        SNTP_forceTimeSync();
        /*
         * Wait here until the semaphore is posted.
         */
        Semaphore_pend(semHandle, BIOS_WAIT_FOREVER);
    
        /*
         * Adjust for the Central Time Zone.
         */
        Seconds_set((unsigned int)((int)Seconds_get()+TIME_ZONE_ADJUST));
        ts = time(NULL);
    
        /*
         * Print the current time to the console.
         */
        System_printf("Current time: %s\n", ctime(&ts));
        System_flush();
    
    }
    
    /*
     *  ======== netIPAddrHook ========
     *  This function is called when IP Addr is added/deleted
     */
    void netIPAddrHook(unsigned int IPAddr, unsigned int IfIdx, unsigned int fAdd)
    {
        static Task_Handle taskHandle;
        Task_Params taskParams;
        Error_Block eb;
    
        /* Create a NTP task when the IP address is added */
        if (fAdd && !taskHandle) {
            Error_init(&eb);
    
            Task_Params_init(&taskParams);
            taskParams.stackSize = NTPTASKSTACKSIZE;
            taskParams.priority = 1;
            taskHandle = Task_create((Task_FuncPtr)startNTP, &taskParams, &eb);
            if (taskHandle == NULL) {
                printError("netIPAddrHook: Failed to create NTP Task\n", -1);
            }
        }
    }
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
        /* Call board init functions */
        Board_initGeneral();
        Board_initGPIO();
        Board_initEMAC();
    
        /* Turn on user LED */
        GPIO_write(Board_LED0, Board_LED_ON);
    
        System_printf("Starting the SNTP example\nSystem provider is set to "
                "SysMin. Halt the target to view any SysMin contents in ROV.\n");
        /* SysMin will only print to the console when you call flush or exit */
        System_flush();
    
        /* Start BIOS */
        BIOS_start();
    
        return (0);
    }

  • Hi Charles,

    The current response that is being printed for the task is DHCPC.

    To be more specific, here is the direct console output.

    Service Status: DHCPC : Enabled : : 000
    Service Status: DHCPC : Enabled : Running : 000
    Service Status: DHCPC : Disabled : : 000

  • Hi Charles,

    I've read through your resources and they're helpful for developing the NTP Client and thanks for your help thus far.

    I suppose the question I have is less related to the NTP client itself and more around setting a static DNS server to translate an NTP hostname to IP. However, when I execute the following line the status return code is 0.

    IPTmp = ntohl(stellarisEthernetConfig.dns_ip1);
    if(IPTmp){
    status = CfgAddEntry(0, CFGTAG_SYSINFO, CFGITEM_DHCP_DOMAINNAMESERVER, 0, sizeof(IPTmp), (UINT8 *)&IPTmp, 0); 

    From reading the API, it means that it has been added but not processed. I'm unsure what this means and what potential issues could be causing it to happen.

  • Hi Kevin,

      Sorry, I'm really not an expert in NDK to answer your question. I find the below threads that discuss about using CFGITEM_DHCP_DOMAINNAMESERVER flag when calling CfgAddEntry. Hopefully, they will provide some hints to your question. You can also do additional e2e searches. Please also make sure your board is connecting to the Internet, not being blocked by firewall or requiring some proxy to get to the internet. 

    https://e2e.ti.com/support/processors-group/processors/f/processors-forum/522740/getting-ip-subnet-mask-gateway-ip-dns-ip-while-dhcp-is-enabled/1913719?tisearch=e2e-sitesearch&keymatch=thread%3A522740#1913719

     https://e2e.ti.com/support/processors-group/processors/f/processors-forum/580994/rtos-tm4c129encpdt-getting-external-dns-server-name-on-ppp-connection/2134004?tisearch=e2e-sitesearch&keymatch=CFGITEM_DHCP_DOMAINNAMESERVER#2134004

    https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/991644/msp432e401y-ndk-dhcp-client-options/3664100?tisearch=e2e-sitesearch&keymatch=CFGITEM_DHCP_DOMAINNAMESERVER#3664100

    https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/894296/ccs-tm4c1294ncpdt-function-dnsgethostbyname-solving-wrong-ip?tisearch=e2e-sitesearch&keymatch=CFGITEM_DHCP_DOMAINNAMESERVER#

    https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/832937/msp432e401y-adding-external-dns-does-not-work-when-using-static-ip-address?tisearch=e2e-sitesearch&keymatch=CFGITEM_DHCP_DOMAINNAMESERVER#

  • Hi Charles,

    I did ensure that the board is connected to the internet, and the resources did help in giving me some insight on the matter. However, I am still running into some issues.

    Right now, after executing CfgAddEntry() I am getting a return value of 0. I stepped through the function and found that the program is getting tripped up at this step in the config.c file of the NDK package. I suspect that the configuration may not be active, but unsure what would be the cause.

    /* If the configuration is active, we process the entry */
    pe->Active = pc->Active;
    if( pe->Active )
    returncode = _CfgEntryProcess( pc, CFGOP_ADD, pe );
    else
    returncode = 0;

    I attached the code of my network hook and the corresponding service report, hopefully that can give some context.

     

    static char *TaskName[]  = {"Telnet","HTTP","NAT","DHCPS","DHCPC","DNS"};
    static char *ReportStr[] = {"","Running","Updated","Complete","Fault"};
    static char *StatusStr[] = {"Disabled","Waiting","IPTerm","Failed","Enabled"};
    Void ti_ndk_config_Global_serviceReport(uint Item, uint Status,
            uint Report, HANDLE h)
    {
        xdc_runtime_System_printf("Service Status: %-9s: %-9s: %-9s: %03d\n",
                TaskName[Item-1], StatusStr[Status],
                ReportStr[Report/256], Report&0xFF);
    
        {
            extern Void networkStatusHook();
    
            /* call user defined status report hook */
            networkStatusHook(Item, Status, Report, h);
        }
        xdc_runtime_System_flush();
    }

    void networkStatusHook(uint Item, uint Status, uint Report, HANDLE h)
    {
      ULONG tmpIP;
      ULONG err;
      IPN IPTmp;
      int status;
    
      tempvar1 = Item;
      tempvar2 = Status;
      tempvar3 = Report & 0xFF;
      tempvar4 = Report & 0xFF00;
    
      //System_printf("item: %x\nstatus: %x\nreport: %x\nhandle: %x\n", Item, Status, Report, h);
      //System_flush();
    
      //Item compares
      // #define CFGITEM_SERVICE_TELNET          0x0001
      // #define CFGITEM_SERVICE_HTTP            0x0002
      // #define CFGITEM_SERVICE_NAT             0x0003
      // #define CFGITEM_SERVICE_DHCPSERVER      0x0004
      // #define CFGITEM_SERVICE_DHCPCLIENT      0x0005
      // #define CFGITEM_SERVICE_DNSSERVER       0x0006
      // #define CFGITEM_SERVICE_MAX             0x0006
    
      //Status Compares
      //#define CIS_SRV_STATUS_DISABLED 0x0000     // Config not active
      //#define CIS_SRV_STATUS_WAIT     0x0001     // Waiting on IP resolve
      //#define CIS_SRV_STATUS_IPTERM   0x0002     // Service terminated via IP synch
      //#define CIS_SRV_STATUS_FAILED   0x0003     // Service failed to initialize
      //#define CIS_SRV_STATUS_ENABLED  0x0004     // Service enabled
    
    #if defined(EE_I2C) && defined(TI_SYSBIOS)
      WAIT_FOR_EE_INIT_FINISH;
    #endif
    
      switch (Item) {
        case CFGITEM_SERVICE_DHCPCLIENT:
          //Report & 0xFF00 compares to
          //#define NETTOOLS_STAT_NONE              0
          //#define NETTOOLS_STAT_RUNNING           0x100
          //#define NETTOOLS_STAT_PARAMUPDATE       0x200
          //#define NETTOOLS_STAT_COMPLETED         0x300
          //#define NETTOOLS_STAT_FAULT             0x400
    
          //Report & 0xFF compares to
          //#define DHCPCODE_IPADD          0x11    // Client has added an address
          //#define DHCPCODE_IPREMOVE       0x12    // IP address removed and CFG erased
          //#define DHCPCODE_IPRENEW        0x13    // IP renewed, DHCP config space reset
          // This callback will be called if the DHCP client is successfully able to add an IP entry after finding a dhcp server
    
    #ifdef __DNSTESTMODE
            //testing if cfgaddentry will work
            IPTmp = ntohl(stellarisEthernetConfig.dns_ip1);
            temp_ip = IPTmp;
            if(IPTmp){
                status = CfgAddEntry(0, CFGTAG_SYSINFO, CFGITEM_DHCP_DOMAINNAMESERVER, 0, sizeof(IPTmp), (UINT8 *)&IPTmp, 0);
                temp_status = status;
            }
    #endif
    
          if (Status == CIS_SRV_STATUS_ENABLED && ((Report & 0xFFF) == (DHCPCODE_IPADD | NETTOOLS_STAT_RUNNING))) {
            dhcpComplete = TRUE;
            dhcpRunning = FALSE;
            //System_printf("Got IP Address\n");
            //System_flush();
    /*
            if(CfgGetImmediate(0, CFGTAG_SYSINFO, CFGITEM_DHCP_DOMAINNAMESERVER, 1, sizeof(tmpIP), (UBYTE*)&tmpIP)){
              stellarisEthernetConfig.dns_ip1 = conv_endian_long(tmpIP);
            }
    */
            networkUp = TRUE;
          }
          else if (Status == CIS_SRV_STATUS_ENABLED && ((Report & 0xFF) == DHCPCODE_IPREMOVE)) {
            System_printf("IP address removed and CFG erased\n");
            //System_flush();
          }
          else if (Status == CIS_SRV_STATUS_ENABLED && ((Report & 0xFF) == DHCPCODE_IPRENEW)) {
            System_printf("IP renewed, DHCP config space reset\n");
            //System_flush();
          }else if (Status == CIS_SRV_STATUS_ENABLED &&
                  (Report == (NETTOOLS_STAT_RUNNING|DHCPCODE_IPADD) ||
                          Report == (NETTOOLS_STAT_RUNNING|DHCPCODE_IPRENEW))){
    
              IPTmp = ntohl(stellarisEthernetConfig.dns_ip1);
              if(IPTmp){
                  status = CfgAddEntry(0, CFGTAG_SYSINFO, CFGITEM_DHCP_DOMAINNAMESERVER, 0, sizeof(IPTmp), (UINT8 *)&IPTmp, 0);
              }
          }
          // This callback is called if the DHCP client task timesout before finding a dhcp server and adding a valid IP entry
          else if ((Status == CIS_SRV_STATUS_ENABLED) && (Item == CFGITEM_SERVICE_DHCPCLIENT) && (Report & (NETTOOLS_STAT_FAULT | 0x02))) {
            //the magic 0x02 above is from ti/ndk/nettools/dhcp/dhcp.h and indicates that the fault
            //occurred because the dhcp client task never successfully found a dhcp server and timedout out in the INIT state (dhcpsm.c)
            // if DHCP timed out with a network cable plugged in, then there would have been a chance
            // to get an IP address, so if it didn't work the first time, it likely would not work
            // the next time either.
            if (is_network_present())
            {
              add_staticIP(); // fall back to static IP since cable is plugged in. DHCP entry and spawned client task will be removed by the NDK
              dhcp_timedout = TRUE;
    
              System_printf("DHCP timeout, reverting to static IP: ");
              IPTmp = ntohl(stellarisEthernetConfig.staticIP);
              System_printf("%d.%d.%d.%d\n", (UINT8) IPTmp & 0xFF, (UINT8) (IPTmp >> 8) & 0xFF, (UINT8) (IPTmp >> 16) & 0xFF, (UINT8) (IPTmp >> 24) & 0xFF);
              System_flush();
            }
            else {
              System_printf("DHCP timed out, without cable connected, reconnect cable for another chance.\n");
              System_flush();
            }
            dhcpRunning = FALSE;
          }
          break;
        default:
    
          break;
      }
      //System_printf("Item %d, Status %d, Report %d, h %d\n", Item, Status, Report, h);
      //System_flush();
    }
    

  • Hi Kevin,

      Although I don't know for sure what is causing the problem, reading the NDK's developer guide, it seems to suggest you need to link to the correct NETCTRL library that will support DNS, DHCPSEVER and etc. See below. For details, refer to https://www.ti.com/lit/pdf/SPRU523J. I wonder if you have linked to the correct library when the XDCtools generates the stacks. Can you please double check if this is the case. 

    In your .cfg file, do you have the DNS and DHCP server (if also need DHCP server) added? See below where you can add DNS and DHCP. Click on them to add them so that the correct library will be linked.