TI's CC3100 websocket camera demo with Arducam mini ov5642 and freertos. Should work with other M3's. Work in progress test demo.

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers WebSockHandler.cpp Source File

WebSockHandler.cpp

00001 //*****************************************************************************
00002 // Copyright (C) 2014 Texas Instruments Incorporated
00003 //
00004 // All rights reserved. Property of Texas Instruments Incorporated.
00005 // Restricted rights to use, duplicate or disclose this code are
00006 // granted through contract.
00007 // The program may not be used without the written permission of
00008 // Texas Instruments Incorporated or against the terms and conditions
00009 // stipulated in the agreement under which this program has been supplied,
00010 // and under no circumstances can it be used with non-TI connectivity device.
00011 //
00012 //*****************************************************************************
00013 
00014 
00015 /**
00016  * @addtogroup WebSockHandler
00017  *
00018  * @{
00019  */
00020 
00021 //#include "HttpHeaders.h"
00022 #include "HttpCore.h"
00023 #include "HttpResponse.h"
00024 #include "HttpRequest.h"
00025 #include "HttpAuth.h"
00026 #include "HttpDebug.h"
00027 #include <string.h>
00028 #include <stdlib.h>
00029 #include "HttpConfig.h"
00030 #include "HttpString.h"
00031 #include "osi.h"
00032 #include "WebSockHandler.h"
00033 #include "httpserverapp.h"
00034 
00035 // Include CC3200 SimpleLink headers
00036 #include "cc3100_simplelink.h"
00037 
00038 
00039 char *GlobRecvBuf;
00040 int64_t GlobPayloadLen;
00041 int64_t GlobRecvLen;
00042 UINT8 RecvMore = 0;
00043 char MaskKey[4];
00044 UINT8 Mask;
00045 UINT8 Ping = 0;
00046 UINT8 Close = 0;
00047 
00048 // WebSocket response status line strings
00049 char    WS_STATUS_OK_STR[]                     =    "ok";
00050 char    WS_STATUS_GOING_AWAY_STR[]             =    "server down";
00051 char    WS_STATUS_ERROR_PROTOCOL_STR[]         =    "protocol error";
00052 char    WS_STATUS_ERROR_DATATYPE_STR[]         =    "datatype not supported";
00053 char    WS_STATUS_ERROR_ENCODING_STR[]         =    "data not interpreted";
00054 char    WS_STATUS_ERROR_OVERFLOW_STR[]         =    "data too large";
00055 char    WS_STATUS_ERROR_UNEXPECTED_STR[]       =    "unexpected event server";
00056 
00057 
00058 /* This function parses the incoming data packet
00059 * @return 1 if successful
00060         0 if failure
00061 */
00062 /*
00063 
00064         0               1                   2                   3
00065      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
00066     +-+-+-+-+-------+-+-------------+-------------------------------+
00067     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
00068     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
00069     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
00070     | |1|2|3|       |K|             |                               |
00071     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
00072     |     Extended payload length continued, if payload len == 127  |
00073     + - - - - - - - - - - - - - - - +-------------------------------+
00074     |                               |Masking-key, if MASK set to 1  |
00075     +-------------------------------+-------------------------------+
00076     | Masking-key (continued)       |          Payload Data         |
00077     +-------------------------------- - - - - - - - - - - - - - - - +
00078     :                     Payload Data continued ...                :
00079     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
00080     |                     Payload Data continued ...                |
00081     +---------------------------------------------------------------+
00082 
00083 
00084 */
00085 
00086 int Payloadlength(struct HttpBlob * pData, UINT8 iter)
00087 {
00088     int result = 0x0;
00089 
00090     while(iter != 0)
00091     {
00092         result = ((int) (*(pData->pData)) | result);
00093         if(iter != 1)
00094             result = result << 8;
00095         pData->pData += sizeof(UINT8);
00096         pData->uLength -= sizeof(UINT8);
00097         iter--;
00098     }
00099 
00100     return result;
00101 }
00102 
00103 
00104 int WSCore_DataRecv(UINT16 uConnection,struct HttpBlob * pData)
00105 {
00106     UINT8 NextBlock;
00107     int lengthLeft;
00108     UINT16 final,RSV,Opcode;
00109     int PayloadLength;
00110     UINT8 iter;
00111     char *PayloadData;
00112     int RecvLength = (int)pData->uLength;
00113 
00114 
00115     if(!RecvMore)
00116     {
00117         //Parse the first byte
00118         NextBlock= *(pData->pData);
00119         pData->pData += sizeof(UINT8);
00120         pData->uLength -= sizeof(UINT8);
00121 
00122         //Mask bits to get header fields
00123         final = (NextBlock&(0x80));
00124         RSV = (NextBlock&(0x70));
00125         Opcode = ((NextBlock&(0x0F)));
00126 
00127         //If Final bit is set, this is the last data byte from client - terminating condition
00128         if(final)
00129             HttpDebug("Final datablock received \n\r");
00130 
00131 
00132         //Inform user about the opcode
00133             HttpDebug("Opcode is %d\n\r",Opcode);
00134 
00135             switch(Opcode)
00136             {
00137                 case WS_TEXT:
00138                     HttpDebug("Text data\n\r");
00139                     break;
00140                 case WS_BINARY:
00141                     HttpDebug("Binary data\n\r");
00142                     break;
00143                 case WS_CLOSE:
00144                     HttpDebug("Client has requested connection to be closed\n\r");
00145                     Close = 1;
00146                     WSStatusString(WS_STATUS_OK,pData);
00147                     WSCore_DataSend(uConnection,*pData,Opcode);
00148                     return 1;
00149                 case WS_CONTINUATION:
00150                     break;
00151                 case WS_PING:
00152                     HttpDebug("Ping received\n\r");
00153                     Ping = 1;
00154                     break;
00155                 case WS_PONG:
00156                     HttpDebug("Pong received\n\r");
00157                     break;
00158                 default:
00159                     HttpDebug("This is unsupported\n\r");
00160                     break;
00161             }
00162 
00163 
00164         ///If header supports extension, send back error
00165         ///Send error frame : TODO
00166         if(RSV)
00167             HttpDebug("Unsupported extension\n\r");
00168 
00169         //Parse the second byte
00170         NextBlock= *(pData->pData);
00171         pData->pData += sizeof(UINT8);
00172         pData->uLength -= sizeof(UINT8);
00173 
00174         Mask = (UINT8)(NextBlock&(0x80));
00175         PayloadLength = (NextBlock&(0x7F));
00176 
00177         //Payload length cases
00178         // If the payload length is 0x7E, the next 2 bytes represent the length
00179         if(PayloadLength == 0x7E)
00180         {
00181             iter = 2;
00182             PayloadLength = Payloadlength(pData, iter);
00183         }
00184 
00185         // If the payload length is 0x7F, the next 8 bytes represent the length
00186         if(PayloadLength == 0x7F)
00187         {
00188             iter = 8;
00189             PayloadLength = Payloadlength(pData, iter);
00190         }
00191 
00192         PayloadData = (char *)malloc(PayloadLength);
00193         if(PayloadData == NULL)
00194         {
00195             return 0;
00196         }
00197         memset(PayloadData,'\0',PayloadLength);
00198         GlobRecvBuf = PayloadData;
00199         GlobPayloadLen = PayloadLength;
00200 
00201         // If mask bit is set, the 4 bytes after payload length represent the masking key
00202         if(Mask)
00203         {
00204             memcpy(MaskKey,pData->pData,4);
00205             pData->pData += sizeof(UINT32);
00206             pData->uLength -= sizeof(UINT32);
00207         }
00208 
00209         int RecvLength = (int)pData->uLength;
00210 
00211         //Now, extract payload data
00212         memcpy(GlobRecvBuf,(const char *)(pData->pData),RecvLength);
00213 
00214         // Go back and get more data.
00215         if(PayloadLength > RecvLength)
00216         {
00217             GlobRecvLen = RecvLength;   // Websocket header has 8 bytes that were also received.
00218             RecvMore = 1;
00219             return 1;
00220         }
00221     }
00222 
00223     else
00224     {
00225         memcpy(GlobRecvBuf+GlobRecvLen,(const char *)(pData->pData),RecvLength);
00226         GlobRecvLen += RecvLength;
00227 
00228         if(GlobRecvLen < GlobPayloadLen)
00229             return 1;
00230     }
00231 
00232     RecvMore = 0;
00233 
00234 
00235     if(Mask)
00236     {
00237         //UINT8 MaskBlock;
00238         char *pData = GlobRecvBuf;
00239         lengthLeft = GlobPayloadLen;
00240         UINT8 MaskIndex = 0;
00241         while(MaskIndex < 4)
00242         {
00243             NextBlock = (UINT8)(*pData);
00244             NextBlock ^= MaskKey[MaskIndex];
00245             MaskIndex++;
00246             *pData = NextBlock;
00247             pData += sizeof(UINT8);
00248             lengthLeft -= sizeof(UINT8);
00249             if(lengthLeft == 0)
00250                 break;
00251             if(MaskIndex == 4)
00252                 MaskIndex = 0;
00253         }
00254 
00255     }
00256 
00257     *(GlobRecvBuf+GlobPayloadLen) = '\0';
00258 
00259     struct HttpBlob PayLoad;
00260     PayLoad.pData = (UINT8 *)GlobRecvBuf;
00261     PayLoad.uLength = (UINT16)GlobPayloadLen;
00262 
00263     if(Ping)
00264     {
00265         HttpDebug("You were Pinged\n\r");
00266         //You must pong
00267         Opcode = 0x0A;
00268         WSCore_DataSend(uConnection,PayLoad,Opcode);
00269     }
00270 
00271     //free(pData->pData);
00272 
00273     //Send this data to main
00274     WebSocketRecvEventHandler(uConnection,GlobRecvBuf);
00275 
00276 
00277     return 1;
00278 
00279 }
00280 
00281 /*!
00282  *  \brief                       Sends data to a websocket client                               
00283  *
00284  *  \param[in] uConnection          Connection number on HTTP server. 
00285  *  \param[in] PayLoad          Structure holding the payload data and the size of the data
00286  *  \param[in] Opcode               User provides data type (text/binary/ping/pong/close).
00287  *
00288  *  \return                     1 - If packet was successfully received, parsed and sent to the user API
00289  *                              0 - Error
00290  */
00291 int WSCore_DataSend(UINT16 uConnection, struct HttpBlob PayLoad, UINT8 Opcode)
00292 {
00293     UINT16 usTotalLength;
00294     UINT8 usNextBlock;
00295     UINT16 usPayloadLen;    // The heap cannot support beyond 65kb
00296     char *pucPayLoadData = (char *)PayLoad.pData;
00297 
00298     usNextBlock = 0;
00299     
00300     if(Opcode != 0x02)
00301         usTotalLength = strlen(pucPayLoadData);
00302     else
00303         usTotalLength = PayLoad.uLength;
00304 
00305     do{
00306 
00307         ///Is this the final packet?
00308         if(usTotalLength < FRAGMENT_LENGTH)
00309         {
00310             //final = 0x1;
00311             usNextBlock |= 0x80;
00312         }
00313         ///Add opcode to the header
00314         usNextBlock |= Opcode;
00315 
00316         /// Add this byte to the sendpacket
00317         HttpResponse_AddCharToResponseHeaders(usNextBlock);
00318 
00319         ///Reset byte
00320         usNextBlock = 0x0;
00321         ///Mask bit is always set to 0 from server to client
00322 
00323         ///PayloadLen field
00324         if(usTotalLength <= 125)
00325             usPayloadLen = usTotalLength;
00326         else
00327             usPayloadLen = (126);
00328 
00329         usNextBlock |= (UINT8)usPayloadLen;
00330 
00331         /// Add this byte to the sendpacket
00332         HttpResponse_AddCharToResponseHeaders(usNextBlock);
00333 
00334         /// If payload length is more than 125 bytes, we need 16 bits to represent it.
00335         if(usPayloadLen == (126))
00336         {
00337 
00338             if(usTotalLength < FRAGMENT_LENGTH)
00339                 usPayloadLen = usTotalLength;
00340             else
00341                 usPayloadLen = FRAGMENT_LENGTH;
00342 
00343             if(usPayloadLen >= FRAGMENT_LENGTH - 4)
00344                 usPayloadLen = FRAGMENT_LENGTH - 4;
00345 
00346             usNextBlock = (char)(usPayloadLen>>8);
00347             HttpResponse_AddCharToResponseHeaders(usNextBlock);
00348             usNextBlock = (char)(usPayloadLen);
00349             HttpResponse_AddCharToResponseHeaders(usNextBlock);
00350         }
00351 
00352         HttpResponse_AddStringToResponseHeaders(pucPayLoadData,(usPayloadLen));
00353 
00354         if(!WS_SendPacket(uConnection))
00355             return 0;
00356 
00357         if(Opcode == WS_CLOSE)
00358         {
00359             sl_WebSocketCloseEvtHdlr();
00360             wait(1);
00361             (HttpCore_CloseConnection(uConnection));
00362             return 1;
00363         }
00364 
00365         usTotalLength -= (usPayloadLen);
00366 
00367         // Reset to continuation frame if packet is larger than max fragment size
00368         Opcode = WS_CONTINUATION;
00369 
00370         ///Reset byte
00371         usNextBlock = 0x0;
00372 
00373         //Update pointer
00374         pucPayLoadData += usPayloadLen;
00375 
00376     }while(usTotalLength > 0);
00377 
00378     return 1;
00379 }
00380 
00381 
00382 /**
00383  * Returns status string according to status code - CHANGE
00384  */
00385 void WSStatusString(UINT32 WS_Status, struct HttpBlob* status)
00386 {
00387     HttpString_utoa(WS_Status, status);
00388     struct HttpBlob blob = {0, NULL};
00389     switch (WS_Status)
00390     {
00391     case WS_STATUS_OK:
00392         HttpBlobSetConst(blob, WS_STATUS_OK_STR);
00393         break;
00394     case WS_STATUS_GOING_AWAY:
00395         HttpBlobSetConst(blob, WS_STATUS_GOING_AWAY_STR);
00396         break;
00397     case WS_STATUS_ERROR_DATATYPE:
00398         HttpBlobSetConst(blob, WS_STATUS_ERROR_DATATYPE_STR);
00399         break;
00400     case WS_STATUS_ERROR_ENCODING:
00401         HttpBlobSetConst(blob, WS_STATUS_ERROR_ENCODING_STR);
00402         break;
00403     case WS_STATUS_ERROR_OVERFLOW:
00404         HttpBlobSetConst(blob, WS_STATUS_ERROR_OVERFLOW_STR);
00405         break;
00406     case WS_STATUS_ERROR_PROTOCOL:
00407         HttpBlobSetConst(blob, WS_STATUS_ERROR_PROTOCOL_STR);
00408         break;
00409     case WS_STATUS_ERROR_UNEXPECTED:
00410         HttpBlobSetConst(blob, WS_STATUS_ERROR_UNEXPECTED_STR);
00411         break;
00412     default:
00413         HttpDebug("Unknown response status \n\r");
00414         HttpAssert(0);
00415         break;
00416     }
00417     memcpy(status->pData + status->uLength, blob.pData, blob.uLength);
00418     return;
00419 }
00420 
00421 /// @}
00422