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.

CCS/MSP432E401Y: configure telnet services using (udpecho)sample code with static IP?

Part Number: MSP432E401Y

Tool/software: Code Composer Studio

I've followed the instructions in a related post for successfully establishing a static IP for the device based on the udpecho example code.   Now I would like to implement a simple telnet service as well.  Is anyone able to point me in the right direction for setting this up, I'm not finding a lot of documentation on the net or in the forums.

To be clear, I just want an idea of the necessary framework for a telnet service that I can build upon for displaying basic serial output to a (Putty) terminal as opposed to using the TI boards UART.

Thanks

  • Patrick,
    I will need to reach out to one of my colleagues, but I will try an get an answer to you by the end of the week.

    Chris
  • Hello Patrick,

    Did you refer the "telnet" utility in the folder "./sourceti/ndk/nettools/telnet/" of the SimpleLink MSP432E4 SDK?

    I have not used it yet, but is that something that works for you?

    Thanks,
    Sai
  • Hello Sai,

    Thank you. I have started to refer to the telnet utility, and I've also located the NDK API Guide which I'll study. I'll try seeing if these can help me get something configured for my purposes and get back to you later this week if I need any help.

    Thanks,
    Patrick
  • Hello Sai,

    so I did some review, and some digging.   I decided to try using XGCONF to configure a telnet operation.  

    I opened the graphical interface and enabled the NDK Global Network Settings, along with IP, TCP, and TELNET layers.    I then went in and added some custom code to power a couple PWMs and ADCs as well as push some terminal output to a UART display.   Everything compiles nicely, but I can't get a telnet terminal to open.

    I look back into XGCONF and see that there's the "Instance" tab, where I assume you can add a new telnet instance, however when I go to the tab all options and dialogs are disabled.     How do I add a telnet instance?

    I found this older thread (/support/embedded/tirtos/f/355/t/327369) which nicely covers the topic but for an older version of CCS and the NDK, still, everything looks reasonably unchanged.  It seems to imply that I should be able to use the Instance tab of the .cfg file telnet layer to create an instance and callback function.    But obviously something is wrong on my end as I don't have that ability.    Are there some additional steps I should be taking?

    I've used the 'empty_MSP_EXP432E401Y_tirtos_ccs' example as my starting point.   I've made some changes to the board.h files to add in features, but nothing substantive.  The main program I have running now is in empty.c

    /*
     *  ======== empty.c ========
     */
    
    /* For usleep() */
    #include <unistd.h>
    #include <stdint.h>
    #include <stddef.h>
    
    /* Driver Header files */
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/ADC.h>
    #include <ti/display/Display.h>
    #include <ti/drivers/PWM.h>
    // #include <ti/drivers/I2C.h>
    // #include <ti/drivers/SDSPI.h>
    // #include <ti/drivers/SPI.h>
    // #include <ti/drivers/UART.h>
    // #include <ti/drivers/Watchdog.h>
    
    /* Board Header file */
    #include "Board.h"
    //#include <ti/devices/msp432e4/driverlib/driverlib.h>
    
    /* global variableS FOR GUI COMPOSER */
    uint16_t adcValue = 0;
    uint16_t threshold = 2048;
    uint16_t trigger = 0;
    uint8_t cycleCount = 0;
    
    /*
     *  ======== mainThread ========
     */
    void *mainThread(void *arg0)
    {
        /* 1 second delay */
        uint32_t    time = 100;     // update 8/sec
        uint16_t     statusTimer = 100;    // number of cycles per status LED toggle
        //[ PWM variables
        uint16_t   pwm1Period = 3000;
        uint16_t   pwm1duty = 0;
        uint16_t   pwm1dutyInc = 100;
    
        uint16_t   pwm2Period = 3000;
        uint16_t   pwm2duty = 0;
        uint16_t   pwm2dutyInc = 100;
    
        uint16_t    pwmtimer = statusTimer;
        //]
    
        /* Call driver init functions */
        GPIO_init();
        ADC_init();
        Display_init();
        PWM_init();
        // I2C_init();
        // SDSPI_init();
        // SPI_init();
        // UART_init();
        // Watchdog_init();
    
        //[ LEDs
        /* Configure the LED pin */
        GPIO_setConfig(Board_GPIO_LED0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);   // status LED
        GPIO_setConfig(Board_GPIO_LED1, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);   // ADC threshold LED
    
        /* Turn on status LED */
        GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);
        //]
    
        //[ Open the PWM Driver
        PWM_Handle pwm1 = NULL;
        PWM_Params pwm1params;
    
        PWM_Handle pwm2 = NULL;
        PWM_Params pwm2params;
    
        PWM_Params_init(&pwm1params);
        pwm1params.dutyUnits = PWM_DUTY_US;
        pwm1params.dutyValue = 0;
        pwm1params.periodUnits = PWM_PERIOD_US;
        pwm1params.periodValue = pwm1Period;
        pwm1 = PWM_open(Board_PWM0, &pwm1params);
        if (pwm1 == NULL) {
            /* Board_PWM0 did not open */
            while (1);
        }
    
        PWM_Params_init(&pwm2params);
        pwm2params.dutyUnits = PWM_DUTY_US;
        pwm2params.dutyValue = 0;
        pwm2params.periodUnits = PWM_PERIOD_US;
        pwm2params.periodValue = pwm2Period;
        pwm2 = PWM_open(Board_PWM1, &pwm2params);
        if (pwm2 == NULL) {
            /* Board_PWM1 did not open */
            while (1);
        }
    
        PWM_start(pwm1);
        PWM_start(pwm2);
        //]
    
        //[ Open the ADC Driver
        ADC_Handle adc0;
        ADC_Params adc0Params;
        ADC_Params_init(&adc0Params);
        adc0 = ADC_open(Board_ADC0, &adc0Params);
        if (adc0 == NULL)
        {
            // Error initializing ADC channel 0
            while(1);
        }
        //]
    
        //[ Open the display Driver
        Display_Handle    displayHandle;
        Display_Params    displayParams;
        Display_Params_init(&displayParams);
        displayHandle = Display_open(Display_Type_UART, NULL);
        //]
    
        /* Run the main routine */
        while(1) {
            int_fast16_t res;
            uint16_t adc0Value;
            //Display_printf(displayHandle, 1, 0, "In main");
    
            res = ADC_convert(adc0, &adc0Value);
            if(res == ADC_STATUS_SUCCESS) {
                Display_printf(displayHandle, 1, 0, "ADC Reading %d", adc0Value);
                if(adc0Value >= threshold) {        // arbitrary threshold
                    GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_ON);
                    trigger = 1;
                }
                else {
                    GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_OFF);
                    trigger = 0;
                }
            }
            cycleCount++;
    
            if(cycleCount == pwmtimer) {
                PWM_setDuty(pwm1, pwm1duty);
                pwm1duty = (pwm1duty + pwm1dutyInc);
                if (pwm1duty == pwm1Period || (!pwm1duty)) {
                    pwm1dutyInc = - pwm1dutyInc;
                }
    
                PWM_setDuty(pwm2, pwm2duty);
                pwm2duty = (pwm2duty + pwm2dutyInc);
                if (pwm2duty == pwm2Period || (!pwm2duty)) {
                    pwm2dutyInc = - pwm2dutyInc;
                }
            }
    
            if(cycleCount == statusTimer) {
                GPIO_toggle(Board_GPIO_LED0);
                cycleCount = 0;
            }
    
            usleep(time);
        }
    }
    

  • Okay, well I figured out how to create the telnet instance, so that's no longer the problem.   But now I'm having trouble understanding how to define the callback function.   Is there a good demo or example somewhere on how to define this for a telnet service?   I don't have a lot of experience with this, so any help is appreciated.\

    Patrick.

  • Hello Sai,

    Sorry for this running commentary. I think I figured out the callback function. I'm having the telnet service call the ndk default ConsoleOpen function. But now I get this error on build that tells me there's something incorrect in the way the console is being instantiated, I think.

    unresolved symbol VerStr, first referenced in C:\ti\simplelink_msp432e4_sdk_2_20_00_20\source\ti\ndk\tools\console\lib\console_min_ipv4.aem4f<console.oem4f>

    I traced this to what I think is something in .\source\ti\ndk\tools\console\console.c But now I'm stuck. Why would it be giving this error? Is there some additional #include i need to put into my empty.c file? I see that VerStr is a char pointer "extern char *VerStr;" but not sure what to do with it.

    Thanks for any help you can provide.

    Patrick.
  • Hi Patrick,

    You've pretty much figured it out. The ConsoleOpen function is the correct function to set for Telnet.

    The "VerStr" issue is a known one, you just need to define it as a global variable somewhere in your app. This was typically done in the 'netHooks.c' file in older examples:

    char *VerStr = "\nNDK Telnet Console\n"; // you can set this to say whatever you want ...

    Steve
  • Steve,

    Thank you very much for your help with this, but I'm seemingly still running into problems getting the telnet service to run consistently.  Using the stock udpecho example I defined a telnet instance but when I initialize the program I get a "failed" status for the telnet.

    Here is what the UART display terminal displays:

    the main changes I've made to the udpecho sample code are to define an initTelnet function which I call in the ndkStackThread along with the other initialization functions for IP, TCP and UDP.   I also created a second serviceReport function to have the telnet service call which is exactly identical to the existing serviceReport function in the example code.  

    Here is the initTelnet function:

    /*
     *  ===== initTelnet =====
     *  Configure a telnet instance
     *  see spru524k_ndk_api_ref p.96
     */
    static void initTelnet(void *hCfg)
    {
        CI_SERVICE_TELNET telnet;
    
        //bzero(&telnet, sizeof(telnet));
        memset(&telnet, NULL, sizeof(telnet));
        telnet.cisargs.Mode   = CIS_FLG_CALLBYIP | CIS_FLG_RESTARTIPTERM;
        telnet.cisargs.IfIdx  = 2;
        telnet.cisargs.IPAddr = INADDR_ANY;
        telnet.cisargs.pCbSrv = &serviceReportTelnet;
        telnet.param.MaxCon = 2;
        telnet.param.Port   = 23;
        telnet.param.Callback = &ConsoleOpen;
        CfgAddEntry(hCfg, CFGTAG_SERVICE, CFGITEM_SERVICE_TELNET, 0,
                    sizeof(telnet), (unsigned char *)&telnet, NULL);
    
    }

    here is the serviceReportTelnet function:

    /*
     *  ======== serviceReportTelnet ========
     *  Function for reporting service status updates.
     */
    static char *taskNameTelnet[] = {"Telnet", "HTTP", "NAT", "DHCPS", "DHCPC", "DNS"};
    static char *reportStrTelnet[] = {"", "Running", "Updated", "Complete", "Fault"};
    static char *statusStrTelnet[] =
            {"Disabled", "Waiting", "IPTerm", "Failed","Enabled"};
    static void serviceReportTelnet(uint32_t item, uint32_t status, uint32_t report,
            void *h)
    {
        Display_printf(display, 0, 0, "Service Status: %-9s: %-9s: %-9s: %03d\n",
                       taskNameTelnet[item - 1], statusStrTelnet[status], reportStrTelnet[report / 256],
                report & 0xFF);
    }

    and here is the modified ndkStackThread function:

    /*
     *  ======== ndkStackThread ========
     *  NDK stack's main thread function
     */
    static void ndkStackThread(uintptr_t arg0, uintptr_t arg1)
    {
        void *hCfg;
        int rc;
        timer_t ndkHeartBeat;
        struct sigevent sev;
        struct itimerspec its;
        struct itimerspec oldIts;
        int ndkHeartBeatCount = 0;
    
        /* create the NDK timer tick */
        sev.sigev_notify = SIGEV_SIGNAL;
        sev.sigev_value.sival_ptr = &ndkHeartBeatCount;
        sev.sigev_notify_attributes = NULL;
        sev.sigev_notify_function = &llTimerTick;
    
        rc = timer_create(CLOCK_MONOTONIC, &sev, &ndkHeartBeat);
        if (rc != 0) {
            Display_printf(display, 0, 0,
                    "ndkStackThread: failed to create timer (%d)\n");
        }
    
        /* start the NDK 100ms timer */
        its.it_interval.tv_sec = 0;
        its.it_interval.tv_nsec = 100000000;
        its.it_value.tv_sec = 0;
        its.it_value.tv_nsec = 100000000;
    
        rc = timer_settime(ndkHeartBeat, 0, &its, NULL);
        if (rc != 0) {
            Display_printf(display, 0, 0,
                    "ndkStackThread: failed to set time (%d)\n");
        }
    
        rc = NC_SystemOpen(NC_PRIORITY_LOW, NC_OPMODE_INTERRUPT);
        if (rc) {
            Display_printf(display, 0, 0,
                    "ndkStackThread: NC_SystemOpen Failed (%d)\n");
        }
    
        /* create and build the system configuration from scratch. */
        hCfg = CfgNew();
        if (!hCfg) {
            Display_printf(display, 0, 0,
                    "ndkStackThread: Unable to create configuration\n");
            goto main_exit;
        }
    
        /* IP, TCP, UDP, and Telnet config */
        initIp(hCfg);
        initTcp(hCfg);
        initUdp(hCfg);
        initTelnet(hCfg);
    
        /* config low priority tasks stack size */
        rc = 2048;
        CfgAddEntry(hCfg, CFGTAG_OS, CFGITEM_OS_TASKSTKLOW, CFG_ADDMODE_UNIQUE,
                sizeof(uint32_t), (unsigned char *)&rc, NULL);
    
        /* config norm priority tasks stack size */
        rc = 2048;
        CfgAddEntry(hCfg, CFGTAG_OS, CFGITEM_OS_TASKSTKNORM, CFG_ADDMODE_UNIQUE,
                sizeof(uint32_t), (unsigned char *)&rc, NULL);
    
        /* config high priority tasks stack size */
        rc = 2048;
        CfgAddEntry(hCfg, CFGTAG_OS, CFGITEM_OS_TASKSTKHIGH, CFG_ADDMODE_UNIQUE,
                sizeof(uint32_t), (unsigned char *)&rc, NULL);
    
        do
        {
            rc = NC_NetStart(hCfg, networkOpen, networkClose, networkIPAddr);
        } while(rc > 0);
    
        /* Shut down the stack */
        CfgFree(hCfg);
    
    main_exit:
        NC_SystemClose();
    
        /* stop and delete the NDK heartbeat */
        its.it_value.tv_sec = 0;
        its.it_value.tv_nsec = 0;
    
        rc = timer_settime(ndkHeartBeat, 0, &its, &oldIts);
    
        rc = timer_delete(ndkHeartBeat);
    
        Display_printf(display, 0, 0, "ndkStackThread: exiting ...\n");
    }

    The remainder of the udpecho example code is unchanged.

    I'm assuming that I'm doing something wrong in either the way I've defined the telnet instance, or maybe in how I call the init routine, but I can't seem to figure it out.   

    Just in case it helps, I've attached the complete ndk_tirtos.c file.       

    ndk_tirtos.c
    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    /*
    * Copyright (c) 2017-2018, Texas Instruments Incorporated
    * All rights reserved.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions
    * are met:
    *
    * * Redistributions of source code must retain the above copyright
    * notice, this list of conditions and the following disclaimer.
    *
    * * Redistributions in binary form must reproduce the above copyright
    * notice, this list of conditions and the following disclaimer in the
    * documentation and/or other materials provided with the distribution.
    *
    * * Neither the name of Texas Instruments Incorporated nor the names of
    * its contributors may be used to endorse or promote products derived
    * from this software without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    */
    /*
    * ======== ndk_tirtos.c ========
    */
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/ndk/inc/netmain.h>
    #include <ti/ndk/inc/os/oskern.h>
    #include <signal.h>
    #include <time.h>
    #include <ti\ndk\inc\tools\console.h>
    #include <ti/display/Display.h>
    /* Socket file descriptor table */
    #define MAXSOCKETS 10
    uint32_t ti_ndk_socket_max_fd = MAXSOCKETS;
    void *ti_ndk_socket_fdtable[MAXSOCKETS];
    extern Display_Handle display;
    /* NDK memory manager page size and number of pages [used by mmAlloc()] */
    #define RAW_PAGE_SIZE 3072
    #define RAW_PAGE_COUNT 6
    const int ti_ndk_config_Global_rawPageSize = RAW_PAGE_SIZE;
    const int ti_ndk_config_Global_rawPageCount = RAW_PAGE_COUNT;
    /* P.I.T. (page information table) */
    #ifdef __ti__
    #pragma DATA_SECTION(ti_ndk_config_Global_pit, ".bss:NDK_MMBUFFER");
    #pragma DATA_SECTION(ti_ndk_config_Global_pitBuffer, ".bss:NDK_MMBUFFER");
    PITENTRY ti_ndk_config_Global_pit[RAW_PAGE_COUNT];
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    I hope you can point me to whatever it is I'm still doing wrong.   

    Thank you

    Patrick

  • Well,

    I never got the telnet service to operate reliably.   I worked around the issue by defining my own connection socket and interface console.  

**Attention** This is a public forum