Microcontroller firmware that uses a simple, yet powerful scripting language to control the timing of input and output events with high temporal resolution. Written by Mattias Karlsson

Dependencies:   SMARTWAV mbed

Files at this revision

API Documentation at this revision

Comitter:
mkarlsso
Date:
Fri Jan 15 22:13:23 2016 +0000
Parent:
3:d7b0a0890d96
Child:
5:67d67d452545
Commit message:
Fixed an issue where syntax errors caused the program to crash instead of just reporting the syntax error.

Changed in this revision

behave.cpp Show annotated file Show diff for this revision Revisions of this file
behave.h Show annotated file Show diff for this revision Revisions of this file
mbedInterface/mbedInterface.cpp Show annotated file Show diff for this revision Revisions of this file
mbedInterface/mbedInterface.h Show annotated file Show diff for this revision Revisions of this file
--- a/behave.cpp	Sat Oct 10 22:37:17 2015 +0000
+++ b/behave.cpp	Fri Jan 15 22:13:23 2016 +0000
@@ -293,7 +293,7 @@
         numTriggersToProcess = hardware->getPendingFunctionTriggers(shortcutTriggers);
         for (int i = 0; i < numTriggersToProcess; i++) {
             textDisplay << "Trigger function " << shortcutTriggers[i]+1 << "\r\n";
-            if ((shortcutTriggers[i] < NUMTRIGGERACTIONS) && functionSpotTaken[shortcutTriggers[i]]) {
+            if ((shortcutTriggers[i] < NUMTRIGGERACTIONS) && functionSpotTaken[shortcutTriggers[i]] && functionEventArray[i]->isUsed) {
                 //textDisplay << "Executing function array index " << shortcutTriggers[i] << "\r\n";
                 functionEventArray[shortcutTriggers[i]]->execute();
             }
@@ -481,7 +481,7 @@
                         lastChangeTime = timeKeeper;
                     }
                     */
-                    if (triggerUpEventPtr != NULL) {triggerUpEventPtr->execute();}
+                    if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();}
                 } else if (inState == 0) {
 
                     lastChangeInterval = inPin->lastDownEvent.timeStamp - lastChangeTime;
@@ -496,7 +496,7 @@
                         lastChangeTime = timeKeeper;
                     }*/
 
-                    if (triggerDownEventPtr != NULL) {triggerDownEventPtr->execute();}
+                    if (triggerDownEventPtr != NULL && triggerDownEventPtr->isUsed){triggerDownEventPtr->execute();}
                 }
             } else if (lastInState == inState) {
 
@@ -506,15 +506,15 @@
                     lastChangeInterval = inPin->lastUpEvent.timeStamp - inPin->lastDownEvent.timeStamp;
                     lastChangeTime = inPin->lastUpEvent.timeStamp;
 
-                    if (triggerDownEventPtr != NULL) {triggerDownEventPtr->execute();}
-                    if (triggerUpEventPtr != NULL) {triggerUpEventPtr->execute();}
+                    if (triggerDownEventPtr != NULL && triggerDownEventPtr->isUsed) {triggerDownEventPtr->execute();}
+                    if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();}
                 } else if (inState == 0) {
 
                     lastChangeInterval = inPin->lastDownEvent.timeStamp - inPin->lastUpEvent.timeStamp;
                     lastChangeTime = inPin->lastDownEvent.timeStamp;
 
-                    if (triggerUpEventPtr != NULL) {triggerUpEventPtr->execute();}
-                    if (triggerDownEventPtr != NULL) {triggerDownEventPtr->execute();}
+                    if (triggerUpEventPtr != NULL && triggerUpEventPtr->isUsed) {triggerUpEventPtr->execute();}
+                    if (triggerDownEventPtr != NULL && triggerDownEventPtr->isUsed) {triggerDownEventPtr->execute();}
                 }
             }
 
