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.

CC3220SF-LAUNCHXL: How to Send uint16_t Data to Desktop Client from HTTP Server on CC3220

Part Number: CC3220SF-LAUNCHXL
Other Parts Discussed in Thread: CC3220SF, SYSCONFIG, SYSBIOS

Hi,

I have to send the multiple (ex. 10000 samples per second) uint16_t data (raw ADC Data) from CC3220SF HTTP Based Server on the HTTP GET request from client. 

Can someone let me know how to perform the same?

Thank you.

Best Regards,

Kuldeep

  • Hi Kuldeep,

    I recommend you take a look at the Out of Box demo, which demonstrates reading from onboard sensors like the accelerometer via its internal web server. You will find the example code in the "out of box" example in the SDK.

    Also, see Chapter 9 HTTP Server of the Network Processor Guide.

    Best regards,

    Jesse

  • Thanks Jesse,

    It helped me a lot to understand the functionality.

    Now my requirement is to send  a  uint16 array of size 64*10=640 data in each 200ms. 

    I have tried to send the data directly copying to a data buffer structure as below - 

     

    //Created Buffer
    
    
    #define DATA_BUFFER_SIZE (1280)
    
    struct DataBufferStruct {
        int len;
        char data[DATA_BUFFER_SIZE];
    };
    
    extern struct DataBufferStruct DataBuffer;
    
    int send_data(void* dat, int len);

    //Function to update the DataBuffer 
    
    
    int send_data(void* data, int len)
    {
        // Append data to global DataBuffer
        if (DataBuffer.len + len >= DATA_BUFFER_SIZE+1) // Buffer overflow
        {
            sprintf(DataBuffer.data, "BUFFER OVERFLOW");
            DataBuffer.len = strlen(DataBuffer.data);
            return -1;
        }
    
        memcpy(DataBuffer.data + DataBuffer.len, data, len);
        DataBuffer.len += len;
    
        return 0;
     }

    //Test Thread to put the data in the DataBuffer after each 1 sec (for test). This thread will be used to receive the data from the ADC output.
    
    
    uint16_t testData[640] = {645,745,842,931,1011,1080,1138,1185,1222,1250,1270,1283,1290,1290,1283,1269,1247,1220,1188,1152,1114,1077,1041,1006,973,941,908,874,835,793,747,697,645,594,544,498,456,417,382,350,318,285,250,214,176,139,103,71,43,22,8,1,1,8,21,41,69,106,153,211,280,360,449,546,645,745,842,931,1011,1080,1138,1185,1222,1250,1270,1283,1290,1290,1283,1269,1247,1220,1188,1152,1114,1077,1041,1006,973,941,908,874,835,793,747,697,645,594,544,498,456,417,382,350,318,285,250,214,176,139,103,71,43,22,8,1,1,8,21,41,69,106,153,211,280,360,449,546,645,745,842,931,1011,1080,1138,1185,1222,1250,1270,1283,1290,1290,1283,1269,1247,1220,1188,1152,1114,1077,1041,1006,973,941,908,874,835,793,747,697,645,594,544,498,456,417,382,350,318,285,250,214,176,139,103,71,43,22,8,1,1,8,21,41,69,106,153,211,280,360,449,546,645,745,842,931,1011,1080,1138,1185,1222,1250,1270,1283,1290,1290,1283,1269,1247,1220,1188,1152,1114,1077,1041,1006,973,941,908,874,835,793,747,697,645,594,544,498,456,417,382,350,318,285,250,214,176,139,103,71,43,22,8,1,1,8,21,41,69,106,153,211,280,360,449,546,645,745,842,931,1011,1080,1138,1185,1222,1250,1270,1283,1290,1290,1283,1269,1247,1220,1188,1152,1114,1077,1041,1006,973,941,908,874,835,793,747,697,645,594,544,498,456,417,382,350,318,285,250,214,176,139,103,71,43,22,8,1,1,8,21,41,69,106,153,211,280,360,449,546,645,745,842,931,1011,1080,1138,1185,1222,1250,1270,1283,1290,1290,1283,1269,1247,1220,1188,1152,1114,1077,1041,1006,973,941,908,874,835,793,747,697,645,594,544,498,456,417,382,350,318,285,250,214,176,139,103,71,43,22,8,1,1,8,21,41,69,106,153,211,280,360,449,546,645,745,842,931,1011,1080,1138,1185,1222,1250,1270,1283,1290,1290,1283,1269,1247,1220,1188,1152,1114,1077,1041,1006,973,941,908,874,835,793,747,697,645,594,544,498,456,417,382,350,318,285,250,214,176,139,103,71,43,22,8,1,1,8,21,41,69,106,153,211,280,360,449,546,645,745,842,931,1011,1080,1138,1185,1222,1250,1270,1283,1290,1290,1283,1269,1247,1220,1188,1152,1114,1077,1041,1006,973,941,908,874,835,793,747,697,645,594,544,498,456,417,382,350,318,285,250,214,176,139,103,71,43,22,8,1,1,8,21,41,69,106,153,211,280,360,449,546,645,745,842,931,1011,1080,1138,1185,1222,1250,1270,1283,1290,1290,1283,1269,1247,1220,1188,1152,1114,1077,1041,1006,973,941,908,874,835,793,747,697,645,594,544,498,456,417,382,350,318,285,250,214,176,139,103,71,43,22,8,1,1,8,21,41,69,106,153,211,280,360,449,546,645,745,842,931,1011,1080,1138,1185,1222,1250,1270,1283,1290,1290,1283,1269,1247,1220,1188,1152,1114,1077,1041,1006,973,941,908,874,835,793,747,697,645,594,544,498,456,417,382,350,318,285,250,214,176,139,103,71,43,22,8,1,1,8,21,41,69,106,153,211,280,360,449,546};
    
    //uint16_t testData[2] = {0x56BA, 0x2349};
    
    /**/
    void *testThread(void* arg0)
    {
    
        while (1)
        {
            send_data(testData, 1280);
            sleep(1);
        }
    }
    

    //When there is a http request for the test data then below is the response for the same - 
      int payload_len = strlen((const char*) gPayloadBuffer);
    
        // while (*argcCallback > 0)
        // {
            // ...
        // }
    
    
        // Copy all data from Global buffer to payload
        memcpy((void *)pPayload, DataBuffer.data, DataBuffer.len);
        payload_len += DataBuffer.len;
    
        // Null terminate the payload
        pPayload[DataBuffer.len] = '\0';
    
        // Reset global Data Buffer
        DataBuffer.len = 0;
    
        //metadataLen = prepareGetMetadata(0, strlen((const char *)gPayloadBuffer), HttpContentTypeList_UrlEncoded);
        metadataLen = prepareGetMetadata(0, payload_len, HttpContentTypeList_UrlEncoded);
    
        metadataLen = prepareGetMetadata(0, strlen((const char *)gPayloadBuffer), HttpContentTypeList_UrlEncoded);
    
        sl_NetAppSend (netAppRequest->Handle, metadataLen, gMetadataBuffer, (SL_NETAPP_REQUEST_RESPONSE_FLAGS_CONTINUATION | SL_NETAPP_REQUEST_RESPONSE_FLAGS_METADATA));
        Display_printf(display, 0, 0, "[Http server task] Metadata Sent, len = %d ", metadataLen);
    
        sl_NetAppSend (netAppRequest->Handle, strlen ((const char *)gPayloadBuffer), gPayloadBuffer, 0); /* mark as last segment */
        Display_printf(display, 0, 0, "[Http server task] Data Sent, len = %d", strlen ((const char *)gPayloadBuffer));

    The Response to the request is as below when I access this from the a laptop, which contain the data sent but along with that it has C2, C3 etc. as shown below - 

      

    C28502C3A9024A03C2A303C3B3033804
    7204C2A104C38604C3A204C3B6040305
    0D0A050D0A050305C3B504C39F04C384
    04C2A404C280045A0435041104C3AE03
    C38D03C2AD03C28C036A0343031903C3
    AB02C2B902C2850252022002C3B201C3
    8801C2A1017E015E013E011D01C3BA

    that too incomplete. 

    what is wrong going here ?

    Is this the correct way to send the data in binary format ?

    Should I first convert the array in string and then sent ?

     

    Regards,

    Kuldeep

  • Hi Kuldeep,

    Yes, you can try converting the array into a string and then sending to see if it displays properly on the laptop.

    You can also start with a known working example like the out of box demo or this Wi-Fi HTTP Server lab in the SimpleLink Academy, and edit it for your use case: https://dev.ti.com/tirex/explore/node?node=AKNlsGY7AbtkzVvTPm66qw__fc2e6sr__LATEST

    The HTTP Server Lab uses these HTTP server files: https://dev.ti.com/tirex/explore/node?node=ADokazZfJ2yBW-QoOaEHCw__fc2e6sr__LATEST 

    Best regards,

    Jesse

  • Hi Jesse,

    Thank you for the references.

    I tried sending strings and that is working fine.

    But I don't want to send the data as string as I need to convert my integer array to string and the size also will be more for the string format. So overall it will increase the computation and memory requirements.

    So I am thinking to send the data directly from the memory as it is. 

    So is it possible the send these data as png or other format. My final motive is to store the data in a file from where i can perfrom further operations required.

    Please suggest if anything else other than string can be done.

    Thanks and Regards,

    Kuldeep

  • Hi Kuldeep,

    You can try sending the data in binary format by updating the content type in the prepareGetMetadata() function. The HTTP content type list is in httpserver.h. Try using HttpContentTypeList_ApplicationOctecStream instead of HttpContentTypeList_UrlEncoded.

    typedef enum
    {
    /* Content types list */
        HttpContentTypeList_TextHtml,
        HttpContentTypeList_TextCSS,
        HttpContentTypeList_TextXML,
        HttpContentTypeList_ApplicationJson,
        HttpContentTypeList_ImagePNG,
        HttpContentTypeList_ImageGIF,
        HttpContentTypeList_TextPlain,
        HttpContentTypeList_TextCSV,
        HttpContentTypeList_ApplicationJavascript,
        HttpContentTypeList_ImageJPEG,
        HttpContentTypeList_ApplicationPDF,
        HttpContentTypeList_ApplicationZIP,
        HttpContentTypeList_ShokewaveFlash,
        HttpContentTypeList_AudioXAAC,
        HttpContentTypeList_ImageXIcon,
        HttpContentTypeList_TextVcard,
        HttpContentTypeList_ApplicationOctecStream,
        HttpContentTypeList_VideoAVI,
        HttpContentTypeList_VideoMPEG,
        HttpContentTypeList_VideoMP4,
        HttpContentTypeList_UrlEncoded,
    }HttpContentTypeList;

    Best regards,

    Jesse

  • Hi Jesse,

    Thank you for suggestions.

    I had converted the data into the string and it was working.

    After this, I were able to send some data from C2000 to CC3220SF using SPI and then same to HTTP Client. The Data size from C2000 to CC3220sf is 640Bytes. I have handshaking (Similar to Master and Slave Demo Code) between CC3220SF and C2000 Before sending any data. The Data are send after each 100ms. There is a GET request from the HTTP client after each 100ms for data. The spi data is send to HTTP GET Callback using a timed MSGQUEUE and then converted to a string and send as the response of the request (If queue is empty then after 1ms queue returns -1 and the send string will be empty string).

    Initially, I have created another GET request (user input from client) which post a Semaphore for the handshaking which start the spi communication and then post the data using msg queue. When there is GET request after each 100ms and as the data present in the queue so callback function will process the data to convert it to string and then send to client using sl_NetAppSend(). This is working whenever I have request from user. But when I am trying to send the data after each 100ms continuously (receiving data from c2000 using SPI at the interval of 100ms and then posting in the queue from the SPI thread in cc3220 to the GET callback)  its getting stuck and stops sending data.

    I am trying to figure out the issue but still no success. Can you please help with the same?

    Thanks & Regards,

    Kuldeep

  • Hi Kuldeep,

    Have you set breakpoints to see when/where exactly your code is getting stuck?

    When you say:

    This is working whenever I have request from user. But when I am trying to send the data after each 100ms continuously (receiving data from c2000 using SPI at the interval of 100ms and then posting in the queue from the SPI thread in cc3220 to the GET callback)  its getting stuck and stops sending data.

    Are you saying that it works when you are sending the data in response to the GET request from the client? In the case where it gets stuck and stops sending data, are you calling sl_NetAppSend() without a GET request from the client?

    Best regards,

    Jesse

  • Hi Jesse,

    I have two GET requests as below - 

    1. 

    	
    	var rawDataStart = true;
    	
    	function getRawData(){
    		if(rawDataStart)
    		{
    			ajaxCall('/raw', "GET", "raw", respRaw);
    		}
    	}

    This is called after each 100ms as shown below - 

    	function startRawData() 
    	{
    	    rawDataInterval = setInterval(getRawData, 100);
    	}

    Response of this at server is as below - 

    int32_t rawGetCallback(uint8_t requestIdx, uint8_t *argcCallback, uint8_t **argvCallback, SlNetAppRequest_t *netAppRequest)
    {
        uint8_t *pPayload;
        uint16_t metadataLen;
        int16_t i, msgSize;
        int32_t retVal;
    
        char rawDataStr[1300];
        uint16_t queueMsg[320];
    
        struct timespec rawts;
    
        /* timeout is 0 to send the message immediatelly */
        rawts.tv_sec = 1;
        rawts.tv_nsec = 0;
    
        pPayload = gPayloadBuffer;
    
    
    
        retVal =mq_timedreceive(i1DataMQueue, (char *)&queueMsg, 640, 0, &rawts);
    
        if(retVal < 0)
        {
            strcpy(rawDataStr, "");
        }
        else
        {
            clock_gettime(CLOCK_REALTIME, &rawts);
            sprintf( &rawDataStr[0],  "%d,",rawts.tv_sec);
    
            for(i = 0; i < 319;i++)
            {
                sprintf( &rawDataStr[ strlen(rawDataStr) ],  "%d,", queueMsg[i] );
            }
            sprintf( &rawDataStr[ strlen(rawDataStr) ],  "%d", queueMsg[319] );
        }
    
    
        // Prepares payload
        sl_Memcpy (pPayload,rawDataStr, strlen(rawDataStr));
        msgSize = strlen(rawDataStr);
        pPayload += msgSize;
    
        /* NULL terminate the payload */
        *(pPayload) = '\0';
    
        metadataLen = prepareGetMetadata(0, msgSize, HttpContentTypeList_TextPlain);
    
        sl_NetAppSend (netAppRequest->Handle, metadataLen, gMetadataBuffer, (SL_NETAPP_REQUEST_RESPONSE_FLAGS_CONTINUATION | SL_NETAPP_REQUEST_RESPONSE_FLAGS_METADATA));
        Display_printf(display, 0, 0, "[Http server task] Metadata Sent, len = %d ", metadataLen);
    
        pPayload = gPayloadBuffer;
        if(msgSize > 1024)
        {
            sl_NetAppSend (netAppRequest->Handle, 1024, pPayload, SL_NETAPP_REQUEST_RESPONSE_FLAGS_CONTINUATION); /* middle segment */
            pPayload +=1024;
            msgSize -=1024;
        }
        sl_NetAppSend (netAppRequest->Handle, msgSize, pPayload, 0); /* mark as last segment */
    
        return 0;
    }

    which get the data from the SPI transition when available otherwise it will just return -1 when there is not data on timed queue after time elapse. convert that to string and send as the response.

     

    2. While, the user request is called on the button press in browser.

    //I have linked the user request with LED ON OFF because with this I can know if the user request is properly placed or not 
    
    
    	function rawDataGet(val){
    		var vsend = "redled="+val;
    		ajaxCall('/usrRqst', "post", vsend, rawDataGetResp);
    			if($('#lightCircle').hasClass('lightOff')){
    				$('#lightCircle').removeClass('lightOff');
    				$('#lightCircle').addClass('lightOn');
    		} else {
    			if($('#lightCircle').hasClass('lightOn')){
    				$('#lightCircle').removeClass('lightOn');
    				$('#lightCircle').addClass('lightOff');
    			}
    		}
    	}
    

    POSTuserCallback will post_sem() and the sem wait in userThread will get executed which will enable handshaking with C2000 and then the spi transition starts. On finish this will do the send_queue().

    As both URLs and Threads are independent so this should not have any issue. 

    Do you see any issue in this?

    As both SPI and HTTP communication with C2000 and HTTP client involved so not able to put the breakpoint on required location because of handshaking between c2000 and cc3220SF.

    I am able to send 320 data at a time from c2000 to cc3220sf(SPI) and cc3220sf to http client(using http) on user request at http client but that to is not happening after sometime as handshaking stops but without http handshaking before SPI data transfer between c2000 and c3220sf is working fine for any duration.

    Please let me know your suggestions.

    Thanks & Regards,

    Kuldeep

  • Hi Kuldeep,

    Sorry for the delay--I will reply by end of day tomorrow.

    Best regards,

    Jesse

  • Hey Kuldeep,

    It looks like your 2nd point above:

    2. While, the user request is called on the button press in browser.
    • This is a POST request, not a GET request -- ajaxCall('/usrRqst', "post", vsend, rawDataGetResp);

    • In the POST processing section of the HTTP Server chapter  of the NWP User's guide, it states that for POST requests, there is no way to return payload data as part of the response, only HTTP headers as part of the meta-data.

    Can you clarify what you mean by the application getting stuck? Is data not being received from the C2000? Is data not being sent from the CC3220SF to the HTTP client in response to the GET requests?

    You should be able to place breakpoints or add debug prints to the GET callback function to further debug.

    Best regards,

    Jesse

  • Hi Jesse,

    Thank you for suggestion.

    Breakpoint at GET Callback is working. I am able to see that the data are getting received properly from the C2000. And able to send the data to http client.

    You are correct about second point that its a POST request. I am not responding to that request back with my raw data. The raw data are the response of the other GET call which is  ajaxCall('/raw', "GET", "raw", respRaw). When I received the post request then I am just posting a semaphore for Master GPIO State change on CC3220SF which will create a external interrupt on the C2000. And C2000 will start the SPI communication.

    Once the Data received the response Callback function for the GET Request  will get the data from the queue ( data from the SPI RX on the SPI Thread). 

    Issue is not all the time, it occurs when I try to get multiple user requests and then SPI transmission stops after some time.

    Also, when I tried to send Application/OctecStream data its making some data to be "\xef\xbf\xbd\x0f" while the data was "\xe1\x0f" or 0x0FE1. Can you please help how to get correct data ? Is gzip or deflate encoding is the issue? If yes how to resolve it?

    Thanks & Regards,

    Kuldeep 

  • Hi Jesse,

    I have tried to debug the issue, I feel that the issue is due to simultaneous use of SPI by HTTP and communication between C2000 and CC3220SF.

    Whenever I am doing alternate data transfer (first between cc3220SF and C2000  and then to send the data to HTTP client from CC3220SF) its working perfectly fine.

    Below is the sysconfig snapshot.

    Can you please suggest how I can put a mutex between http transfer request and CC3220-C2000 SPI communication?  or any other way to overcome this issue.

    As per documentation, Network  SPI is different then General Purpose SPI. Is my understanding not correct or the configuration which I did above is incorrect. 

    Thanks & Regards,

    Kuldeep 

  • Hi Kuldeep,

    Could you try re-posting your sysconfig snapshot? I can't see it in your previous post.

    You are correct, the SPI for communicating with the NWP is different from the general purpose SPI.

    As for implementing a mutex:

    • documentation on mutexes can be found in the Thread Communication section of the TI-RTOS basics guide. See "Semaphore Example 2".

    • there is a mutex example in the SDK under C:\ti\simplelink_cc32xx_sdk_6_10_00_05\examples\rtos\CC3220SF_LAUNCHXL\sysbios\mutex that can be imported into CCS

    Best regards,

    Jesse

  • Hi Jesse,

    Please find the below snapshot of the sysconfig for the SPI configuration - 

    Also, can you please suggest if the queue is full will it create a issue or the data will be get over  written with the next coming data.

    I am trying to send the SPI Data to http get response using queue. 

    Regarding Mutex, I was asking where to put the mutex lock in http request so it doesn't block the SPI.

    when I am using mutext lock in getcallback and spi transmission then Its doing its work but getting stuck if the queue becomes full.

    What can be the issue?

     

    Thank You,

    Best Regards,

    Kuldeep

  • Hi Jesse,

    I tried to debug again and found that if I connect the ADC input to the C2000 which is connected to CC3220SF using SPI. When I place a HTTP request from the client then I see that my CC3220SF is getting stuck as below - 

    Can you please check if this issue is known or why I am getting stuck there.

    When I place a request to CC3220SF HTTP Server from a client without connecting an Input to c2000. I am able to send the data to the client and its not getting stuck at that infinite loop.

    Is it related to some hardware issue?

    Thank You.

    Best Regards,

    Kuldeep

  • Hi Kuldeep,

    I am not aware of this issue. I will check internally.

    Best regards,

    Jesse

  • Hey Kuldeep,

    There are several different reasons you could be getting stuck in a Hwi. It could be stack overflow or you could be doing something improperly in an interrupt routine.

    You can get more information on this using the debugging features and tools in CCS: https://dev.ti.com/tirex/content/simplelink_academy_cc32xxsdk_6_10_00_00/modules/rtos/tirtos_basics/tirtos_basics.html#debugging-features-and-tools

    Runtime Object View and System Analyzer should be helpful to continue to debug.

    Best regards,

    Jesse

  • Hi Jesse,

    Thank you for the suggestion.

    I will try the same and come back to you.

    Is there any chance of same SPI resource to be used by for http communication and communication with C2000 ? I am asking this because when I used mutex between http send response and spi data transfer, it started working fine for some user requests. 

    Can you let me know any example which uses the SPI for the HTTP communication as well as for the SPI data transfer to other MCU or other device?

    Thank you.

    Best Regards,

    Kuldeep

  • Hey Kuldeep,

    I'm not aware of any examples that demonstrate HTTP communication as well as SPI data transfer to another device, but this should not be an issue as the SPI instances for communicating with the NWP and for interfacing with the C2000 are different.

    Best regards,

    Jesse

  • Hi Jesse,

    Thank you for your response.

    I have one more question.

    Can we transmit more then  1364 as the response of a GET request?

    I tried keeping SL_NETAPP_REQUEST_RESPONSE_FLAGS_CONTINUATION flag in in-between segments but time out is happening.

    Can you give a example where more then 1364 data has been transmitted as the response of GET Request in HTTP protocol.

    Thank you.

    Best Regards,

    Kuldeep

  • Hey Kuldeep,

    See section 9.7.2.1 Fragmentation of the NWP Guide. "Fragmentation must be used to transfer resources larger than 1500 bytes (the maximal size of a single fragment). While there are more fragments to send, the SL_NETAPP_REQUEST_RESPONSE_FLAGS_CONTINUATION bit must be set in the flags parameter of the API. On the last fragment, this bit must be zero. The first call to sl_NetAppSend API must carry the metadata (HTTP headers) of the response. For that, the SL_NETAPP_REQUEST_RESPONSE_FLAGS_METADATA bit must be set in the flags parameter of the API.

    Part 2 of Figure 9-11 shows a GET request with fragmentation and the example code on p. 181 (just before section 9.7.3 POST Processing) shows an example of using fragmentation.

    Best regards,

    Jesse