
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
Revision 4:abee20c0bf2a, committed 2016-01-15
- 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
--- 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; };