Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: XBeeLib mbed HvZAlphaNumLib HvZServerLib
Revision 0:9cdba0589ba2, committed 2010-12-12
- Comitter:
- etherealflaim
- Date:
- Sun Dec 12 19:35:00 2010 +0000
- Child:
- 1:d1b5cd8b2c18
- Commit message:
Changed in this revision
--- /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