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.

How to implement a Full Duplex channel over TCP?

Other Parts Discussed in Thread: SYSBIOS

Hello,

I'm using NDK 2.21.01.38 on the EVM6678. I want to use the DSP as a data server and a command handler over TCP sending data to a PC and receiving commands from the PC.

Data should send continuously from DSP -> PC, it should also check to see if there is a message from the PC. If so, process this message, then continue to send the next data packet to PC.

TCP_setup()

while( 1 )

     sendDataToPc()

     if( commandIncomingFromPc )

    { 

        processCommandAndContinue()

    }

}

Is there an example scheme for doing this? I'm working off the echosrv() example, and I have two problems.

1) I cannot figure out how to open and connect two TCP sockets.

2) I can instead use a TCP socket and a UDP socket, in this case TCP for send data, and UDP to receive commands. The problem is that if there is no incoming message on the UDP socket, it blocks there and will not move on to send data on TCP.

Best regards,

Ryan

  • Ryan,

    In UDP socket, how do you determine if there are data received? I don't understand why when there is no data in UDP socket, the TCP send is blocked.

    Regards, Eric

  • Hi Eric,

    I want to continuously stream data over TCP. I also want asynchronous messages to come in over UDP from the PC, so most of the time there will be no packets sent, but occasionally a packet is there. I need a scheme where it won't block waiting for data on UDP.

    Ideally, I would like to use TCP for both channels. As I said above, I can't get both TCP sockets open and connected.

    Thanks,

    Ryan

  • Hi,

    Just use two thread, or use the non blocking operation. See NDK programmer'sreference guide about fdSelect(), fdStatus(), and SO_BLOCKING socket option.

  • Is there a more appropriate way of doing this? 

    1) Using two daemons?

    2) Am I using the listen operation wrong if it is blocking? Can I use it in a non-blocking way instead?

    Ryan

  • I've switched to the server daemon model instead of socket programming. I can successfully use a single daemon to receive a TCP packet from the PC. I want to run another server daemon to stream data to the PC. I can launch the two daemons, but having two daemons breaks the model.

    I have two daemons, 1) daemonTaskCommServer -- it listens for commands from the PC and sets a flag to turn on or off data streaming 2) daemonTaskDataServer -- it streams data from DSP to PC when the flag to stream is turned on. If I never launch daemonTaskDataServer, the CommServer works exactly as intended. When I launch both daemons (CommServer on port 7 and DataServer on port 1000), it gets confused by port assignments. Wireshark shows a complaint that TCP port numbers reused (see attached image for wireshark output).

    Code for the program is below:

    main.c

    int main(void)
    {
        Task_Handle task;
        Task_Params task_params;
        Error_Block eb;
        if(DNUM == 0)
        {
        Error_init(&eb);
            Task_Params_init(&task_params);
            task_params.priority = 5;
            task = Task_create((ti_sysbios_knl_Task_FuncPtr)master_main, &task_params, &eb);
            if(task == NULL)
            {
                System_printf("Task_create() failed!\n");
                return 0;
            }
        }
        master_mbox_receive = Mailbox_create (sizeof(mbox_process_msg_t), 1, 0, 0);
        if(!master_mbox_receive) {
            System_printf("main: Mailbox creation failed for master_mbox_receive\n");
            return 0;
        }
        master_mbox_send = Mailbox_create (sizeof(mbox_response_msg_t), 1, 0, 0);
        if(!master_mbox_send) {
            System_printf("main: Mailbox creation failed for master_mbox_send\n");
            return 0;
        }
        // Create our local servers
         hComm = DaemonNew( SOCK_STREAMNC, 0, 7, daemonTaskCommServer, OS_TASKPRINORM, OS_TASKSTKNORM, 0, 3 );
         if( hComm == NULL )
         {
             platform_write( "failed to create Comm Daemon\n" );
         }
         hData = DaemonNew( SOCK_STREAM, 0, 1000, daemonTaskDataServer, OS_TASKPRINORM, OS_TASKSTKNORM, 0, 3 );
         if( hData == NULL )
         {
             platform_write( "failed to create Data Daemon\n" );
         }
         for( ;; )
         {
             // do nothing
             ;
         }
        int k;
        for( k = 0; k < 2; k++ )
        {
            platform_write( "calling processFrame \n" );
    //        processFrame();
            platform_write( "processFrame complete. \n" );
        }
        platform_write( "calling echosrv()...\n" );
    //    echosrv();
        platform_write( "...echosrv() called.\n" );
    }
    servers.c

    int daemonTaskCommServer( SOCKET s, UINT32 unused )
    {
        struct timeval to;
        int            i;
        char           *pBuf;
        HANDLE         hBuffer;
        (void)unused;
        // Configure our socket timeout to be 5 seconds
        to.tv_sec  = 5;
        to.tv_usec = 0;
        setsockopt( s, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof( to ) );
        setsockopt( s, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof( to ) );
        i = 1;
        setsockopt( s, IPPROTO_TCP, TCP_NOPUSH, &i, 4 );
        for(;;)
        {
            i = (int)recvnc( s, (void **)&pBuf, 0, &hBuffer );
            if( i > 0 )
            {
                if( i == 1 )
                {
                    platform_write( "i = 1\n" );
                    continueSendData = 1;
                }
                else if( i == 2 )
                {
                    platform_write( "i = 2\n" );
                    continueSendData = 0;
                }
                platform_write( "continueSendData is %d\n", continueSendData );
            }
        }
        fdClose( s );
        // Return "0" since we closed the socket
        return(0);
    }
    int daemonTaskDataServer( SOCKET s, UINT32 unused )
    {
        struct timeval to;
        int i;
        uint32_t totalBytes;
        int frameIndex = 0;
        (void)unused;
        // Configure our socket timeout to be 5 seconds
        to.tv_sec  = 5;
        to.tv_usec = 0;
        setsockopt( s, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof( to ) );
        setsockopt( s, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof( to ) );
        i = 1;
        setsockopt( s, IPPROTO_TCP, TCP_NOPUSH, &i, 4 );
        for(;;)
        {
            if( continueSendData )
            {
                 // begin to stream data
                 send( s, dataToOutput, sizeof( dataToOutput ), 0 );
            }
        }
        // we didn't call fdClose(s)
        // Return "1" since the socket is still open
        return(1);
    }



    --- Thanks for your help,

    Ryan

  • I figured it didn't like my CommServer being on the designated Echo port (7), so I assigned it to port 1001 instead. It didn't complain about the reused port, but when I try sending a packet from the PC over the Comm Port, it is never received. It attempts to re-send, and marks the packet with "TCP Keep-Alive". See the image below.

    -Ryan