Arianna autonomous DAQ firmware

Dependencies:   mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW

Websocket.cpp

Committer:
uci1
Date:
2012-06-30
Revision:
0:664899e0b988
Child:
1:e392595b4b76

File content as of revision 0:664899e0b988:

#include "Websocket.h"
#include <string>

//#define DEBUG


#ifdef TARGET_LPC1768
Websocket::Websocket(char * url) {
    server_ip = NULL;
    netif = ETH;
    eth_writeable = false;
    eth_readable = false;
    eth_connected = false;
    response_server_eth = false;
    new_msg = false;
    fillFields(url);

    eth = new EthernetNetIf(
        IpAddr(128,195,204,148), //IP Address
        IpAddr(255,255,255,0), //Network Mask
        IpAddr(128,195,204,1), //Gateway
        IpAddr(128,200,1,201)  //DNS   
    );
    sock = new TCPSocket();

    EthernetErr ethErr = eth->setup();
#ifdef DEBUG
    if (ethErr) {
        printf("\r\nERROR %d in setup.\r\n", ethErr);
    }
#endif

    //we must use dnsresolver to find the ip address
    if (server_ip == NULL) {
        DNSResolver dr;
        server_ip = new IpAddr();
        *server_ip = dr.resolveName(ip_domain.c_str());
#ifdef DEBUG
        printf("\r\nserver with dns=%d.%d.%d.%d\r\n", (*server_ip)[0], (*server_ip)[1], (*server_ip)[2], (*server_ip)[3]);
#endif

    }

    IpAddr ipt = eth->getIp();
#ifdef DEBUG
    printf("\r\nmbed IP Address is %d.%d.%d.%d\r\n", ipt[0], ipt[1], ipt[2], ipt[3]);
#endif

    sock->setOnEvent(this, &Websocket::onTCPSocketEvent);
}
#endif //target


void Websocket::fillFields(char * url) 
{
    printf("FILLFIELDS\r\n");
    char *res = NULL;
    char *res1 = NULL;

    char buf[50];
    strcpy(buf, url);
    printf("\r\nBuf is:");
    for(int i=0;i<50;i++)
    {
        printf("%d", buf[i]);
    }
    printf("\r\n");
    res = strtok(buf, ":");
    if (strcmp(res, "ws")) 
    {
#ifdef DEBUG
        printf("\r\nFormat error: please use: \"ws://ip-or-domain[:port]/path\"\r\n\r\n");
#endif
    } 
    else 
    {
        //ip_domain and port
        res = strtok(NULL, "/");

        //path
        res1 = strtok(NULL, " ");
        if (res1 != NULL) 
        {
            path = res1;
        }

        //ip_domain
        res = strtok(res, ":");

        //port
        res1 = strtok(NULL, " ");
        //port
        if (res1 != NULL) 
        {
            port = res1;
        } else 
        {
            port = "80";
        }

        if (res != NULL) 
        {
            ip_domain = res;

            //if we use ethernet, we must decode ip address or use dnsresolver
#ifdef TARGET_LPC1768
            if (netif == ETH) {
                strcpy(buf, res);
                //we try to decode the ip address
                if (buf[0] >= '0' && buf[0] <= '9') {
                    res = strtok(buf, ".");
                    int i = 0;
                    int ip[4];
                    while (res != NULL) {
                        ip[i] = atoi(res);
                        res = strtok(NULL, ".");
                        i++;
                    }
                    server_ip = new IpAddr(ip[0], ip[1], ip[2], ip[3]);
#ifdef DEBUG
                    printf("server without dns=%i.%i.%i.%i\n",(*server_ip)[0],(*server_ip)[1],(*server_ip)[2],(*server_ip)[3]);
#endif
                }
            }
#endif //target
        }
    }
}


