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.

RTOS/TM4C1294NCPDT: RTOS

Part Number: TM4C1294NCPDT

Tool/software: TI-RTOS

Working on a project with UDP communication.  The requirement is to send status data periodically over ethernet.   I modified the udpecho.c example.   In this I created another task for sending the data.  I tried to use the same socket created from receiver task. The code snippet below.   Here select, bytesSent1 and FD_ISSET returns -1.  Could you guide me how to do this.   inserting the modified UDpecho.c file

Void ethcmdxmit(UArg arg0, UArg arg1)
{
    int                bytesSent1;
    int                status;
    UInt posted;
    for (;;) {
        System_printf("In ethcmdxmit Task\n");
        System_flush();
        posted = Event_pend(getPstsEvtHandle(), Event_Id_NONE, Event_Id_01, BIOS_WAIT_FOREVER);
       if(sockcreated)
        {
       if(!isXmitQEmpty())
         {
           System_printf("Queue updated\n");

            tbuff=retrieveXmitQ();
            FD_ZERO(&readSet);
            FD_SET(server, &readSet);
            addrlen = sizeof(clientAddr);
            /* Wait forever for the reply */
            status = select(server + 1, &readSet, NULL, NULL, NULL);
            System_printf("status = %d\n", status);
            System_printf("error = %d\n", fdError());
 //           if (status > 0) {
                if (FD_ISSET(server, &readSet)) {
             bytesSent1=sendto(server, tbuff, 5, 0,  (struct sockaddr *)&clientAddr, addrlen);
             System_printf("bytesSent1 inside loop = %d\n", bytesSent1);
                }
                System_printf("bytesSent1 = %d\n", bytesSent1);
 //           }
            System_flush();
         }
     }
    } //for loop
}
/*
 * Copyright (c) 2015, 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.
 */

/*
 *    ======== udpEcho.c ========
 *    Contains BSD sockets code.
 */

#include <string.h>

#include <xdc/std.h>
#include <xdc/cfg/global.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Error.h>

#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/drivers/GPIO.h>

/* NDK BSD support */
#include <sys/socket.h>

/* Example/Board Header file */
#include "Board.h"
#include "ethcmd.h"
#include "vdsutils.h"
#include "pstatus.h"

#define UDPPORT 4000
#define UDPPACKETSIZE 256
    char *tbuff;
 /* prototype definition */

    Void ethcmdxmit(UArg arg0, UArg arg1);
    Void initEthXmitter(void);
    Void testtask(UArg arg0, UArg arg1);
    Void ethstsSend(UArg arg0, UArg arg1);

    int                server;
    fd_set             readSet;
    fd_set             wrSet;
    struct sockaddr_in localAddr;
    struct sockaddr_in clientAddr;
    socklen_t          addrlen;
    Bool sockcreated=FALSE;
/*
 *  ======== echoFxn ========
 *  Echoes UDP messages.
 *
 */
