Dependencies:   XBeeLib mbed HvZAlphaNumLib HvZServerLib

Files at this revision

API Documentation at this revision

Comitter:
etherealflaim
Date:
Sun Dec 12 19:35:00 2010 +0000
Child:
1:d1b5cd8b2c18
Commit message:

Changed in this revision

HvZAlphaNumLib.lib Show annotated file Show diff for this revision Revisions of this file
HvZServerLib.lib Show annotated file Show diff for this revision Revisions of this file
XBeeLib.lib Show annotated file Show diff for this revision Revisions of this file
lib/Stun.hpp Show annotated file Show diff for this revision Revisions of this file
lib/Tag.cpp Show annotated file Show diff for this revision Revisions of this file
lib/Tag.hpp Show annotated file Show diff for this revision Revisions of this file
lib/iHvZ.hpp Show annotated file Show diff for this revision Revisions of this file
lib/udp.cpp Show annotated file Show diff for this revision Revisions of this file
lib/udp.hpp Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HvZAlphaNumLib.lib	Sun Dec 12 19:35:00 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/etherealflaim/code/HvZAlphaNumLib/#48d04cc40e1c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HvZServerLib.lib	Sun Dec 12 19:35:00 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/etherealflaim/code/HvZServerLib/#7e2eb93442e7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/XBeeLib.lib	Sun Dec 12 19:35:00 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/etherealflaim/code/XBeeLib/#2a826741387f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Stun.hpp	Sun Dec 12 19:35:00 2010 +0000
@@ -0,0 +1,66 @@
+#ifndef _Stun
+#define _Stun
+
+#include "mbed.h"
+
+class Stun {
+private:
+    
+    // Tag status and timing
+    bool     m_is_stunned;     //< Whether currently stunned or not
+    // Game options
+    unsigned m_stun_time;     //< Total duration of current stun
+    Timer    m_stun_timer;     //< Current amount of stun
+    Timeout  m_stun_timeout;   //< Triggers when the stun is over
+    Ticker   m_stun_ticker;    //< Ticks for the duration of the stun
+    
+    // Tag LED
+    DigitalOut m_stun_led;
+    
+public:
+    inline Stun(PinName stun_led)
+    : m_is_stunned(false), m_stun_time(0), m_stun_led(stun_led)
+    {
+    }
+    
+    /// Get the stun status
+    inline bool stunned() { return m_is_stunned; }
+    
+    /// Get the stun time remaining
+    inline int stunleft()
+    {
+        if (!m_is_stunned) return 0;
+        return m_stun_time - m_stun_timer.read();
+    }
+
+    /* Actions */
+    inline void stun(unsigned duration)
+    {
+        m_is_stunned = true;
+        m_stun_time = duration;
+        m_stun_timeout.attach(this, &Stun::stun_expire, m_stun_time);
+        m_stun_ticker.attach(this, &Stun::stun_tick, 1);
+        m_stun_timer.start();
+        m_stun_led = 1;
+    }
+
+private:
+    inline void stun_tick()
+    {
+    
+    }
+
+    inline void stun_expire()
+    {
+        m_is_stunned = false;
+        m_stun_ticker.detach();
+        m_stun_timer.stop();
+        m_stun_timer.reset();
+        m_stun_led = 0;
+        m_stun_time = 0;
+        
+    }
+};
+
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Tag.cpp	Sun Dec 12 19:35:00 2010 +0000
@@ -0,0 +1,203 @@
+#include "mbed.h"
+#include "iHvZ.hpp"
+#include "XBee.hpp"
+
+#include <vector>
+#include <string>
+
+Tag::Tag(iHvZ *game, PinName tagbtn)
+: m_game(game), m_tag(tagbtn), m_tag_int(tagbtn)
+{
+    m_tag_int.rise(this, &Tag::rise);
+    m_game->xbee_device().attach(this, &Tag::rx);
+}
+
+void Tag::rise()
+{
+    Serial usb(USBTX,USBRX);
+    
+    // debounce
+    wait(.1);
+    if (!m_tag) return;
+    
+    event(TAG_EVENT_BUTTON);
+}
+
+void Tag::rx()
+{
+    event(TAG_EVENT_RX);
+}
+
+void Tag::timeout()
+{
+    event(TAG_EVENT_TIMEOUT);
+}
+
+void Tag::event(TagEvent ev)
+{
+    Serial usb(USBTX,USBRX);
+    static TagState state = TAG_STATE_WAITING;
+    static string peer = "";
+    static string peer_tagid = "";
+    static string type = ""; // = (m_game.status()==STATUS_HUMAN)?"STUN":"TAG";
+    static string ack = "";
+    
+    XBeePacket pkt;
+    
+    if (ev == TAG_EVENT_TIMEOUT)
+    {
+        // Display the timeout character (TODO)
+        usb.printf("!! TIMEOUT !!\r\n");
+        m_game->alphanumdisplay_device().display('*');
+        //wait(1);
+        state = TAG_STATE_WAITING;
+    }
+    
+    if (ev == TAG_EVENT_RX)
+    {
+        // Get the packet that triggered this event
+        pkt = m_game->xbee_device().read();
+    }
+
+    do switch (state)
+    {
+        case TAG_STATE_WAITING:
+            // Zero everything
+            peer = "";
+            peer_tagid = "";
+            type = "";
+            ack = "";
+            // Display H/Z
+            // m_game->alphanumdisplay_device().display((m_game->status()==STATUS_HUMAN)?'H':'Z');
+            // Check transitions
+            if (ev == TAG_EVENT_BUTTON)     state = TAG_STATE_TX_SEND;
+            else if (ev == TAG_EVENT_RX)    state = TAG_STATE_RX_RECV;
+            else                            return;
+            continue;
+        // Sending states
+        case TAG_STATE_TX_SEND:
+            // First, check if this zombie is stunned (if so, they can't do anything)
+            if (m_game->stun_tracker().stunned()) return;
+            // Get whether we are tagging or stunning
+            type = (m_game->status()==STATUS_HUMAN)?"STUN":"TAG";
+            // Generate a random acknowledge character for display
+            do { ack = string(1, 'A'+rand()%26); } while (ack == "H" || ack == "Z");
+            // Send the SYN message
+            m_game->xbee_device().broadcast(type + "\001SYN\001" + ack);
+            // Display the acknowledge character (TODO)
+            usb.printf("CHECK: %s (send)\r\n", ack.c_str());
+             m_game->alphanumdisplay_device().display(ack[0]);
+            // Attach a timeout that will revert to waiting
+            m_timeout.attach(this, &Tag::timeout, TAG_TIMEOUT_TIME);
+            state = TAG_STATE_TX_WAITACK;
+            continue;
+        case TAG_STATE_TX_WAITACK:
+            if (ev == TAG_EVENT_RX)
+            {
+                // Make sure it is an ack packet with the right ack character
+                vector<string> pieces = pkt.split_data();
+                if (pieces.size() != 5) return;
+                if (pieces[0] != type) return;
+                if (pieces[1] != "ACK") return;
+                if (pieces[2] != ack) return;
+                ack = pieces[3];
+                // Store the peer ID and tag ID
+                peer = pkt.source();
+                peer_tagid = pieces[4];
+                // Display the new character for verification (TODO)
+                usb.printf("CHECK: %s (send ack)\r\n", ack.c_str());
+                m_game->alphanumdisplay_device().display(ack[0]);
+                // Attach a timeout
+                m_timeout.attach(this, &Tag::timeout, TAG_TIMEOUT_TIME);
+                state = TAG_STATE_TX_WAITBTN;
+            }
+            return;
+        case TAG_STATE_TX_WAITBTN:
+            if (ev == TAG_EVENT_BUTTON)
+            {
+                state = TAG_STATE_TX_SENDCOMP;
+                continue;
+            }
+            return;
+        case TAG_STATE_TX_SENDCOMP:
+            // Send the FIN message indicating that the transaction is complete
+            m_game->xbee_device().send(peer, type+"\001FIN\001"+ack);
+            // Display the completion character (TODO)
+            usb.printf("COMPLETE: %s\r\n", type.c_str());
+            m_game->alphanumdisplay_device().display('^');
+            state = TAG_STATE_WAITING;
+            m_timeout.detach();
+            
+            // Register the successful tag or stun
+            if (type == "TAG" && m_game->status() == STATUS_ZOMBIE)
+                m_game->register_tag(peer_tagid);
+            if (type == "STUN" && m_game->status() == STATUS_HUMAN)
+                m_game->register_stun(peer_tagid);
+            return;
+        // Receiving states
+        case TAG_STATE_RX_RECV:
+            if (ev == TAG_EVENT_RX)
+            {
+                vector<string> pieces = pkt.split_data();
+                if (pieces.size() != 3) return;
+                type = pieces[0];
+                if (pieces[1] != "SYN") return;
+                ack = pieces[2];
+                // Register the source
+                peer = pkt.source();
+                // Display the verification character (TODO)
+                usb.printf("CHECK: %s (receive)\r\n", ack.c_str());
+                m_game->alphanumdisplay_device().display(ack[0]);
+                // Attach a timeout
+                m_timeout.attach(this, &Tag::timeout, TAG_TIMEOUT_TIME);
+                state = TAG_STATE_RX_WAITBTN;
+            }
+            return;
+        case TAG_STATE_RX_WAITBTN:
+            if (ev == TAG_EVENT_BUTTON)
+            {
+                state = TAG_STATE_RX_SENDACK;
+                continue;
+            }
+            return;
+        case TAG_STATE_RX_SENDACK:
+            {
+                // Generate a new acknowledgment character
+                string oldack = ack;
+                ack = string(1, '0'+rand()%9);
+                // Send the ack packet
+                m_game->xbee_device().send(peer, type+"\001ACK\001"+oldack+"\001"+ack+"\001"+m_game->life());
+                // Display the verification character (TODO)
+                usb.printf("CHECK: %s (receive ack)\r\n", ack.c_str());
+                m_game->alphanumdisplay_device().display(ack[0]);
+                // Attach a timeout
+                m_timeout.attach(this, &Tag::timeout, TAG_TIMEOUT_TIME);
+                state = TAG_STATE_RX_WAITCOMP;
+            }
+            return;
+        case TAG_STATE_RX_WAITCOMP:
+            if (ev == TAG_EVENT_RX)
+            {
+                vector<string> pieces = pkt.split_data();
+                // Make sure the completion packet is well-formed
+                if (pieces.size() != 3) return;
+                if (pieces[0] != type) return;
+                if (pieces[1] != "FIN") return;
+                if (pieces[2] != ack) return;
+                // Make sure the peer is the same
+                if (peer != pkt.source()) return;
+                // Display the completion character (TODO)
+                usb.printf("COMPLETE: %s\r\n", type.c_str());
+                m_game->alphanumdisplay_device().display('^');
+                m_timeout.detach();
+                state = TAG_STATE_WAITING;
+                
+                // Stun or tag the player
+                if (type == "TAG" && m_game->status() == STATUS_HUMAN)
+                    m_game->tagged();
+                if (type == "STUN" && m_game->status() == STATUS_ZOMBIE)
+                    m_game->stunned();
+            }
+            return;
+    } while (1);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Tag.hpp	Sun Dec 12 19:35:00 2010 +0000
@@ -0,0 +1,55 @@
+#ifndef _TAGCONNECTION
+#define _TAGCONNECTION
+
+#include "mbed.h"
+#include "iHvZ.hpp"
+#include "XBee.hpp"
+
+/** Connection between devices for the purpose of tagging and stunning
+ */
+class Tag {
+private:
+    iHvZ        *m_game;            //< Maintain a connection to the active game
+
+    DigitalIn    m_tag;             //< Check the status of the tagging/stunning button
+    InterruptIn  m_tag_int;         //< Get an interrupt whenever the tag/stun button is hit
+    Timeout      m_timeout;         //< Get an interrupt when a timeout occurs
+
+    typedef enum {
+      TAG_EVENT_UNKNOWN = 0,
+      TAG_EVENT_BUTTON,
+      TAG_EVENT_RX,
+      TAG_EVENT_TIMEOUT,
+    } TagEvent;
+    
+    typedef enum {
+      TAG_STATE_WAITING = 0,
+      // Sending states
+      TAG_STATE_TX_SEND,
+      TAG_STATE_TX_WAITACK,
+      TAG_STATE_TX_WAITBTN,
+      TAG_STATE_TX_SENDCOMP,
+      // Receiving states
+      TAG_STATE_RX_RECV,
+      TAG_STATE_RX_WAITBTN,
+      TAG_STATE_RX_SENDACK,
+      TAG_STATE_RX_WAITCOMP
+    } TagState;
+
+public:
+    /**
+     * Create a new Tag
+     */
+    Tag(iHvZ *game, PinName tagbtn);
+    
+private:
+    inline void rise();
+    inline void rx();
+    inline void timeout();
+    
+    // Defined in Tag.cpp
+    void event(TagEvent ev = TAG_EVENT_UNKNOWN);
+
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/iHvZ.hpp	Sun Dec 12 19:35:00 2010 +0000
@@ -0,0 +1,281 @@
+#ifndef _iHvZ
+#define _iHvZ
+
+#include "mbed.h"
+
+
+#include <map>
+#include <string>
+#include <sstream>
+#include <fstream>
+class iHvZ;
+
+#define STUN_STATUS_LED LED4
+#define STUN_DEFAULT_DURATION (15)
+#define STUN_INCUBATION_TIME (30)
+#include "Stun.hpp"
+
+#define _XBEE_DEBUG 0
+#define XBEE_PINS_DIN_DOUT_RST_ON p28,p27,p26,p20
+#include "XBee.hpp"
+
+#define TAG_TIMEOUT_TIME 5
+#define TAG_INPUT p23
+#include "Tag.hpp"
+
+#define ALPHA_NUM_DISPLAY_PINS p13, p10, p8, p11, p9, p15, p6, p14, p5, p12, p7
+#include "AlphaNumDisplay.hpp"
+
+#define ETH_PIN p21
+#include "udp.hpp"
+
+typedef enum
+{
+  STATUS_HUMAN = 0,
+  STATUS_ZOMBIE
+} Status;
+
+class iHvZ {
+private: 
+    // Device configuration
+    string   m_id;              //< The ID (8-byte DeviceID or 16-bit MAC Address) of this iHvZ device
+    Stun     m_stun;            //< The stun status class
+    XBee     m_xb;              //< The XBee device
+    Tag      m_tag;             //< The device-to-device tagging
+    AlphaNumDisplay m_alphanum;  //< The alphanumeric display 
+    UDP      m_server;          //< The UDP server class
+    
+    // Game configuration
+    unsigned m_stun_duration;   //< The current stun duration time
+    unsigned m_incubation_time; //< The zombie incubation time
+    
+    // Tag IDs
+    vector<string> m_tagids;   //< The list of IDs (8-byte TagIDs) given out when stunned or tagged (antidotes, etc can add to this list)
+        
+    // List of TagIDs of victims
+    vector<string> m_victimids;
+    
+public:
+    /// Start an iHvZ game with the given ID (should start out as the MAC address)
+    inline iHvZ(string id)
+    : m_id(id),
+      m_stun(STUN_STATUS_LED),
+      m_xb(id, XBEE_PINS_DIN_DOUT_RST_ON),
+      m_tag(this, TAG_INPUT),
+      m_server(this, ETH_PIN),
+      m_alphanum(ALPHA_NUM_DISPLAY_PINS),
+      m_stun_duration(STUN_DEFAULT_DURATION),
+      m_incubation_time(STUN_INCUBATION_TIME)
+    {
+        srand(time(NULL));
+    }
+    
+    inline string itoa(int i)
+    {
+        static char buf[12];
+        sprintf(buf, "%d", i);
+        return string(buf);
+    }
+    
+    inline int atoi(string s)
+    {
+        int i;
+        sscanf(s.c_str(), "%d", &i);
+        return i;
+    }
+    
+    /* Filesystem save and load */
+    /** Save the iHvZ state to iHvZ.cfg on the filesystem */
+    inline bool save()
+    {
+        LocalFileSystem lfs("usb");
+        Serial usb(USBTX,USBRX);
+        ofstream statefile("/usb/iHvZ.cfg");
+        map<string,string> params;
+        int writecount = 0;
+        
+        // Make sure the file opened
+        if (!statefile) return false;
+        
+        // Set the parameters
+        //params["mode"] = (m_status==STATUS_HUMAN)?"HUMAN":"ZOMBIE";
+        params["deviceid"] = m_id;
+        params["stundur"] = itoa(m_stun_duration);
+        params["inctime"] = itoa(m_incubation_time);
+        params["tagcount"] = itoa(m_tagids.size());
+        for (int i = 0; i < m_tagids.size(); ++i)
+        {
+            params["tagid[" + itoa(i) + "]"] = m_tagids[i];
+        }
+        params["victimcount"] = itoa(m_victimids.size());
+        for (int i = 0; i < m_victimids.size(); ++i)
+        {
+            params["victim[" + itoa(i) + "]"] = m_victimids[i];
+        }
+        
+        
+        // Write to file
+        for (map<string,string>::iterator iter = params.begin(); iter != params.end(); ++iter)
+        {
+            statefile << iter->first << "=" << iter->second << endl;
+            ++writecount;
+        }
+        
+        // Write status to USB
+        usb.printf("Successfully wrote %d parameters to iHvZ.cfg\r\n", writecount);
+        
+        // Update the display (in case stuff changed)
+        m_alphanum.display(m_tagids.size()==0?'Z':'H');
+        
+        // Success
+        return true;
+    }
+    
+    /* Load the iHvZ state from iHvZ.cfg on the filesystem */
+    inline bool load()
+    {
+        LocalFileSystem lfs("usb");
+        Serial usb(USBTX,USBRX);
+        ifstream statefile("/usb/iHvZ.cfg");
+        map<string,string> params;
+        int readcount = 0;
+        
+        // Make sure the file opened
+        if (statefile)
+        {
+            // Read in the lines of the file
+            string line;
+            while (getline(statefile, line))
+            {
+                int eqsign = line.find('=');
+                if (eqsign == string::npos) continue;
+                string param = line.substr(0,eqsign);
+                string value = line.substr(eqsign+1);
+                params[param] = value;
+                ++readcount;
+            }
+            
+            // Read static parameters
+            m_id = params["deviceid"];
+            m_stun_duration = atoi(params["stundur"]);
+            m_incubation_time = atoi(params["inctime"]);
+            
+            // Read lives
+            int tagcnt = atoi(params["tagcount"]);
+            m_tagids.clear();
+            m_tagids.reserve(tagcnt);
+            for (int i = 0; i < tagcnt; ++i)
+            {
+                m_tagids.push_back( params["tagid[" + itoa(i) + "]"] );
+            }
+            
+            // Read victims
+            int victimcnt = atoi(params["victimcount"]);
+            m_victimids.clear();
+            m_victimids.reserve(victimcnt);
+            for (int i = 0; i < victimcnt; ++i)
+            {
+                m_victimids.push_back( params["victim[" + itoa(i) + "]"] );
+            }
+        
+            usb.printf("Successfully read %d parameters from /usb/iHvZ.cfg\r\n", readcount);
+        }
+        else
+        {
+            usb.printf("Unable to read /usb/iHvZ.cfg\r\n");
+        }
+        m_alphanum.display(m_tagids.size()==0?'Z':'H');
+        
+        // Success or failure
+        return readcount > 0;
+    }
+    
+    
+    /* Getters */
+    /// Get the status
+    inline bool status() { return m_tagids.size() ? STATUS_HUMAN : STATUS_ZOMBIE; }
+    /// Get the id
+    inline string id() { return m_id; }
+    /// Get the next tagid
+    inline string life()
+    {
+        if (m_tagids.size() == 0) return m_id;
+        return m_tagids.back();
+    }
+    /// Get the victims vector
+    inline vector<string> &get_victims() { return m_victimids; }
+    
+    /// Get stun time
+    inline unsigned stun_duration() { return m_stun_duration; }    
+    /// Get incubation time
+    inline unsigned incubation_time() { return m_incubation_time; }
+    /// Get the stun tracker
+    inline Stun &stun_tracker() { return m_stun; }
+    /// Get the tag tracker
+    inline Tag &tag_tracker() { return m_tag; }
+    /// Get the xbee device
+    inline XBee &xbee_device() { return m_xb; }
+    /// Get the UDP device
+    //inline UDP &udp_device() { return m_server; }
+    /// Get the alphanum device
+    inline AlphaNumDisplay &alphanumdisplay_device() { return m_alphanum; }
+    
+    
+    /* Setters */
+    /// Set the id
+    inline void id(string newid) { m_id = newid; m_xb.uid(newid); }
+    /// Add a tagid
+    inline void life(string newtagid) { 
+        m_tagids.push_back(newtagid); 
+        
+        m_alphanum.display('H');
+    }
+    /// Set stun time
+    inline void stun_duration(unsigned stun) { m_stun_duration = stun; }    
+    /// Set incubation time
+    inline void incubation_time(unsigned incubation) { m_incubation_time = incubation; }
+
+    /* Meta-actions */
+    inline void tagged()
+    {
+        if (status() == STATUS_ZOMBIE) return;
+        // Should we have an admin flag?
+        
+        // Use up the next player life or antidote
+        if (m_tagids.size() > 0) m_tagids.pop_back();
+        
+        // If the player still has lives, they are fine
+        if (m_tagids.size() > 0) return;
+        
+        // This player is now a zombie!
+        m_stun.stun(m_incubation_time);
+
+        // Save the stun to prevent power cycle cheating
+        save();
+        wait(1);
+        m_alphanum.display('Z');
+    }
+    
+    // Register the tagging of the given tagID by this device
+    inline void register_tag(string tagid) { m_victimids.push_back(tagid); }
+    
+    // Clear the victim list
+    inline void clear_victims() { m_victimids.clear(); }
+    inline void clear_lives() { m_tagids.clear(); }
+    
+    inline void stunned()
+    {
+        if (status() == STATUS_HUMAN) return;
+        
+        // This zombie is now stunned
+        m_stun.stun(m_stun_duration);
+        
+        // Save the stun to prevent power cycle cheating
+        save();
+    }
+    
+    inline void register_stun(string tagid) {}
+};
+
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/udp.cpp	Sun Dec 12 19:35:00 2010 +0000
@@ -0,0 +1,342 @@
+#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;
+} 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/udp.hpp	Sun Dec 12 19:35:00 2010 +0000
@@ -0,0 +1,182 @@
+#ifndef _UDP
+#define _UDP
+
+#include <string>
+#include <vector>
+#include <queue>
+#include <cctype>
+#include <iostream>
+
+#include "mbed.h"
+#include "if/eth/EthernetNetIf.h"
+#include "iHvZ.hpp"
+
+#include "util/types.h"
+#include "net/net.h"
+
+#include "core/net.h"
+#include "core/host.h"
+
+#define HVZ_PORT 4489
+#define HVZ_HOSTNAME "kylelemons.net"
+
+enum UDPErr
+{
+  __UDPSOCKET_MIN = -0xFFFF,
+  UDPSOCKET_SETUP, ///<UDPSocket not properly configured
+  UDPSOCKET_IF, ///<Interface has problems, does not exist or is not initialized
+  UDPSOCKET_MEM, ///<Not enough mem
+  UDPSOCKET_INUSE, ///<Interface / Port is in use
+//...
+  UDPSOCKET_OK = 0 ///<Success
+};
+
+///UDP Socket Event(s)
+enum UDPSocketEvent //Only one event here for now, but keeps that model in case we need to implement some others
+{
+  UDPSOCKET_READABLE, ///<Data in buf
+};
+
+enum responseType
+{
+   HVZ_REG = 0,
+   HVZ_TAG,
+   HVZ_PULL
+};
+
+enum pullType
+{
+   PULL_DEV = 0,
+   PULL_MAC
+};
+
+class NetUdpSocket;
+enum NetUdpSocketEvent;
+
+class UDP {
+public:
+
+  iHvZ *m_game;                     //< Maintain a connection to the active game
+  
+  Ethernet_MAC mac;                 
+  Ethernet eth;                     
+  EthernetNetIf conn;
+  char srvr_resp[128];
+  int registered;
+  
+  DigitalIn   m_eth;
+  InterruptIn m_eth_int;            //< Get an interrupt whenever the ethernet button is hit
+  Timeout     m_eth_chk;
+          
+public:
+
+  /* Creates a new socket */
+  UDP(iHvZ *game, PinName eth_in);
+  
+  /* Closes and destroys socket */
+  ~UDP(); //close()
+  
+  /* Check to see if theres an ethernet connection */
+  void check();
+      
+  /* Sends data to Server */
+  int sendto(const char* buf, int len, Host* pHost);
+  
+  /* Receive from Server */
+  int recvfrom(char* buf, int len, Host* pHost);
+  
+  /* Closes the socket */
+  UDPErr close();
+  
+  /* Checks to see if theres an ethernet link */
+  void ethlink();
+  
+  /* Read response from Server */
+  void read(UDPSocketEvent e);
+  
+  /* Set the game device and tag IDs */
+  void set_ids(char *response);
+   
+  /* Registers the new device */
+  inline void register_device(Ethernet_MAC originMAC, Host *host)
+  {
+     char data[34];
+     
+     sprintf(data, "iHvZ\001reg\001%02X%02X%02X%02X%02X%02X\001end", originMAC.octet[0], originMAC.octet[1], 
+         originMAC.octet[2], originMAC.octet[3], originMAC.octet[4], originMAC.octet[5]);              
+
+     sendto(data, strlen(data), host);           
+  }
+    
+  /* Sends a player tag to the server of the tagged device */
+  inline void send_tag(Host *host, vector<string> taggedIDs);
+  
+  //Requests an update of all settings from Server
+  inline void send_pull(Host *host);
+  
+  inline int get_ack_err(char *response, responseType type)
+  {  
+      char ack_err[3];
+      int i;
+      
+      memset(ack_err,0,3);
+      
+      for( i = 5; i < 8; i++ )
+          memcpy(&(ack_err[i-5]),&(response[i]),1);
+          
+      if( strcmp(ack_err,"ack") == 0 ) {
+            
+          switch( type ) {
+            case HVZ_REG:                          
+              return 1;           
+        
+            case HVZ_PULL:            
+              return 1;           
+            
+            case HVZ_TAG:
+              // If sent invalid taggedIDs to server, the response will be ack
+              // but it will not have valid tagged IDs, this is the size
+              // of such a response
+              if( strlen(response) > 16 ) 
+                  return 1;
+              
+              else 
+                  return 0;
+              
+          }
+      }
+      
+      return 0;      
+  }
+  
+  /* Update the Settings for the game */
+  void update_settings(char *response);
+ 
+  class CDummy;
+  
+  ///Setups callback
+  template<class T> 
+  void setOnEvent( T* pItem, void (T::*pMethod)(UDPSocketEvent) )
+  {
+    m_pCbItem = (CDummy*) pItem;
+    m_pCbMeth = (void (CDummy::*)(UDPSocketEvent)) pMethod;
+  }
+  
+  ///Disables callback
+  void resetOnEvent();
+
+protected:
+  void onNetUdpSocketEvent(NetUdpSocketEvent e);
+  UDPErr checkInst();
+
+private:
+  NetUdpSocket* m_pNetUdpSocket;
+  
+  CDummy* m_pCbItem;
+  void (CDummy::*m_pCbMeth)(UDPSocketEvent);
+  
+  void (*m_pCb)(UDPSocketEvent);
+      
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Dec 12 19:35:00 2010 +0000
@@ -0,0 +1,38 @@
+#include "mbed.h"
+#include "lib/iHvZ.hpp"
+#include "XBee.hpp"
+#include "string.h"
+
+iHvZ        game("TEST_UID");
+Serial      usb(USBTX, USBRX);
+DigitalOut  human_led(LED1);
+
+void dots() {
+    usb.printf(".");
+}
+
+Ticker      dotter;
+
+int main() {
+    dotter.attach(dots, 10);
+    
+    usb.printf("Starting iHvZ:\r\n");
+    
+    if (game.load())
+    {
+        usb.printf(" - Loading state from file\r\n");
+    }
+    else
+    {
+        usb.printf(" - Starting as ZOMBIE (no file read)\r\n");
+        //game.life("FAKE_TID");
+    }
+    game.save();
+    
+    while(1)
+    {        
+        //(game.alphanumdisplay_device()).display('H');
+        human_led = game.status() == STATUS_HUMAN;
+        wait(.1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sun Dec 12 19:35:00 2010 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/e2ac27c8e93e