Dependencies:   XBeeLib mbed HvZAlphaNumLib HvZServerLib

lib/udp.cpp

Committer:
etherealflaim
Date:
2010-12-12
Revision:
1:d1b5cd8b2c18
Parent:
0:9cdba0589ba2

File content as of revision 1:d1b5cd8b2c18:

#include "mbed.h"
#include "iHvZ.hpp"
#include "if/net/netudpsocket.h"

#include "udp.hpp"

UDP::UDP(iHvZ *game, PinName eth_in) 
:  m_game(game), m_eth(eth_in), m_eth_int(eth_in),
   m_pNetUdpSocket(NULL), m_pCbItem(NULL), m_pCbMeth(NULL), m_pCb(NULL),
   //conn(IpAddr(192,168,1,2),IpAddr(255,255,255,0), IpAddr(), IpAddr())
{
    // Set the game ID
    char mac[8];
    char macaddr[12+1];
    eth.address(mac);
    sprintf(macaddr, "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    m_game->id(macaddr);
    
    //m_eth_int.rise(this, &UDP::check);
    m_eth_chk.attach(this, &UDP::check, 5);
    registered = 0;
}
 
UDP::~UDP()
{
  close();
}

void UDP::check()
{   
    // debounce (if attached to a button)
    wait(.1);
    //if (m_eth)
    //{        
    //    usb.printf("- Connection found, starting sync\r\n");
        ethlink();
    //}
    m_eth_chk.attach(this, &UDP::check, 10);
}
     
int UDP::sendto(const char* buf, int len, Host* pHost)
{
  UDPErr udpSocketErr = checkInst();
  if(udpSocketErr)
    return udpSocketErr; 
  return m_pNetUdpSocket->sendto(buf, len, pHost);  
}

int UDP::recvfrom(char* buf, int len, Host* pHost)
{
  UDPErr udpSocketErr = checkInst();
  if(udpSocketErr)
    return udpSocketErr;
  return m_pNetUdpSocket->recvfrom(buf, len, pHost);
}

UDPErr UDP::close()
{
  if(!m_pNetUdpSocket)
    return UDPSOCKET_SETUP;
  m_pNetUdpSocket->resetOnEvent();
  UDPErr udpSocketErr = (UDPErr) m_pNetUdpSocket->close(); //Close (can already be closed)
  Net::releaseUdpSocket(m_pNetUdpSocket); //And release it so it can be freed when properly removed
  m_pNetUdpSocket = NULL;
  return udpSocketErr;
} 

void UDP::ethlink()
{
    Serial usb(USBTX,USBRX);
    usb.printf("Checking for Ethernet connection...\r\n");
    
    Host game_server(IpAddr(128, 61, 89, 71), HVZ_PORT, HVZ_HOSTNAME);
    //Host game_server(IpAddr(192, 168, 1, 1), HVZ_PORT, HVZ_HOSTNAME);
    
    /* Function to call upon Server response */    
    setOnEvent(this, &UDP::read);
     
    if( !eth.link() ) return;
    usb.printf(" - Link active\r\n");
    
    m_game->alphanumdisplay_device().display('*');
      
    if( registered == 0 ) {
        conn.setup();
                      
        //Get the MAC address of this device
        eth.address((char *)mac.octet);     
                                           
        // Send to Game Server until receive a response 
        // and wait for a response                                                                                                                                 
        do {
        
             register_device(mac, &game_server);
             wait(0.1);
                           
             Net::poll();
                             
          } while ( memcmp("i",&(srvr_resp[0]),1) );
        
        printf("srvr_resp = %s\r\n", srvr_resp); 
        
        // If the response is an acknowledgement
        // get the IDs from the response and
        // set the game device and tag IDs
        if( get_ack_err(srvr_resp,HVZ_REG) ) {
            set_ids(srvr_resp); 
           //printf( "deviceID = %s\r\n", m_game->id() );
           //printf( "tagID = %s\r\n", m_game->tagid() );
        
            // Clear the response string 
            memset(srvr_resp,0,sizeof(srvr_resp));
        
            // Upon registration there will be no tags or 
            // updates for this device, so just return here   
            return;
        }          
        
        // Set as already registered
        registered = 1;
        
        // Clear the response string 
        memset(srvr_resp,0,sizeof(srvr_resp));
    }
    
    // Submit any tags to the server
    // and wait for a response 
    do {    
        send_tag(&game_server, m_game->get_victims());
        wait(0.1);
                       
        Net::poll();                        
    //} while ( memcmp("i",&(srvr_resp[0]),1) );
    } while ( 'i' != srvr_resp[0] );
    
    printf("srvr_resp = %s\r\n", srvr_resp);
    
    // On successfully reporting tags to Server
    // clear the tagged list
    if( get_ack_err(srvr_resp,HVZ_TAG) ) 
        m_game->clear_victims(); 
    
    // Clear the response string 
    memset(srvr_resp,0,sizeof(srvr_resp));
    
    // Next request updates to the server 
    do {
        // If the deviceID is set at update request
        send_pull(&game_server);    
        
        wait(0.1);
                       
        Net::poll(); 
    //} while ( !srvr_resp[0] );
    } while ( 'i' != srvr_resp[0] );
    
    printf("srvr_resp = %s\r\n", srvr_resp);  
    
    // If pull request ack, update settings of the game
    if( get_ack_err(srvr_resp,HVZ_PULL) )  
        update_settings(srvr_resp);
    
    // Clear the response string 
    memset(srvr_resp,0,sizeof(srvr_resp));
    
    // Display a completion mark
    m_game->alphanumdisplay_device().display('^');
    wait(1);
    m_game->alphanumdisplay_device().display(m_game->status()==STATUS_HUMAN?'H':'Z');
}

void UDP::read(UDPSocketEvent e)
{
    Host host(IpAddr(128, 61, 89, 71), HVZ_PORT, HVZ_HOSTNAME);
    //Host host(IpAddr(192, 168, 1, 1), HVZ_PORT, HVZ_HOSTNAME);
    
    if ( e == UDPSOCKET_READABLE )
    {
        while( int len = recvfrom(srvr_resp, sizeof(srvr_resp), &host) )
        {
            if( len <= 0 )
              break;   
        }
    }
}

void UDP::set_ids(char *response)
{
    char buf[9];
        
    /* First set the deviceID */
    memcpy(buf,response+13,8);
    buf[8] = '\0';
    m_game->id(buf);
  
    /* Next set the tagID */
    memcpy(buf,response+22,8);
    buf[8] = '\0';
    m_game->life(buf);  
    
    m_game->save(); 
}

void UDP::update_settings(char *response)
{
    char *tok;
    // Clear the lives so we can add them all back
    m_game->clear_lives();
    
    // Start tokenizing the response
    tok = strtok(response,"\001"); 
    
    typedef enum { RNONE,RDEV,RLIVES,RSTUN,RINC } readtype;
    readtype type = RNONE; 
    
    while (tok != NULL)
    {
        //printf ("%s\r\n",tok);
        tok = strtok (NULL, "\001");
        
        if( strcmp(tok,"deviceid") == 0 ) {
            type = RDEV;
            continue;
        }
        
        else if( strcmp(tok,"tagids") == 0 ) {
            type = RLIVES;
            continue;
        }
        
        else if( strcmp(tok,"stuntime") == 0 ) {
            type = RSTUN;
            continue;
        }
        
        else if( strcmp(tok,"incubate") == 0 ) {
            type = RINC;
            continue;
        }
        
        switch (type)
        {
        case RDEV:
            m_game->id(tok);
            break;
        case RLIVES:
            m_game->life(tok);
            continue; // possibility of more than one
        case RSTUN:
            m_game->stun_duration((unsigned)atoi(tok));
            break;
        case RINC:
            m_game->incubation_time((unsigned)atoi(tok));
            break;
        }
        
        // go back to no parsing
        type = RNONE;
    }  
    
    m_game->save(); 
}

void UDP::send_pull(Host *host)
{
    char data[64];
//     char buff[12];
//     
//     memset(data,0,sizeof(data));
 
//     if( type == PULL_DEV )
//         sprintf(buff, "%c%c%c%c%c%c%c%c", pullId[0], pullId[1], pullId[2],
//             pullId[3], pullId[4], pullId[5], pullId[6], pullId[7]); 
 
//     else
//         sprintf(buff, "%02X%02X%02X%02X%02X%02X", pullId[0], pullId[1], pullId[2],
//             pullId[3], pullId[4], pullId[5]); 
 
//     strcat(data, "iHvZ\001pull\001");
//     strcat(data, buff);
//     strcat(data, "\001end");

    sprintf(data, "iHvZ\001pull\001%s\001end", m_game->id().c_str());
    
    sendto(data, strlen(data), host);
}

  inline void UDP::send_tag(Host *host, vector<string> taggedIDs)
  {
     int totalsize = 32;
          
     for (int i = 0; i < taggedIDs.size(); i++)
     {
        totalsize += taggedIDs[i].size();
     }
     
     char tmp[totalsize];
     
     // Clear out buffers
     memset(tmp, 0, sizeof(tmp));
     
     // Append tagIDs
     for (int i = 0; i < taggedIDs.size(); i++)
     {
        strcat(tmp, taggedIDs[i].c_str());
        strcat(tmp, "\001");
     }
     string tagids = tmp;
          
     sprintf(tmp, "iHvZ\001tag\001%s\001%send", m_game->id().c_str(), tagids.c_str());

     sendto(tmp, strlen(tmp), host);
  }
  
void UDP::resetOnEvent() //Disable callback
{
  m_pCb = NULL;
  m_pCbItem = NULL;
  m_pCbMeth = NULL;
}

void UDP::onNetUdpSocketEvent(NetUdpSocketEvent e)
{
  if(m_pCbItem && m_pCbMeth)
    (m_pCbItem->*m_pCbMeth)((UDPSocketEvent) e);
  else if(m_pCb)
    m_pCb((UDPSocketEvent) e);
}

UDPErr UDP::checkInst()
{
  if(!m_pNetUdpSocket)
  {
    m_pNetUdpSocket = Net::udpSocket();
    if(!m_pNetUdpSocket)
    {
      return UDPSOCKET_IF; //Interface did not return a socket (usually because a default interface does not exist)
    }
    m_pNetUdpSocket->setOnEvent(this, &UDP::onNetUdpSocketEvent);
  }
  return UDPSOCKET_OK;
}