Void echoFxn(UArg arg0, UArg arg1)
{
    int                bytesRcvd;
    int                bytesSent;
    int                bytesSent1;
    int                status;
//    int                server;
//    fd_set             readSet;
//    struct sockaddr_in localAddr;
//    struct sockaddr_in clientAddr;
//    socklen_t          addrlen;
    char               buffer[UDPPACKETSIZE];
    char               custombuff[9]={1,2,3,4,5,6,7,8,9};
    char               tbf[5]= {0x23,0x45,0x67,0x89,0x90};

    ethMsgObj ethrecvmsg;
    Event_Handle tEvt;
    Mailbox_Handle tMbx;

    server = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (server == -1) {
        System_printf("Error: socket not created.\n");
        goto shutdown;
    }

    memset(&localAddr, 0, sizeof(localAddr));
    localAddr.sin_family = AF_INET;
    localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    localAddr.sin_port = htons(arg0);

    status = bind(server, (struct sockaddr *)&localAddr, sizeof(localAddr));
    if (status == -1) {
        System_printf("Error: bind failed.\n");
        goto shutdown;
    }
    else sockcreated=TRUE;
    System_printf("socket creation finished.\n");
    System_flush();
    do {
        /*
         *  readSet and addrlen are value-result arguments, which must be reset
         *  in between each select() and recvfrom() call
         */
        FD_ZERO(&readSet);
        FD_SET(server, &readSet);
        addrlen = sizeof(clientAddr);

        /* Wait forever for the reply */
        status = select(server + 1, &readSet, NULL, NULL, NULL);
        if (status > 0) {
            if (FD_ISSET(server, &readSet)) {
                bytesRcvd = recvfrom(server, buffer, UDPPACKETSIZE, 0,
                        (struct sockaddr *)&clientAddr, &addrlen);

                if (bytesRcvd > 0) {
                    bytesSent = sendto(server, buffer, bytesRcvd, 0,
                            (struct sockaddr *)&clientAddr, addrlen);
                    bytesSent1=sendto(server, custombuff, 9, 0,
                                      (struct sockaddr *)&clientAddr, addrlen);
  //                copyCharArry(buffer,ethrecvmsg.msgbuf,30 );
  //                tMbx=getCmdMailboxHndle();
  //             Mailbox_post(tMbx, &ethrecvmsg, TIMEOUT);
                   postCmdMBoxMsg(buffer,30 );
                    if (bytesSent < 0 || bytesSent != bytesRcvd) {
                        System_printf("Error: sendto failed.\n");
                        goto shutdown;
                    }
                }
            }
        }
       if(!isXmitQEmpty())
        {


           tbuff=retrieveXmitQ();
  //    copyCharArry(tbuff, tbf,5 );
            bytesSent1=sendto(server, tbuff, 5, 0,
                                                  (struct sockaddr *)&clientAddr, addrlen);
        }

    } while (status > 0);

shutdown:
    if (server > 0) {
        close(server);
    }
}

/*
 *  ======== main ========
 */