bool Websocket::connect(Timer* stop, const uint32_t timeout) 
{
 //   printf("CONNECT() Function\r\n");
    char cmd[50];
#ifdef TARGET_LPC1768
   //M: else if (netif == ETH) 
    if (netif == ETH) 
    {
        Host server (*server_ip, atoi(port.c_str()));
        sock->close();
        TCPSocketErr bindErr = sock->connect(server);
        if (bindErr) 
        {
#ifdef DEBUG
            printf("\r\nERROR binderr: %d\r\n", bindErr);
#endif
            return false;
        }
        Timer tmr;
        tmr.start();
        Timer myStop;
        if (stop==0) {
            stop = &myStop;
        }
        int i = 0;
        printf("I: %d\r\n", i);
        while (true) {
            Net::poll();
            if (stop->read() > timeout)
                return false;
            if (tmr.read() > 0.05) {
                tmr.reset();
                if (eth_connected) {
                    switch (i) {
                        case 0:
                            sprintf(cmd, "GET /%s HTTP/1.1\r\n", path.c_str());
                            sock->send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 1:
                            sprintf(cmd, "Host: %s:%s\r\n", ip_domain.c_str(), port.c_str());
                            sock->send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 2:
                            sprintf(cmd, "Upgrade: WebSocket\r\n");
                            sock->send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 3:
                            sprintf(cmd, "Origin: null\r\n");
                            sock->send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 4:
                            sprintf(cmd, "Connection: Upgrade\r\n");
                            sock->send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 5:
                            sprintf(cmd, "Sec-WebSocket-Key: L159VM0TWUzyDxwJEIEzjw==\r\n");
                            sock->send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 6:
                            sprintf(cmd, "Sec-WebSocket-Version: 13\r\n\r\n");
                            sock->send(cmd, strlen(cmd));
                            i++;
                            break;
                        case 7:
                            if (response_server_eth)
                                i++;
                            else
                                break;

                        default:
                            break;
                    }
                }
                if (i==8) {
#ifdef DEBUG
                    printf("\r\nip_domain: %s\r\npath: /%s\r\nport: %s\r\n\r\n",this->ip_domain.c_str(), this->path.c_str(), this->port.c_str());
#endif
                    return true;
                }
            }
        }
    }
#endif //target
    //the program shouldn't be here
    return false;
}    

void Websocket::sendLength(uint32_t len) 
{
    //printf("SENDLENGTH(), Send Length: %d\r\n", len);
    if (len < 126) 
    {
        sendChar(len | (1<<7));
    } 
    else if (len < 65535) 
    { // use 2 bytes 
        sendChar(126 | (1<<7));
       //M: reverce these two lines 
        sendChar((len >> 8) & 0xff); //2       
        sendChar(len & 0xff); //1
  //      sendChar((len >> 8) & 0xff); //2         
    } 
    else
    {
        sendChar(127 | (1<<7));
        for (int i = 0; i < 8; i++) 
        {
            sendChar((len >> i*8) & 0xff);
        }
    }
}

int Websocket::sendChar(uint8_t c) 
{
#ifdef TARGET_LPC1768
    if (netif == ETH) {
        Net::poll();
        return sock->send((const char *)&c, 1);
  //      printf("SENDCHAR(), Sendchar %d \r\n", c);
    }
#endif
    return 0;
}

void Websocket::sendOpcode(uint8_t opcode) 
{
//    printf("SENDOPCODE()\r\n");
    sendChar(0x80 | (opcode & 0x0f));
//    printf("SendOpcode: 0x%X\r\n", opcode);
}

/*Masking-key:  0 or 4 bytes
      All frames sent from the client to the server are masked by a 32-
      bit value that is contained within the frame.  This field is
      present if the mask bit is set to 1, and is absent if the mask bit
      is set to 0.
*/
void Websocket::sendMask() 
{
//    printf("SENDMASK()\r\n");
    for (int i = 0; i < 4; i++) {
        sendChar(0); //no frame masking 
    }
}