@@ -615,7 +615,7 @@
 
 void triggerFunctionAction::execute() {
 
-    if (functionSpotTaken[functionNum]) {
+    if (functionSpotTaken[functionNum] && functionEventArray[functionNum]->isUsed) {
         functionEventArray[functionNum]->execute();
     }
 
@@ -2215,7 +2215,7 @@
 //-------------------------------------------------------
 void scriptStream::parseBlock() {
 
-
+    tmpEvent = NULL;
     lineError = false;
     blockDepth = 0;
     ifBlockInit = false;
@@ -2477,10 +2477,16 @@
                     textDisplay << "Error: clock commands only allowed outside of block structure\r\n";
                     lineError = true;
                 }
+                int pos1 = tmpLine.find("clock(")+6;
+                int pos2 = tmpLine.find_first_of(")",pos1);
+                if (pos2 == std::string::npos) {
+                    textDisplay << "Syntax Error: expected a ')'\r\n";
+                    lineError = true;
+                }
 
                 if (!lineError) {
-                    int pos1 = tmpLine.find("clock(")+6;
-                    int pos2 = tmpLine.find_first_of(")",pos1);
+                    //int pos1 = tmpLine.find("clock(")+6;
+                    //int pos2 = tmpLine.find_first_of(")",pos1);
                     string dispVar = tmpLine.substr(pos1,pos2-pos1);
 
 
@@ -2612,61 +2618,67 @@
                 wholeLineEvaluated = true;
                 int pos1 = tmpLine.find("trigger(")+8;
                 int pos2 = tmpLine.find_first_of(")",pos1);
-                int funcNum = atoi(tmpLine.substr(pos1,pos2-pos1).data());
-                if ((funcNum > 0) && (funcNum < NUMFUNCTIONS+1)) {
-                    if (functionSpotTaken[funcNum-1]) {
-
-
-                    } else {
-                        textDisplay << "Error: function number does not exist\r\n";
-                        lineError = true;
-                    }
-                } else {
-                    textDisplay << "Error: not a valid function number\r\n";
+                if (pos2 == std::string::npos) {
+                    textDisplay << "Syntax error: expected a ')'\r\n";
                     lineError = true;
                 }
 
-                funcNum--;  //change to 0-based index
-                if (!lineError && (blockDepth == 0)) {
-                    //we are not inside a block structure, so execute function now
-                    //textDisplay << "Exectuting function";
-                    //textDisplay.flush();
-
-                    functionEventArray[funcNum]->execute();
-
-                } else if (!lineError && (blockDepth > 0) ){
-                    //the trigger function was put inside a block, so we need to create a new action
-                    textDisplay.debug("Trigger statement\r\n");
-                    triggerFunctionAction* tPtr = findFirstUnUsed(triggerFunctionActionBlock, NUMTRIGGERACTIONS);
-                    if (tPtr == NULL) {
-                        textDisplay << "Error: no memory slots available.\r\n";
+                if (!lineError) {
+                    int funcNum = atoi(tmpLine.substr(pos1,pos2-pos1).data());
+                    if ((funcNum > 0) && (funcNum < NUMFUNCTIONS+1)) {
+                        if (functionSpotTaken[funcNum-1] && functionEventArray[funcNum]->isUsed) {
+
+
+                        } else {
+                            textDisplay << "Error: function number does not exist\r\n";
+                            lineError = true;
+                        }
+                    } else {
+                        textDisplay << "Error: not a valid function number\r\n";
                         lineError = true;
                     }
 
-                    if (!lineError) {
-                        //we only give provide it the function number, instead
-                        //of a pointer to the event.  That way, if the user modifies
-                        //the function (which would change the pointer), all callbacks
-                        //still using that function number will use the new function.
-                        tPtr->set(funcNum);
-                        action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
-                        if (tmpAction == NULL) {
+                    funcNum--;  //change to 0-based index
+                    if (!lineError && (blockDepth == 0)) {
+                        //we are not inside a block structure, so execute function now
+                        //textDisplay << "Exectuting function";
+                        //textDisplay.flush();
+
+                        functionEventArray[funcNum]->execute();
+
+                    } else if (!lineError && (blockDepth > 0) ){
+                        //the trigger function was put inside a block, so we need to create a new action
+                        textDisplay.debug("Trigger statement\r\n");
+                        triggerFunctionAction* tPtr = findFirstUnUsed(triggerFunctionActionBlock, NUMTRIGGERACTIONS);
+                        if (tPtr == NULL) {
                             textDisplay << "Error: no memory slots available.\r\n";
                             lineError = true;
                         }
+
                         if (!lineError) {
-
-                            tmpAction->set(tPtr);
-                            tmpEventPtrArray.back()->addAction(tmpAction);
+                            //we only give provide it the function number, instead
+                            //of a pointer to the event.  That way, if the user modifies
+                            //the function (which would change the pointer), all callbacks
+                            //still using that function number will use the new function.
+                            tPtr->set(funcNum);
+                            action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
+                            if (tmpAction == NULL) {
+                                textDisplay << "Error: no memory slots available.\r\n";
+                                lineError = true;
+                            }
+                            if (!lineError) {
+
+                                tmpAction->set(tPtr);
+                                tmpEventPtrArray.back()->addAction(tmpAction);
+                            }
                         }
+
+
                     }
 
-
                 }
 
 
-
-
                 //int is used to decalar new variables.  Only allowed outside of callbacks-------------------
                 //example: int a;  int b = 9
             } else if (tokens[i].compare("int") == 0) { //define a new integer variable
@@ -2812,7 +2824,6 @@
                     //int pos1 = tmpLine.find("trigger(")+8;
                     //int pos2 = tmpLine.find_first_of(")",pos1);
                     int tempPort = atoi(tokens[i+2].data());
-                    
                     if (tempPort > 0) {
                         specifiedPort = tempPort-1;
                     } else {
@@ -2919,72 +2930,24 @@
                 if (!lineError) {
                     //i++;
                     //clear variables
+
                     if (clearMode == 1) {
-                        while (!globalVariables.empty()) {
-                            delete globalVariables.back();
-                            globalVariables.pop_back();
-                        }
-                        broadCastStateChanges = true;
-                        for (int i=0;i<NUMPORTS;i++) {
-                            system->setPortUpdatesOn(i);
-                        }
-                    }
-
-                    //clear callbacks, functions, and queue
-                    if (clearMode < 3) {
-                        for (int pNum = 0; pNum < NUMPORTS; pNum++) {
-                            //delete portVector[pNum]->triggerUpEventPtr;
-                            if (portVector[pNum].triggerUpEventPtr != NULL) {
-                                portVector[pNum].triggerUpEventPtr->release();
-                            }
-                            portVector[pNum].triggerUpEventPtr = NULL;
-
-                            //delete portVector[pNum]->triggerDownEventPtr;
-                            if (portVector[pNum].triggerDownEventPtr != NULL) {
-                                portVector[pNum].triggerDownEventPtr->release();
-                            }
-                            portVector[pNum].triggerDownEventPtr = NULL;
-
-
-                            /*
-                             while (!functionArray.empty()) {
-                             delete functionArray.back();
-                             functionArray.pop_back();
-                             } */
-                        }
-                        for (int i = 0; i < NUMFUNCTIONS; i++) {
-                            functionSpotTaken[i] = false;
-                            functionEventArray[i] = NULL;
-                        }
-                        for (int i = 0; i < NUMEVENTS; i++) {
-                            eventBlock[i].release();
-                        }
-                        for (int i = 0; i < NUMCONDITIONS; i++) {
-                            conditionBlock[i].release();
-                        }
-                        for (int i = 0; i < NUMINTCOMPARE; i++) {
-                            intCompareBlock[i].release();
-                        }
-                        for (int i = 0; i < NUMACTIONS; i++) {
-                            actionBlock[i].release();
-                        }
-                        for (int i = 0; i < NUMPORTMESSAGES; i++) {
-                            portMessageBlock[i].release();
-                        }
-                        for (int i = 0; i < NUMINTOPERATIONS; i++) {
-                            intOperationBlock[i].release();
-                        }
-                        for (int i = 0; i < NUMDISPLAYACTIONS; i++) {
-                            displayActionBlock[i].release();
-                        }
-                        for (int i = 0; i <NUMTRIGGERACTIONS; i++) {
-                            triggerFunctionActionBlock[i].release();
-                        }
-
-                        queuePtr->eraseQueue();
-                    }
-
-                    if (clearMode == 4) {
+                        //Clears everything
+                        int sendClearMode = 0;
+                        sendClearMode |= BLOCKMEMORYTYPES;
+                        sendClearMode |= VARIABLEMEMORYTYPES;
+                        sendClearMode |= ENVSETTINGSMEMORYTYPES;
+
+                        clearEnvironmentVariables(sendClearMode);
+
+                    } else if  (clearMode == 2) {
+                        //Clear just varaibles
+                        int sendClearMode = 0;
+                        sendClearMode |= VARIABLEMEMORYTYPES;
+                        clearEnvironmentVariables(sendClearMode);
+
+                    } else if (clearMode == 3) {
+                        //Clear the current event queue (can itself be a queued action)
                         if (blockDepth > 0) { //we are inside a block
                             action* tmpAction = findFirstUnUsed(actionBlock, NUMACTIONS);
                             if (tmpAction == NULL) {
@@ -3612,6 +3575,7 @@
             }
 
             if (lineError) {
+                 textDisplay.flush();
                  break; //stop parsing the rest of the line if an error was detected
             }
             if (wholeLineEvaluated) { //some of the tokens forces the whole line to be avaluated at once
@@ -3624,20 +3588,43 @@
         if (lineError) {
 
             textDisplay << "Line text: ";
+            /*
             while (!tokens.empty()) {
                 textDisplay << tokens.front()<< " ";
-                tokens.erase(tokens.begin());
+                //tokens.erase(tokens.begin());
+            }*/
+
+            //Display the line with the syntax error
+            for (int tokInd = 0; tokInd < tokens.size(); tokInd++) {
+                textDisplay << tokens.at(tokInd) << " ";
             }
             textDisplay << "\r\n";
+            textDisplay.flush();
 
             currentBlock.resetBuffer();
+
+            //Clear the line tokens
             while (!tokens.empty()) {
                 tokens.pop_back();
             }
+
+            if (tmpEventPtrArray.size() > 0) {
+                tmpEventPtrArray.at(0)->release(); //release the unfinished block (and all children)
+            }
+            while (tmpEventPtrArray.size() > 0){
+                tmpEventPtrArray.pop_back();
+            }
+
+
             //delete tmpEvent;
-            tmpEvent->release();
+            /*
+            if (tmpEvent != NULL) {
+                tmpEvent->release();
+            }
+            */
         } else {
 
+            //Clear the line tokens
             while (!tokens.empty()) {
                 tokens.pop_back();
             }
@@ -5489,3 +5476,73 @@
 
 }
 
+void scriptStream::clearEnvironmentVariables(int clearMode) {
+    //Modes:
+
+    //clear callbacks, functions, and queue
+    if (clearMode & BLOCKMEMORYTYPES) {
+        for (int pNum = 0; pNum < NUMPORTS; pNum++) {
+            //delete portVector[pNum]->triggerUpEventPtr;
+            if (portVector[pNum].triggerUpEventPtr != NULL) {
+                portVector[pNum].triggerUpEventPtr->release();
+            }
+            portVector[pNum].triggerUpEventPtr = NULL;
+
+            //delete portVector[pNum]->triggerDownEventPtr;
+            if (portVector[pNum].triggerDownEventPtr != NULL) {
+                portVector[pNum].triggerDownEventPtr->release();
+            }
+            portVector[pNum].triggerDownEventPtr = NULL;
+
+        }
+        for (int i = 0; i < NUMFUNCTIONS; i++) {
+            functionSpotTaken[i] = false;
+            functionEventArray[i] = NULL;
+        }
+        for (int i = 0; i < NUMEVENTS; i++) {
+            eventBlock[i].release();
+        }
+        for (int i = 0; i < NUMCONDITIONS; i++) {
+            conditionBlock[i].release();
+        }
+        for (int i = 0; i < NUMINTCOMPARE; i++) {
+            intCompareBlock[i].release();
+        }
+        for (int i = 0; i < NUMACTIONS; i++) {
+            actionBlock[i].release();
+        }
+        for (int i = 0; i < NUMPORTMESSAGES; i++) {
+            portMessageBlock[i].release();
+        }
+        for (int i = 0; i < NUMINTOPERATIONS; i++) {
+            intOperationBlock[i].release();
+        }
+        for (int i = 0; i < NUMDISPLAYACTIONS; i++) {
+            displayActionBlock[i].release();
+        }
+        for (int i = 0; i <NUMTRIGGERACTIONS; i++) {
+            triggerFunctionActionBlock[i].release();
+        }
+
+        queuePtr->eraseQueue();
+    }
+
+    if (clearMode & VARIABLEMEMORYTYPES) {
+        while (!globalVariables.empty()) {
+            delete globalVariables.back();
+            globalVariables.pop_back();
+        }
+    }
+
+    if (clearMode & ENVSETTINGSMEMORYTYPES) {
+        //set all environment settings to default values
+        broadCastStateChanges = true;
+        for (int i=0;i<NUMPORTS;i++) {
+            system->setPortUpdatesOn(i);
+        }
+    }
+
+
+
+}
+
--- a/behave.h	Sat Oct 10 22:37:17 2015 +0000
+++ b/behave.h	Fri Jan 15 22:13:23 2016 +0000
@@ -14,10 +14,6 @@
 
 #define MAXVARNAMESIZE 30 //The maximum number of characters of a variable name
 
-
-
-
-
 #ifdef MBEDHARDWARE
     #include "mbedInterface.h"
 #endif
@@ -25,6 +21,11 @@
     #include "fpgaInterface.h"
 #endif
 
+#define BLOCKMEMORYTYPES 1
+#define VARIABLEMEMORYTYPES 2
+#define ENVSETTINGSMEMORYTYPES 4
+
+
 /*
 #define NUMEVENTS 50
 #define NUMCONDITIONS 150
@@ -480,38 +481,28 @@
 class scriptStream {
 public:
     scriptStream(digitalPort* portVectorInput, int numPortsInput, eventQueue* queueInput, sSystem* system);
-    void parseBlock();
+    void parseBlock(); //Parses everything since the last semicolon was found
     void addLineToCurrentBlock(char* lineInput); // if the line did not end with a semicolon, add it to the current block
+
+private:
+
     int* findIntVariable(string nameInput); //used to retrieve the pointer to the designated variable if it exists
     int* findIntVariable(const char* nameInput); //used to retrieve the pointer to the designated variable if it exists
     int* findIntVariable(const char* nameInput, int start, int end); //used to retrieve the pointer to the designated variable if it exists
-
     bool createIntVariable(string nameInput); // creates a new interger variable
     action* evaluateAssignmentForAction(string expression); //parses a numerical assignment or operation (a = b - c)
     action* evaluateAssignmentForAction(const char* expression); //parses a numerical assignment or operation (a = b - c)
-
     bool evaluateConditions(string& expression, event* currentEvent); //parses a condition statement (a == b && c > d)
-    //condition* parseConditions(string& expression); //parses a condition statement (a == b && c > d)
-    //std::size_t findFirstOrOutsideParenth(string& expression);
-    //std::size_t findFirstAndOutsideParenth(string& expression);
-    //bool isOutsideParenth(string& expression,std::size_t foundItem);
-
     condition* parseConditions(const char* expression,int start, int end); //parses a condition statement (a == b && c > d)
     int findFirstOrOutsideParenth(const char* expression, int start, int end);
     int findFirstAndOutsideParenth(const char* expression, int start, int end);
     bool isOutsideParenth(const char* expression,int foundItem, int start, int end);
     bool isNum(const char* expression, int start, int end);
     bool areStringsSame(const char* str1, const char* str2, int start, int end);
-
     int getRandomParam(string expression);
     int getRandomParam(const char* expression,int start,int end);
-
-
     int findStringLoc(const char* refString,const char* findString,int start, int end);
-
-
-
-private:
+    void clearEnvironmentVariables(int mode);
 
     int currentTriggerPort;
     int currentTriggerDir;
--- a/mbedInterface/mbedInterface.cpp	Sat Oct 10 22:37:17 2015 +0000
+++ b/mbedInterface/mbedInterface.cpp	Fri Jan 15 22:13:23 2016 +0000
@@ -18,7 +18,7 @@
 extern bool changeToStandAlone;
 extern outputStream textDisplay;
 
-int externalIncrementMod = 30;
+int externalIncrementMod = 1;
 int externalIncrementCounter = 0;
 
 
@@ -118,11 +118,13 @@
 
     //The external clock reset signal pulse has come back down.  If the pulse was long
     //enough, then we condsider it a valid pulse (the pulses should be 1 ms long)
+    /*
+    textDisplay << uSec_SinceLastReset;
     if ((clockSlave)&&(uSec_SinceLastReset >= 700)) {
         uSec_SinceLastReset = 0;
         timeKeeper = 1; //It has been 1ms since the reset pulse went up
         textDisplay << timeKeeper << " Clock reset\r\n";
-    }
+    }*/
 }
 
 //------------------------------------------------------------------------
@@ -132,10 +134,9 @@
 //---------------------------------------------------------------------
 
 //translate pin numbers to hardware pins
-//PinName outPins[NUMPORTS] = {p11,p13,p15,p18,p21,p23,p25,p29,p20};
-PinName outPins[NUMPORTS] = {p18,p15,p13,p11,p29,p25,p23,p21,p20};
-PinName inPins[NUMPORTS] = {p12,p14,p16,p17,p22,p24,p26,p30,p7};
-
+PinName outPins[NUMOUTPORTS] = {p11,p13,p15,p18,p21,p23,p25,p29,p20,p6}; //Old board output pins
+//PinName outPins[NUMPORTS] = {p18,p15,p13,p11,p29,p25,p23,p21,p20}; //New board output pins
+PinName inPins[NUMINPORTS] = {p12,p14,p16,p17,p22,p24,p26,p30,p7};
 
 
 
@@ -145,11 +146,19 @@
 //This is the callback for the MBED timer
 extern "C" void TIMER0_IRQHandler (void) {
 
-    if (clockSlave) {
+    /*if (clockSlave) {
+
         //The function is called every 100 us
-        uSec_SinceLastClockInc = uSec_SinceLastClockInc+100;
-        uSec_SinceLastReset = uSec_SinceLastReset+100;
-    } else {
+        if((LPC_TIM0->IR & 0x01) == 0x01) {  // if MR0 interrupt, proceed
+
+            LPC_TIM0->IR |= 1 << 0;         // Clear MR0 interrupt flag
+            uSec_SinceLastClockInc = uSec_SinceLastClockInc+100;
+            uSec_SinceLastReset = uSec_SinceLastReset+100;
+
+        }
+
+
+    } else {*/
         //The function is called every 1 ms
         if((LPC_TIM0->IR & 0x01) == 0x01) {  // if MR0 interrupt, proceed
 
@@ -161,7 +170,7 @@
                 resetTimer = false;
             }
         }
-    }
+    //}
 
 }
 //-----------------------------------------------------------------------
@@ -193,7 +202,6 @@
     }
 
 
-
     sWav.reset();
 
 }
@@ -207,8 +215,11 @@
     //LPC_SC->PCLKSEL0 &= (3 << 3); //mask
     //LPC_SC->PCLKSEL0 |= (1 << 3); //sets it to 1*SystemCoreClock - table 42 (page 57 in user manual)
     LPC_SC->PCONP |=1<1;            //timer0 power on   
+
+
     LPC_TIM0->MR0 = 23980;        //1 msec
 
+
     //LPC_TIM0->PR  = (SystemCoreClock / 1000000); //microsecond steps
     //LPC_TIM0->MR0 = 1000;        //100 msec
     //LPC_TIM0->MR0  = (SystemCoreClock / 1000000); //microsecond steps
@@ -279,12 +290,13 @@
     uSec_SinceLastReset = 0;
 
 
-    /*
+
     if (clockSlave) {
         LPC_TIM0->TCR = 0x02;    // reset timer
         externalIncrementCounter = 0;
+
         immediateClockReset();
-    }*/
+    }
 
 }
 
@@ -363,37 +375,55 @@
 
 //-----------------------------------------------------
 MBEDDigitalOut::MBEDDigitalOut() {
-
+    pinExists = false;
 }
 
 void MBEDDigitalOut::init(int pin) {
-    outpin = new DigitalOut(outPins[pin]);
+    if (pin < NUMOUTPORTS) {
+        outpin = new DigitalOut(outPins[pin]);
+        pinExists = true;
+    }
 }
 
 int MBEDDigitalOut::read() {
-    return outpin->read();
+    if (pinExists) {
+        return outpin->read();
+    } else {
+        return 0;
+    }
 }
 
 void MBEDDigitalOut::write(int value) {
-    outpin->write(value);
+    if (pinExists) {
+
+        outpin->write(value);
+    }
 }
 //--------------------------------------------------------
 
 MBEDDigitalIn::MBEDDigitalIn() {
-
+    pinExists = false;
 }
 
 void MBEDDigitalIn::init(int pin) {
-    inpin = new DigitalIn(inPins[pin]);
-    inpin_interrupt = new InterruptIn(inPins[pin]);
-    inpin->mode(PullDown);
-    //Set up callbacks for the port interrupts
-    inpin_interrupt->rise(this, &MBEDDigitalIn::interrupt_up_callback);
-    inpin_interrupt->fall(this, &MBEDDigitalIn::interrupt_down_callback);
+
+    if (pin < NUMINPORTS) {
+        inpin = new DigitalIn(inPins[pin]);
+        inpin_interrupt = new InterruptIn(inPins[pin]);
+        inpin->mode(PullDown);
+        //Set up callbacks for the port interrupts
+        inpin_interrupt->rise(this, &MBEDDigitalIn::interrupt_up_callback);
+        inpin_interrupt->fall(this, &MBEDDigitalIn::interrupt_down_callback);
+        pinExists = true;
+    }
 }
 
 int MBEDDigitalIn::read() {
-    return inpin->read();
+    if (pinExists) {
+        return inpin->read();
+    } else {
+        return 0;
+    }
 }
 
 void MBEDDigitalIn::interrupt_up_callback() {
--- a/mbedInterface/mbedInterface.h	Sat Oct 10 22:37:17 2015 +0000
+++ b/mbedInterface/mbedInterface.h	Fri Jan 15 22:13:23 2016 +0000
@@ -15,7 +15,9 @@
 //#define MBED_RF
 
 
-#define NUMPORTS 9 //the number of ports available on this hardware
+#define NUMPORTS 10 //the number of ports available on this hardware
+#define NUMINPORTS 9
+#define NUMOUTPORTS 10
 
 #define NUMEVENTS 50
 #define NUMCONDITIONS 150
@@ -63,6 +65,7 @@
 
 private:
     DigitalOut *outpin;
+    bool pinExists;
 
 };
 
@@ -82,6 +85,7 @@
 private:
     DigitalIn *inpin;
     InterruptIn *inpin_interrupt;
+    bool pinExists;
 
 };