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/EK-TM4C1294XL: UDP receive stops working after 12 packets (1 byte each) regardless of send time-interval.

Part Number: EK-TM4C1294XL

Tool/software: TI-RTOS

I am trying to setup my Tiva to receive single byte packets over UDP.  I have had some success: I can receive packets correctly. However, after 12 consecutive packets (1 byte per packet), I can no longer receive. Specifically, the fdSelect function hangs with no timeout, or times out if I give it one. I have pinpointed that it fdSelect calls fdPoll and that is the hang up. Here is my code:

//
//  Configure UDP
//
#define UDPPORT 5005


/** Setup the UDP task.
 * This hook is called when the device connects to the network,
 * and the connection becomes available for usage.
 */
Void networkOpenHook()
{
    Task_Handle taskHandle;
    Task_Params taskParams;
    Error_Block eb;

    // Ensure that the error block is initialized.
    Error_init(&eb);

    // Create the UDP task handler.
    // The first argument is the the port that the task listens to.
    // Set this to be a high priority task.
    Task_Params_init(&taskParams);
    taskParams.stackSize = 1024;
    taskParams.priority = 1;
    taskParams.arg0 = UDPPORT;
    taskHandle = Task_create((Task_FuncPtr) udpHandler, &taskParams, &eb);
    if (taskHandle == NULL)
        System_printf("Failed to create udpHandler task.\n");
}

Void udpHandler(UArg arg0, UArg arg1)
{
    SOCKET lSocket;
    struct sockaddr_in sLocalAddr;
    struct sockaddr_in client_addr;
    struct timeval to;
    fd_set readfds;
    int addrlen = sizeof(client_addr);
    int status;
    HANDLE hBuffer;
    IPN LocalAddress = 0;

    Int nbytes;
    Bool flag = TRUE;
    Char* buffer;

    fdOpenSession(TaskSelf());

    lSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (lSocket < 0) {
        System_printf("udpHandler: socket failed\n");
        Task_exit();
        return;
    }

    memset((char *)&sLocalAddr, 0, sizeof(sLocalAddr));
    sLocalAddr.sin_family = AF_INET;
    //sLocalAddr.sin_len = sizeof(sLocalAddr);
    sLocalAddr.sin_addr.s_addr = LocalAddress;
    sLocalAddr.sin_port = htons(arg0);

    status = bind(lSocket, (struct sockaddr *)&sLocalAddr, sizeof(sLocalAddr));
    if (status < 0) {
        System_printf("udpHandler: bind failed: returned: %d, error: %d\n", status, fdError());
        fdClose(lSocket);
        Task_exit();
        return;
    }

    to.tv_sec = 5;
    to.tv_usec = 0;

    // Loop while we receive data
    static uint32_t trigger_count = 0;
    while (flag) {
        FD_ZERO(&readfds);
        FD_SET(lSocket, &readfds);

        if (fdSelect(0, &readfds, NULL, NULL, &to) != 1) {
            status = fdError();
            System_printf("timed out waiting for client\n", status);
            System_printf("udpHandler: received %u triggers so far\n", trigger_count);
            System_flush();
            continue;
        }

        nbytes = recvncfrom(lSocket, (void **)&buffer, MSG_WAITALL, (struct sockaddr *)&client_addr, &addrlen, &hBuffer);

        if (nbytes >= 0) {
            // If reply byte was received, then echo it.
            uint8_t data = *((uint8_t*) buffer);
            if (data == 0xAA) {
                sendto(lSocket, (char*) &data, 1, 0, (struct sockaddr *)&client_addr, sizeof(client_addr));
                recvncfree(hBuffer);
                System_printf("udpHandler: Echo'd  %u to client.\n", data);
            } else {
                trigger_count++;
                System_printf("udpHandler: Received %u from client.\n", data);
            }
        }
        else {
            status = fdError();
            if (status == EWOULDBLOCK) {
                System_printf("udpHandler: Waiting for client to send UDP data.\n");
                continue;
            }
            else {
                System_printf(
                    "udpHandler: recvfrom failed: returned: %d, error: %d\n",
                    nbytes, status);
                fdClose(lSocket);
                flag = FALSE;
            }
        }
    }

    System_printf("udpHandler: received %u triggers\n", trigger_count);
    System_printf("udpHandler stop, lSocket = 0x%x\n", lSocket);
    System_flush();

    if (lSocket) {
        fdClose(lSocket);
    }

    fdCloseSession(TaskSelf());

    /*
     *  Since deleteTerminatedTasks is set in the cfg file,
     *  the Task will be deleted when the idle task runs.
     */
    Task_exit();
}