int main(void)
{
    /* Call board init functions */
    Board_initGeneral();
    Board_initGPIO();
    Board_initEMAC();
    initEthCmd();
    initEthXmitter();
 //   initTestTask();
    initPstatus();
    /* Turn on user LED */
    GPIO_write(Board_LED0, Board_LED_ON);

    System_printf("Starting the UDP Echo 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();
    System_printf("Just testing\n");
    System_flush();
    /* Start BIOS */
    BIOS_start();

    return (0);
}

Void initEthXmitter(void)
{


    Task_Handle taskHandle;
    Task_Params taskParams;
    Error_Block eb;
    /* Make sure Error_Block is initialized */
    Error_init(&eb);

    Task_Params_init(&taskParams);
     taskParams.stackSize = 1024;
     taskParams.priority = 4;
     taskParams.arg0 = UDPPORT;
     taskHandle = Task_create((Task_FuncPtr)ethcmdxmit, &taskParams, &eb);
     if (taskHandle == NULL) {
         System_printf("main: Failed to create ethcmdxmit Task\n");
     }

}

Void initTestTask(void)
{


    Task_Handle taskHandle;
    Task_Params taskParams;
    Error_Block eb;
    /* Make sure Error_Block is initialized */
    Error_init(&eb);

    Task_Params_init(&taskParams);
     taskParams.stackSize = 1024;
     taskParams.priority = 3;
     taskParams.arg0 = UDPPORT;
     taskHandle = Task_create((Task_FuncPtr)testtask, &taskParams, &eb);
     if (taskHandle == NULL) {
         System_printf("main: Failed to create ethcmdxmit Task\n");
     }

}
Void testtask(UArg arg0, UArg arg1)
{
    for (;;) {
        System_printf("In test Task\n");
        System_flush();
    }

}
Void ethcmdxmit(UArg arg0, UArg arg1)
{
    int                bytesSent1;
    int                status;
    UInt posted;
    for (;;) {
        System_printf("In ethcmdxmit Task\n");
        System_flush();
        posted = Event_pend(getPstsEvtHandle(), Event_Id_NONE, Event_Id_01, BIOS_WAIT_FOREVER);

       if(sockcreated)
        {
       if(!isXmitQEmpty())
         {
           System_printf("Queue updated\n");


            tbuff=retrieveXmitQ();
            FD_ZERO(&readSet);
            FD_SET(server, &readSet);
            addrlen = sizeof(clientAddr);

            /* Wait forever for the reply */
            status = select(server + 1, &readSet, NULL, NULL, NULL);
            System_printf("status = %d\n", status);
            System_printf("error = %d\n", fdError());
 //           if (status > 0) {
                if (FD_ISSET(server, &readSet)) {
             bytesSent1=sendto(server, tbuff, 5, 0,  (struct sockaddr *)&clientAddr, addrlen);
             System_printf("bytesSent1 inside loop = %d\n", bytesSent1);
                }
                System_printf("bytesSent1 = %d\n", bytesSent1);

 //           }
            System_flush();
         }
     }
    } //for loop

}

Void initEthsend(void)
{


    Task_Handle taskHandle;
    Task_Params taskParams;
    Error_Block eb;
    /* Make sure Error_Block is initialized */
    Error_init(&eb);

    Task_Params_init(&taskParams);
     taskParams.stackSize = 1024;
     taskParams.priority = 4;
     taskParams.arg0 = UDPPORT;
     taskHandle = Task_create((Task_FuncPtr)ethstsSend, &taskParams, &eb);
     if (taskHandle == NULL) {
         System_printf("main: Failed to create ethcmdxmit Task\n");
     }

}
Void ethstsSend(UArg arg0, UArg arg1)
{

}
Void psidletask(UArg arg0, UArg arg1)
{

}
  • Ramesh,

    It seems that you want to have two tasks on the server sending data to the same client. One task (echoFxn) is sending the data it received from the client and the other task (ethcmdxmit) is sending status data to the client. The status task does this periodically.

    Have I go this correct?

    The problem is that you cannot have two tasks calling select() at the same time with the same socket. You need to create a new socket for the second task. In addition, the client needs to establish both connections.

    I suggest that your status task first calls bind() on a different port. In your client code, have it connect to both ports. This will establish two channels of communication.

    On the client, you can either use two tasks (one for each socket) or use one task and place both sockets into the call to select. But on the server side, you will need two tasks, each managing one channel of data.

    When you get a return value of -1 from select(), you can call fdError() to get the actual error code. Lookup the error code in /ti/ndk/inc/serrno.h for details.

    ~Ramsey

  • Hi Ramsey

    Actually I am working on the client side. My intention is to use same socket to receive and send UDP data. I am fine with using single task. But the client need to send data periodically to the server as well as should receive the data send from server.


    So if I use echofxn task alone it is getting blocked while calling select function and status could not be send periodically.

    Regards,
    Ramesh
  • Ramesh,

    Your reply indicates you are working on the client side, but the code you attached above is server code. I'm unclear if you want to unblock the task in select() on the server side or the client side.

    It would be helpful to understand your setup. Are you communicating between a PC and the TM4C or between two TM4C boards? Maybe you are using two boards, each running NDK where one is the server and the other is the client?

    In either case, if you are running on the TM4C, using the NDK, you can use fdSelectAbort() to unblock the task in the call to select().

    /ti/ndk/inc/bsd/socketndk.h
     
    void fdSelectAbort(HANDLE hTask)

    This should cause the task in select() to return with -1. From there, you can send your periodic data and then loop around and call select() again.

    However, if you are trying to do this on the PC, then you are not using the NDK. In this case, you can use eventfd().

    #include <sys/eventfd.h>

    int eventfd(unsigned int initval, int flags);

    Here, you create a new file descriptor using eventfd(). Add this file description to your readfds set in the call to select(). When you want to unblock the thread in select(), call write() using the file descriptor. This will make the blocked thread return from select(). Be sure to call read() on the file descriptor, so that you can use it again the next time through the loop.

    ~Ramsey

  • Hi Ramsey,

    Looks like I have to implement the server only.  Actually I was confused with customer requirement of client.   I clarified and current udpecho example should  satisfy the requirements.  

    Will comeback if any help needed.

    Thanks & Regards,

    Ramesh