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