/*
 *  ======== main ========
 */
int main(void)
{
    /* Call board init functions */
    Board_initGeneral();
    Board_initEMAC();
    Board_initGPIO();

     /* Turn on user LED */
    GPIO_write(Board_LED0, Board_LED_ON);

    // Initialize the config_t to use the global solenoids
    global_config.solenoids = global_solenoids;
    global_config.num_solenoids = NUM_SOLENOIDS;

    System_printf("Starting the 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);
}

I don't know if it matters, but In addition to the UDP code, I am running the HTTP server as well (successfully). 

 

  • Hi Cody,

    I'm assigning this thread to an engineer, but to get the ball rolling, which TI-RTOS for TIvaC version are you using?

    Todd
  • I am using TI-RTOS for TivaC version 2.16.00.08.

    Thanks,
    Cody
  • Cody,

    I tried to reproduce your failure case, but so far it has been working. Maybe there is some interaction between the UDP thread and the http server?

    Does the failure happen only with 1-byte packets or any size packet?

    I installed TI-RTOS 2.16.00.08, built the udpEcho example, and ran it with the client sending 1 byte packets. It seems to work fine. Maybe you can use the same setup as a baseline.

    To help us debug further, would you try the following. In your CCS Expression window, enter the following two variables and expand them to see the individual elements.

    udps
    EMACSnow_private

    With your target program running, turn on the continuous refresh button in the Expression window. You should see the numbers update about every second.

    I would expect to see EMACSnow_private.rxCount constantly increasing about 4 counts per second. Without the udpSendReceive client running, you might see udps.RcvTotal increase occasionally, but not too much.  Run the client application for a few seconds; you should see udps.RcvTotal increasing significantly.

    When you experience the UDP thread lockup, does upds.RcvTotal continue to increase or not? How about EMACSnow_private.rxCount?  Do you see EMACSnow_private.rxDropped start to increase?

    This information should help us track down the issue.

    I will continue to investigate on my end.

    ~Ramsey

  • Ramsey,

    Using my code still (which is udpEcho modified to only echo if a certain byte is received) I went ahead and watched udps.RcvTotal,  EMACSnow_private.rxCount, and EMACSnow_private.rxDropped. I found that after the 12 1-byte packets, none of those values continue increasing.

    So I changed my code to always echo back the received data, like the udpEcho program. Now everything works as expected, and I can continue to receive packets indefinitely. This will work for me, I was just thinking that it was unnecessary to always echo. I am interested if you have an idea why it is necessary to send a reply back to the client? As far as I understand UDP, the protocol itself doesn't require it. 

    Thanks,

    Cody

  • Cody,

    I agree, the UDP protocol does not require return packets. It might have something to do with the program that is sending UDP packets to your board. I assume you have written your own or modified the udpSendReceive sample program.

    In the udpSendReceive program, it sends a buffer of data (256 bytes) and then waits for any data coming back. If nothing comes back after a millisecond, it re-sends the buffer again and waits again. It does this because UDP is a "lossy" transport.

    Once *any* data returns, the program drops into a loop waiting for the entire buffer to be returned.

    However, there might be a problem with this logic. When the original buffer was sent, it might have been fragmented into smaller packets (maybe 64 bytes). Some of these packets could get dropped. When the Tiva receives packets, it simply sends them back. It does not know how many packets to expect for each buffer. Therefore, the udpSendReceive program might get stuck waiting for the full buffer of data to be returned, but if any packets were lost, it will wait forever and thus never send any more data.

    I'm wondering it this could be the issue you are seeing. If your Tiva program consumes packets without returning them, then the sending program might be waiting for data which will never come and not send any more packets. This is just a guess on my part.

    ~Ramsey