void Websocket::send(char * str) 
{
    //printf("SEND()\r\n");
/* Opcode:  4 bits
      The opcode denotes the frame type of the WebSocket frame
      Defines the interpretation of the payload data.  If an unknown
      opcode is received, the receiving endpoint MUST _Fail the
      WebSocket Connection_.  The following values are defined.
      *  %x0 denotes a continuation frame
      *  %x1 denotes a text frame
      *  %x2 denotes a binary frame
      *  %x3-7 are reserved for further non-control frames
      *  %x8 denotes a connection close
      *  %x9 denotes a pingg
      *  %xA denotes a pong
      *  %xB-F are reserved for further control frames
      
      */
    sendOpcode(0x01);
    sendLength(strlen(str));
    sendMask();

#ifdef TARGET_LPC1768
   //M: else if (netif == ETH) {
    if (netif == ETH) 
    {
        Net::poll();
        sock->send(str, strlen(str));
    }
#endif //target
}

bool Websocket::sendBinary(char* str, const uint32_t len) 
{
    // CJR: add function for sending binary
    
    //printf("SEND()\r\n");
/* Opcode:  4 bits
      The opcode denotes the frame type of the WebSocket frame
      Defines the interpretation of the payload data.  If an unknown
      opcode is received, the receiving endpoint MUST _Fail the
      WebSocket Connection_.  The following values are defined.
      *  %x0 denotes a continuation frame
      *  %x1 denotes a text frame
      *  %x2 denotes a binary frame
      *  %x3-7 are reserved for further non-control frames
      *  %x8 denotes a connection close
      *  %x9 denotes a pingg
      *  %xA denotes a pong
      *  %xB-F are reserved for further control frames
      
      */
    sendOpcode(0x02);
    sendLength(len);
    sendMask();

#ifdef TARGET_LPC1768
   //M: else if (netif == ETH) {
    if (netif == ETH) 
    {
        Net::poll();
        uint32_t nbytes=0;
        char* s = str;
        for (uint32_t i=0; i<len; i++, s++) {
            nbytes += sendChar(*s);
        }
        //const int32_t nbytes = sock->send(str, len);
        return nbytes==len;
    }
#endif //target
    return false;
}

bool Websocket::sendBinary(FILE* f, const uint32_t nbytes) 
{
    // CJR: add function for sending binary
    // return false if EOF or file error before nbytes sent
    
    //printf("SEND()\r\n");
/* Opcode:  4 bits
      The opcode denotes the frame type of the WebSocket frame
      Defines the interpretation of the payload data.  If an unknown
      opcode is received, the receiving endpoint MUST _Fail the
      WebSocket Connection_.  The following values are defined.
      *  %x0 denotes a continuation frame
      *  %x1 denotes a text frame
      *  %x2 denotes a binary frame
      *  %x3-7 are reserved for further non-control frames
      *  %x8 denotes a connection close
      *  %x9 denotes a pingg
      *  %xA denotes a pong
      *  %xB-F are reserved for further control frames
      
      */
    sendOpcode(0x02);
    sendLength(nbytes);
    sendMask();

#ifdef TARGET_LPC1768
   //M: else if (netif == ETH) {
    if (netif == ETH) 
    {
        Net::poll();
        uint8_t c;
        // conserve mbed memory by reading byte-by-byte
        for (uint32_t i=0; i<nbytes; i++) {
            fread(&c, 1, 1, f);
            if ((feof(f)==0) && (ferror(f)==0)) {
                sendChar(c);
            } else {
                return false;
            }
        }
            
    }
#endif //target
    return true;
}

