Coordinator v2

Dependencies:   NerfUSXbee PinDetect EthernetInterface JSON MFRC522 WebSocketClient mbed-rtos mbed

Files at this revision

API Documentation at this revision

Comitter:
Ismael Balafrej
Date:
Mon Apr 10 15:02:24 2017 -0400
Child:
2:019d8848cf7e
Commit message:
V1

Changed in this revision

.hgignore Show annotated file Show diff for this revision Revisions of this file
NerfUSXbee.lib Show annotated file Show diff for this revision Revisions of this file
PinDetect.lib Show annotated file Show diff for this revision Revisions of this file
includes/BtnHandler.hpp Show annotated file Show diff for this revision Revisions of this file
includes/FreeMem.h Show annotated file Show diff for this revision Revisions of this file
includes/GameCoordinator.hpp Show annotated file Show diff for this revision Revisions of this file
includes/GameMode.hpp Show annotated file Show diff for this revision Revisions of this file
includes/GameModes/ReflexMode.hpp Show annotated file Show diff for this revision Revisions of this file
includes/GameModes/SpeedMode.hpp Show annotated file Show diff for this revision Revisions of this file
includes/ServerData.hpp Show annotated file Show diff for this revision Revisions of this file
includes/Target.hpp Show annotated file Show diff for this revision Revisions of this file
includes/dispatcher.hpp Show annotated file Show diff for this revision Revisions of this file
includes/jsonParser.hpp Show annotated file Show diff for this revision Revisions of this file
includes/ports.hpp Show annotated file Show diff for this revision Revisions of this file
includes/serverEvents.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
src/GameCoordinator.cpp Show annotated file Show diff for this revision Revisions of this file
src/Target.cpp Show annotated file Show diff for this revision Revisions of this file
src/ports.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,10 @@
+BUILD
+.temp
+JSON
+mbed-rtos
+mbed
+WebSocketClient
+.git
+MFRC522
+JSON
+EthernetInterface
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NerfUSXbee.lib	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,1 @@
+https://mbed.org/teams/NerfUS/code/NerfUSXbee/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PinDetect.lib	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,1 @@
+https://mbed.org/users/AjK/code/PinDetect/#cb3afc45028b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/BtnHandler.hpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,24 @@
+#pragma once
+#include "ports.hpp"
+#include "PinDetect.h"
+#include "ServerData.hpp"
+#include "serverEvents.hpp"
+
+class BtnHandler {
+    PinDetect _interrupt;
+    ServerEvent event;
+    public:
+        BtnHandler(PinName pin, const char *eventName) : _interrupt(pin) {
+            strcpy(event.event, eventName);
+            _interrupt.mode( PullDown );
+            _interrupt.setSampleFrequency();
+            _interrupt.attach_asserted(this, &BtnHandler::sendEvent);
+        }
+        BtnHandler(PinName pin, const char *eventName, const char *direction) : BtnHandler(pin, eventName) {
+            strcpy(event.data.direction, direction);
+        }
+        void sendEvent()
+        {
+            websocket_message_send(event);
+        }
+};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/FreeMem.h	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,36 @@
+/* Using malloc() to determine free memory.*/
+//https://developer.mbed.org/questions/6994/How-to-print-Free-RAM-available-RAM-or-u/
+ 
+#include <stdio.h>
+#include <stdlib.h>
+#define FREEMEM_CELL 100
+struct elem { /* Definition of a structure that is FREEMEM_CELL bytes  in size.) */
+    struct elem *next;
+    char dummy[FREEMEM_CELL-2];
+};
+int FreeMem(void) {
+    int counter;
+    struct elem *head, *current, *nextone;
+    current = head = (struct elem*) malloc(sizeof(struct elem));
+    if (head == NULL)
+        return 0;      /*No memory available.*/
+    counter = 0;
+   // __disable_irq();
+    do {
+        counter++;
+        current->next = (struct elem*) malloc(sizeof(struct elem));
+        current = current->next;
+    } while (current != NULL);
+    /* Now counter holds the number of type elem
+       structures we were able to allocate. We
+       must free them all before returning. */
+    current = head;
+    do {
+        nextone = current->next;
+        free(current);
+        current = nextone;
+    } while (nextone != NULL);
+   // __enable_irq();
+ 
+    return counter*FREEMEM_CELL;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/GameCoordinator.hpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,30 @@
+#pragma once
+#include <vector>
+#include "ports.hpp"
+#include "Target.hpp"
+#include "ServerData.hpp"
+#include "GameMode.hpp"
+#include "ReflexMode.hpp"
+#include "SpeedMode.hpp"
+
+class GameCoordinator
+{
+    public:
+        GameCoordinator();
+
+        void start_game(ServerData *configs);
+        void stop_game();
+        void ticker_callback();
+        void get_next_round();
+
+        vector<Target> targets;
+        Thread Tget_next_round;
+    private:
+        vector<GameMode*> game_modes; 
+        GameMode* current_game;
+        uint16_t target_timeout = 10000;
+        uint8_t number_of_targets = 10;
+        Ticker ticker;
+};
+
+extern GameCoordinator gameCoordinator;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/GameMode.hpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,42 @@
+#pragma once
+#include <vector>
+#include "ports.hpp"
+#include "Target.hpp"
+#include "ServerData.hpp"
+
+class GameMode
+{
+public:
+  GameMode(vector<Target> *_targets)
+  {
+    targets = _targets;
+  }
+
+  virtual bool IsWeaponValid(int weaponId)
+  {
+    return true; //Default to any Weapons
+  }
+
+  virtual ServerData GetStats()
+  {
+    return stats;
+  }
+
+  virtual Target* GetNextTarget() = 0;  
+  virtual void OnTargetHit(int timeTaken) = 0;
+  virtual void OnTargetMiss() = 0;  
+  virtual int getTimeBetweenTargets()
+  {
+    return 1000; //default to 1 sec
+  }
+
+protected:
+  ServerData stats;
+  vector<Target>* targets;
+  Target *GetRandomTarget()
+  {
+    int target_nb = rand() % targets->size();
+    return &(targets->at(target_nb));
+
+  }
+};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/GameModes/ReflexMode.hpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,25 @@
+#pragma once
+#include "GameMode.hpp"
+
+class ReflexMode : public GameMode
+{
+  public:
+    using GameMode::GameMode;
+    Target* GetNextTarget()
+    {
+      return GetRandomTarget();
+    }
+    void OnTargetHit(int timeTaken)
+    {
+      stats.targets++;
+      stats.score += 5;
+    }
+    void OnTargetMiss()
+    {
+      stats.score -= 1;
+    }  
+    int getTimeBetweenTargets()
+    {
+      return rand() % 3000 + 500;
+    }
+};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/GameModes/SpeedMode.hpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,25 @@
+#pragma once
+#include "GameMode.hpp"
+
+class SpeedMode : public GameMode
+{
+  public:
+    using GameMode::GameMode;
+    Target* GetNextTarget()
+    {
+      return GetRandomTarget();
+    }
+    void OnTargetHit(int timeTaken)
+    {
+      stats.targets++;
+      stats.score += 5;
+    }
+    void OnTargetMiss()
+    {
+      stats.score -= 1;
+    }  
+    int getTimeBetweenTargets()
+    {
+      return 1000;
+    }
+};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/ServerData.hpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,26 @@
+#pragma once
+
+//TODO: Separate ?
+struct ServerData
+{
+    //To server
+    uint8_t targets = 0;
+    uint8_t enemies = 0;
+    uint8_t allies = 0;
+    uint16_t averageReflexTime = 0;
+    uint16_t gameLength = 0;
+    uint16_t score = 0;
+    char rfid_code[32] = {'\0'};
+    char direction[10] = {'\0'};
+
+    //From server
+    uint8_t game_id = 0;
+    uint16_t max_reflex_time = 10000;
+    uint8_t number_of_target = 100;
+
+};
+struct ServerEvent
+{
+    char event[32] = {'\0'};
+    ServerData data;
+};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/Target.hpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,19 @@
+#pragma once
+#include <vector>
+#include "ports.hpp"
+#include "RealXbeeTransmitter.hpp"
+
+extern RealXbeeTransmitter xbee_transmitter;
+
+struct Target
+{
+    int target_number; //0 or 1
+    int addr_table[8]; //64 bit addr
+
+    Target(int address_msb, int address_lsb, int target_number);
+
+    //mode: ally (0) or enemy (1), timeout 16 bits in ms
+    void rise(int mode, int timeout);
+
+    void get_address_for_xbee(int address_msb, int address_lsb);
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/dispatcher.hpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,23 @@
+#pragma once
+#include "ports.hpp"
+#include "ServerData.hpp"
+#include "GameCoordinator.hpp"
+#include <vector>
+
+void dispatch_event_from_target(vector<uint8_t> data, int* address)
+{
+    //addr: table of 8 int 
+    //TODO - calc stats
+}
+
+void dispatch_event_from_server(ServerEvent *event) {
+    toPc("Event Name: %s", event->event);
+    if (strcmp(event->event, "start_game") == 0)
+    {
+        gameCoordinator.start_game(&(event->data));
+    } 
+    else if (strcmp(event->event, "request_report") == 0)
+    {
+        gameCoordinator.stop_game();
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/jsonParser.hpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,55 @@
+#pragma once
+#include "ports.hpp"
+#include "Json.h"
+#include "ServerData.hpp"
+
+bool get_value_from_json(char *jsonSource, const char *keyName, char *outValue)
+{
+    Json json(jsonSource, strlen(jsonSource), 40); //Can add 3rd argument if json is too big, default: 32 tokens
+    if (!json.isValidJson())
+    {
+        toPc("Invalid JSON: %s", jsonSource);
+        return false;
+    }
+    if (json.type(0) != JSMN_OBJECT)
+    {
+        toPc("Invalid JSON.  ROOT element is not Object: %s", jsonSource);
+        return false;
+    }
+    int keyIndex = json.findKeyIndexIn(keyName, 0);
+    if (keyIndex == -1)
+    {
+        //toPc("\"%s\" key not found in json: %s", keyName, jsonSource);
+        return false;
+    }
+    int valueIndex = json.findChildIndexOf(keyIndex, -1);
+    if (valueIndex > 0)
+    {
+        const char *valueStart = json.tokenAddress(valueIndex);
+        int valueLength = json.tokenLength(valueIndex);
+        strncpy(outValue, valueStart, valueLength);
+        outValue[valueLength] = 0;
+        return true;
+    }
+    return false;
+}
+
+void parse_server_event_from_json(char *jsonSource, ServerEvent *returnEvent)
+{
+    char data[250]; //container for the json in "data"
+    get_value_from_json(jsonSource, "event", returnEvent->event);
+
+    bool data_parse_successful = get_value_from_json(jsonSource, "data", data);
+    if (data_parse_successful)
+    {
+        char tmp[32];
+        if (get_value_from_json(data, "game_id", tmp))
+            returnEvent->data.game_id = atoi(tmp);
+
+        if (get_value_from_json(data, "max_reflex_time", tmp))
+            returnEvent->data.max_reflex_time = atoi(tmp);
+
+        if (get_value_from_json(data, "number_of_target", tmp))
+            returnEvent->data.number_of_target = atoi(tmp);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/ports.hpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,11 @@
+#pragma once
+#include "mbed.h"
+//#include "rtos.h"
+//#include "lpc17xx.h"
+
+//Printf to pc and add new line
+#define toPc(str, ...) pc.printf(str, ##__VA_ARGS__); pc.printf("\r\n");
+#define cls() pc.printf("\033[2J\r\n"); //Clear pc screen
+
+extern Serial pc;
+extern DigitalOut leds[4];
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/serverEvents.hpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,122 @@
+#pragma once
+#include "ports.hpp"
+#include "EthernetInterface.h"
+#include "Websocket.h"
+#include "jsonParser.hpp"
+#include "dispatcher.hpp"
+
+#define USING_DHCP_SERVER 0
+
+EthernetInterface eth;
+Websocket ws("ws://1.0.0.1:8080/");
+Mail<ServerEvent, 30> messages_to_server;
+void websocket_message_send(ServerEvent event);
+
+void ethernet_initialization() {
+    #if USING_DHCP_SERVER
+        eth.init();
+    #else
+        char ip_addr[]="1.0.0.2";
+        char mask[]="255.255.255.0";
+        char gateway[]="1.0.0.1";
+        eth.init(ip_addr, mask, gateway); 
+    #endif
+    
+    eth.connect();
+    toPc("IP Address is %s", eth.getIPAddress());
+    toPc("Mask is %s", eth.getNetworkMask());
+}
+
+void websocket_initialization() {
+    toPc("Connecting to websocket url: \"ws://1.0.0.1:8080/\"");
+    ws.connect();
+    if (ws.is_connected()) {
+        ws.send("{\"event\":\"mbed\",\"data\":\"{\"state\": \"connected\"}\"}");
+    }
+}
+
+//Thread
+void websocket_message_receiver() {
+    ethernet_initialization();
+    websocket_initialization();
+
+    char msgBuffer[500];
+    ServerEvent newEvent;
+    while(1) {
+        if (!ws.is_connected()) {
+            toPc("Disconnected from websocket... Attempting to reconnect");
+            websocket_initialization();
+        } else {
+            if (ws.read(msgBuffer)) {
+                toPc("New message received from server");
+                parse_server_event_from_json(msgBuffer, &newEvent);
+                dispatch_event_from_server(&newEvent);
+            }
+        }
+        Thread::wait(100);
+    }
+}
+
+//Via thread
+void websocket_message_send(ServerEvent event)
+{
+    ServerEvent *newEvent = messages_to_server.alloc();
+    *newEvent = event;
+    messages_to_server.put(newEvent);
+}
+
+//Direct send
+void send_message_to_websocket(ServerEvent *event)
+{
+    char msgBuffer[500];
+    if (strcmp(event->event, "start") == 0) {
+        sprintf(msgBuffer, "{"
+            "\"event\":\"%s\""
+        "}", event->event);
+    } else if (strcmp(event->event, "navigate") == 0) {
+        sprintf(msgBuffer, "{"
+            "\"event\":\"%s\","
+            "\"data\":{"
+                "\"direction\":\"%s\""
+            "}"
+        "}", event->event, event->data.direction);
+    } else if (strcmp(event->event, "gun") == 0) {
+        sprintf(msgBuffer, "{"
+            "\"event\":\"%s\","
+            "\"data\":{"
+                "\"rfid_code\":\"%s\""
+            "}"
+        "}", event->event, event->data.rfid_code);
+    } else { //event == report
+        sprintf(msgBuffer, "{"
+            "\"event\":\"%s\","
+            "\"data\":{"
+                "\"allies\": %i,"
+                "\"enemies\": %i,"
+                "\"targets\": %i,"
+                "\"averageReflexTime\": %i,"
+                "\"gameLength\": %i,"
+                "\"score\": %i"
+            "}"
+        "}", event->event, event->data.allies, event->data.enemies, 
+        event->data.targets, event->data.averageReflexTime, event->data.gameLength, 
+        event->data.score);
+    }
+
+    //toPc("Sending msg to websocket: %s", msgBuffer);
+    ws.send(msgBuffer);
+}
+
+//Thread
+void websocket_message_sender()
+{
+    while(1) {
+        osEvent evt = messages_to_server.get();
+        if (evt.status == osEventMail) {
+            ServerEvent *mail = (ServerEvent*)evt.value.p;
+            send_message_to_websocket(mail);            
+            messages_to_server.free(mail);
+        }
+        Thread::yield();
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,86 @@
+#include <vector>
+#include "ports.hpp"
+#include "serverEvents.hpp"
+#include "Target.hpp"
+#include "RealXbeeReceiver.hpp"
+#include "BtnHandler.hpp"
+#include "GameCoordinator.hpp"
+#include "FreeMem.h"
+#include "MFRC522.h"
+
+#define MF_RESET    D8
+
+DigitalOut LedGreen(LED1);
+MFRC522 RfChip(p5, p6, p7, p21, p22);
+
+int main()
+{
+    cls();
+    toPc("Coordinator starting...");
+    toPc("Initial Memory: %i", FreeMem());
+
+    //Starting the different threads
+    //Websocket
+    Thread Twebsocket_message_receiver(websocket_message_receiver, osPriorityLow, 2300);
+    Thread Twebsocket_message_sender(websocket_message_sender, osPriorityLow, 1500);
+
+    //Xbee
+    RealXbeeReceiver xbeeReceiver;
+    xbeeReceiver.start(&dispatch_event_from_target);
+
+    //Btn interupts
+    BtnHandler startBtn(p21, "start");
+    BtnHandler nextBtn(p22, "navigate", "next");
+    BtnHandler previousBtn(p23, "navigate", "previous");
+
+    //Creating the targets with their 64 bits address
+    //Bruno/Max Router
+    gameCoordinator.targets.push_back(Target(0x0013A200, 0x4086DA0E, 0));
+    gameCoordinator.targets.push_back(Target(0x0013A200, 0x4086DA0E, 1));
+    //TODO: more targets
+
+    RfChip.PCD_Init();
+
+    while(1) {
+        LedGreen = 1;
+
+        // Look for new cards
+        if ( ! RfChip.PICC_IsNewCardPresent())
+        {
+            toPc("No card detected");
+            Thread::wait(500);
+            continue;
+        }
+    
+        // Select one of the cards
+        if ( ! RfChip.PICC_ReadCardSerial())
+        {
+            toPc("Cant read serial");
+            Thread::wait(500);
+            //wait_ms(500);
+            continue;
+        }
+        toPc("Printing card");
+        LedGreen = 0;
+ 
+        // Print Card UID
+        pc.printf("Card UID: ");
+        for (uint8_t i = 0; i < RfChip.uid.size; i++)
+        {
+        pc.printf(" %X02", RfChip.uid.uidByte[i]);
+        }
+        pc.printf("\n\r");
+
+
+        //Memory monitoring
+        // toPc("Thread Twebsocket_message_receiver max stack: %i / %i", Twebsocket_message_receiver.max_stack(), Twebsocket_message_receiver.stack_size());
+        // toPc("Thread Twebsocket_message_sender max stack: %i / %i", Twebsocket_message_sender.max_stack(), Twebsocket_message_sender.stack_size());
+        // toPc("Thread gameCoordinator.Tget_next_round max stack: %i / %i", gameCoordinator.Tget_next_round.max_stack(), gameCoordinator.Tget_next_round.stack_size());
+        // toPc("Thread xbeeReceiver.message_handler_thread max stack: %i / %i", xbeeReceiver.message_handler_thread.max_stack(), xbeeReceiver.message_handler_thread.stack_size());
+        // toPc("Thread xbeeReceiver.message_reader_thread max stack: %i / %i", xbeeReceiver.message_reader_thread.max_stack(), xbeeReceiver.message_reader_thread.stack_size());
+        // toPc("Free Memory: %i", FreeMem());
+        Thread::wait(1000);
+    }
+    //Thread::wait(osWaitForever);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/GameCoordinator.cpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,58 @@
+#include "GameCoordinator.hpp"
+
+GameCoordinator gameCoordinator;
+
+//TODO: move that to .cpp 
+GameCoordinator::GameCoordinator()
+{
+    //Adding all the game modes to the game_modes vector
+    //TODO: can we avoid new operator ?
+    ReflexMode *reflex_mode = new ReflexMode(&targets);
+    SpeedMode *speed_mode = new SpeedMode(&targets);
+    game_modes.push_back(reflex_mode);
+    game_modes.push_back(speed_mode);
+
+    //Starting internal thread
+    Tget_next_round = Thread(osPriorityNormal, 800);
+    Tget_next_round.start(this, &GameCoordinator::get_next_round);
+}
+
+void GameCoordinator::start_game(ServerData *configs)
+{
+    current_game = game_modes[configs->game_id];
+    target_timeout = configs->max_reflex_time;
+    number_of_targets = configs->number_of_target;
+    ticker.attach(callback(this, &GameCoordinator::ticker_callback), current_game->getTimeBetweenTargets() / 1000.0);
+}
+
+void GameCoordinator::stop_game()
+{
+    ticker.detach();
+    LPC_TIM3->TC = 0;
+    //TODO: send stats back to server
+}
+
+void GameCoordinator::ticker_callback()
+{
+    Tget_next_round.signal_set(0x1);
+}
+
+//Thread
+void GameCoordinator::get_next_round()
+{
+    while (1)
+    {
+        Thread::signal_wait(0x1);
+        Target *nextTarget = current_game->GetNextTarget();
+        if (nextTarget == NULL || number_of_targets-- <= 0)
+        {
+            stop_game();
+        } 
+        else
+        {
+            //TODO: how to select enemy or ally ?
+            nextTarget->rise(rand() % 2, target_timeout);
+        }
+        Thread::yield();
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Target.cpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,32 @@
+#include "Target.hpp"
+
+RealXbeeTransmitter xbee_transmitter;
+
+Target::Target(int address_msb, int address_lsb, int target_number)
+{
+    get_address_for_xbee(address_msb, address_lsb);
+    this->target_number = target_number;
+}
+
+void Target::rise(int mode, int timeout)
+{
+    toPc("Rising target %i!", target_number);
+    vector<uint8_t> message;
+    message.push_back(target_number);
+    message.push_back(mode);
+    message.push_back((timeout >> 8) & 0xFF);
+    message.push_back(timeout && 0xFF);
+    xbee_transmitter.transmit(message, addr_table);
+}
+
+void Target::get_address_for_xbee(int address_msb, int address_lsb)
+{
+    addr_table[0] = address_msb >> 24;
+    addr_table[1] = (address_msb >> 16) & 0xFF;
+    addr_table[2] = (address_msb >> 8) & 0xFF;
+    addr_table[3] = (address_msb) & 0xFF;
+    addr_table[4] = address_lsb >> 24;
+    addr_table[5] = (address_lsb >> 16) & 0xFF;
+    addr_table[6] = (address_lsb >> 8) & 0xFF;
+    addr_table[7] = (address_lsb) & 0xFF;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ports.cpp	Mon Apr 10 15:02:24 2017 -0400
@@ -0,0 +1,6 @@
+#include "ports.hpp"
+
+Serial pc(USBTX, USBRX);
+DigitalOut leds[4] = {
+    DigitalOut(LED1), DigitalOut(LED2), DigitalOut(LED3), DigitalOut(LED4)
+};
\ No newline at end of file