bool Websocket::read(char * message, Timer* timer, const uint32_t timeout) 
{
    //printf("READ()\r\n");
    uint32_t len_msg; //32 bit size
    char opcode = 0; //continuation frame
    char mask[4] = {0, 0, 0, 0}; //no mask
    Timer myTimer;
    if (timer==0) {
        timer = &myTimer;
    }
#ifdef TARGET_LPC1768
    if (netif == ETH) 
    {
  //      printf("Current opcode in read() 0x%X\r\n", opcode);
        uint32_t index = 0;
        Net::poll();
        if (new_msg) //from webserver
        {
            printf("There is new message from webserver\r\n");
             // read the opcode
            while (true) 
            {
                if (timer->read() > timeout) 
                {
                    return false;
                }
                opcode = eth_rx[index++];
                printf("new opcode in read() func: 0x%X\r\n", opcode); //0x81
                if (opcode == 0x81) 
                {
                    break;
                }
            }// end of while(true)
#ifdef DEBUG
      //      printf("opcode: 0x%X\r\n", opcode);
#endif                 
            len_msg = eth_rx[index++] & 0x7f;
            printf("length_message2 : %d\r\n", len_msg);            //
            if (len_msg == 126)
            {
                len_msg += eth_rx[index++] << 8;                        
                len_msg = eth_rx[index++];                                  
             printf("len message is greater than 126 %d\r\n", len_msg);     
            } 
            else if (len_msg == 127) 
            {              
                len_msg = 0;
                for (int i = 0; i < 8; i++) 
                {
                    len_msg += eth_rx[index++] << i*8;
                }            
            } 
            if(len_msg == 0) 
            {  
                return false;
            }
#ifdef DEBUG
          //  printf("length: %d\r\n", len_msg);
#endif
            if ((len_msg & 0x80)) 
            {
                printf("print mask bit %d\r\n", len_msg & 0x80);
                for (int j = 0; j < 4; j++){
                    mask[j] = eth_rx[index++];
                    printf(" mask index %i is %i, ", j, mask[j]); 
                    }                   
            }
           // for (int i = 0; i < 4; i++)
           //{
           //         mask[i] = 0; 
           //} 
         /*   for (int i = 0; i < 4; i++)
            {
                 printf(" mask index %i is %i, ", i, mask[i]); 
            }*/   
            printf("\r\n");
            for (int i = 0; i < len_msg; i++) 
            {             
         //      printf("%c", eth_rx[i]);
        //       message[i-8] = eth_rx[i];            
          //      message[i] = eth_rx[index++] ^ mask[i % 4];    
          if (len_msg < 126)
                message[i] = eth_rx[i+2];                      
          else
                message[i] = eth_rx[i+4];                              
             //   printf("message is %s\r\n", message);            
            }            
            message[len_msg] = 0;

            //M: add :
          //  if (new_msg)
          //   {new_msg = true;}
            //else
             new_msg = false;                
           return true;
        }//if new message
        printf("no new message!\r\n");
        return false;
    }//end of if(eth)
#endif //target
//the program shouldn't be here
    return false;
} // end of read func

bool Websocket::close() 
{
 //   printf("COSE()\r\n");
#ifdef TARGET_LPC1768
    if (netif == ETH) 
    {
        if (sock->close())
            return false;
        return true;
    }
#endif //target
    //the program shouldn't be here
    return false;
}

bool Websocket::connected() {
 //   printf("CONNECTED()\r\n");

#ifdef TARGET_LPC1768

    if (netif == ETH)
    {    
        return eth_connected;
    }
#endif //target
    //the program shouldn't be here
    return false;
}

std::string Websocket::getPath()
{
    return path;
}

#ifdef TARGET_LPC1768
void Websocket::onTCPSocketEvent(TCPSocketEvent e) 
{
 //   printf("TCPSocketEvent is ");
    if (e == TCPSOCKET_CONNECTED) 
    {
        eth_connected = true;
#ifdef DEBUG
   //     printf("TCP Socket Connected\r\n");
#endif
    } 
    else if (e == TCPSOCKET_WRITEABLE) {
  //      printf("TCPSOCKET_WRITEABLE\r\n");
    } 
    else if (e == TCPSOCKET_READABLE) 
    {
   //     printf("TCPSOCKET_READABLE\r\n");
        int len = sock->recv(eth_rx, 512);       
        eth_rx[len] = 0;
        new_msg = true;
        if (!response_server_eth) 
        {
            string checking;
            size_t found = string::npos;
            checking = eth_rx;
            found = checking.find("DdLWT/1JcX+nQFHebYP+rqEx5xI=");
            if (found != string::npos)
                response_server_eth = true;
        }
    } 
    else 
    {
#ifdef DEBUG
        printf("TCP Socket Fail\r\n");
#endif
        eth_connected = false;
    }
}
#endif //target