A scripting environment used to define precise output/input temporal relationships.
Dependencies: SMARTWAV mbed HelloWorld
Dependents: perturbRoom_legacy
Fork of HelloWorld by
behave.h
00001 #include "mbed.h" 00002 #include <stdint.h> 00003 #include <string.h> 00004 #include <string> 00005 #include <vector> 00006 #include <list> 00007 #include <deque> 00008 #include <queue> 00009 #include "soundControl.h" 00010 00011 00012 #define NUMEVENTS 50 00013 #define NUMCONDITIONS 150 00014 #define NUMINTCOMPARE 150 00015 #define NUMACTIONS 150 00016 #define NUMPORTMESSAGES 150 00017 #define NUMINTOPERATIONS 150 00018 #define NUMDISPLAYACTIONS 30 00019 00020 #define ARITHMATIC_CONDITION 0 00021 #define OR_CONDITION 1 00022 #define AND_CONDITION 2 00023 00024 #define NUMPORTS 8 00025 00026 #define INPUTCHARBUFFERSIZE 3072 00027 00028 class event; //we foreward declare this because of class interdependencies 00029 00030 //used in the digital port class to organize digital change events 00031 struct changeEvent { 00032 uint32_t timeStamp; 00033 bool triggered; 00034 }; 00035 00036 //The digitalPort object directly controls and keeps data about the port. Each port has 00037 //one digital out and one digital in. 00038 class digitalPort { 00039 public: 00040 digitalPort(DigitalOut* DOP, DigitalIn* DIP); 00041 void setDigitalOut(int outVal); 00042 //int getDigitalOut(); 00043 int getDigitalIn(); 00044 int getLastChangeState(); 00045 uint32_t getTimeSinceLastChange(); 00046 uint32_t lastChangeTime; 00047 uint32_t lastOutChangeTime; 00048 00049 void setTriggerUpEvent(event* eventInput); //attahces a routine to an upward change 00050 void setTriggerDownEvent(event* eventInput); //attahces a routine to a downward change 00051 void addStateChange(int newState, uint32_t timeStamp); 00052 00053 bool update(); //called from the main loop 00054 00055 int inState; 00056 int outState; 00057 00058 bool outStateChanged; 00059 00060 event* triggerUpEventPtr; 00061 event* triggerDownEventPtr; 00062 00063 private: 00064 00065 DigitalOut* outPin; 00066 DigitalIn* inPin; 00067 int lastInState; 00068 uint32_t lastChangeInterval; 00069 00070 changeEvent lastUpEvent; 00071 changeEvent lastDownEvent; 00072 }; 00073 00074 00075 //an intVariable contains an integer value and the name of that variable within the script 00076 class intVariable { 00077 00078 public: 00079 intVariable(); 00080 intVariable(string tagInput, int initialValue); 00081 void set(string tagInput, int initialValue); 00082 int value; 00083 string tag; 00084 bool isUsed; 00085 00086 }; 00087 00088 00089 //ACTION SECTION-- an 'action' is a command in the script. It can be a single command, 00090 //or a block containing a set of actions 00091 //------------------------------------------------------------------------------------ 00092 00093 //display actions are used to output text messages via the serial port. The user can display 00094 //either a static text string or the value of a single variable. 00095 class displayAction { 00096 00097 public: 00098 displayAction(); 00099 displayAction(int* variable, string varNameInput, Serial* pcPtrInput); 00100 displayAction(string text, Serial* pcPtrInput); 00101 void set(int* variable, string varNameInput, Serial* pcPtrInput); 00102 void set(string text, Serial* pcPtrInput); 00103 bool isUsed; 00104 void execute(); 00105 void release(); 00106 00107 private: 00108 int* dVariable; 00109 string dText; 00110 Serial* pcPtr; 00111 }; 00112 00113 //intOpertaion is an action that does addition or subtraction of integers and returns/stores the result 00114 //these operation are very limited so far (only + or - allowed, and only one operation per object, 00115 //for example a = b + b works but a = b + c + d does not. The output value can also be set to a random number. 00116 class intOperation { 00117 00118 public: 00119 intOperation(); 00120 intOperation(int randParam, const char* cmpString, int cmpValInput); 00121 intOperation(int randParam, const char* cmpString, int* cmpIntVarInput); 00122 intOperation(int* intVarInput, const char* cmpString, int cmpValInput); 00123 intOperation(int* intVarInput, const char* cmpString, int* cmpIntVarInput); 00124 intOperation(int* intVarInput, intOperation* operationInput); 00125 00126 ~intOperation(); 00127 00128 void set(int randParam, const char* cmpString, int cmpValInput); 00129 void set(int randParam, const char* cmpString, int* cmpIntVarInput); 00130 void set(int* intVarInput, const char* cmpString, int cmpValInput); 00131 void set(int* intVarInput, const char* cmpString, int* cmpIntVarInput); 00132 void set(int* intVarInput, intOperation* operationInput); 00133 void release(); 00134 bool isUsed; 00135 int execute(); 00136 00137 private: 00138 int randHigh; 00139 int* cmpVal; 00140 int* intVal; 00141 intOperation* opPtr; 00142 bool cmpValGlobal; 00143 int (intOperation::*executePtr)(); 00144 int addAndStore(); 00145 int subtractAndStore(); 00146 int add(); 00147 int subtract(); 00148 int equals(); 00149 00150 }; 00151 00152 //portMessage is an action to change a digital port. So far, You can only change the digital out (0 or 1) 00153 class portMessage { 00154 public: 00155 00156 portMessage(); 00157 //portMessage(digitalPort* portIn, int whichToSet, int value); //whichToSet: 1 DigitalOut; 2 State 00158 //void setMessage(digitalPort* portIn, int whichToSet, int value); //whichToSet: 1 DigitalOut; 2 State 00159 portMessage(int* portIn, int whichToSet, int value); //whichToSet: 00160 void setMessage(int* portIn, int whichToSet, int value); //whichToSet: 00161 00162 void execute(); 00163 void release(); 00164 bool isUsed; 00165 00166 private: 00167 int whichToSet; //hard coded port number 00168 int* port; //alternative variable port number 00169 int value; 00170 //digitalPort* port; 00171 00172 }; 00173 00174 //holder class for all possible actions. This include general system commands. 00175 class action { 00176 public: 00177 00178 action(); 00179 ~action(); 00180 action(intOperation* opInput); 00181 action(portMessage* messageInput); 00182 action(event* eventInput); 00183 //action(event* eventInput, uint32_t delay); 00184 action(displayAction* displayInput); 00185 action(soundControl* soundInput); 00186 action(int8_t sysCommandInput); //for general system commands 00187 00188 void set(intOperation* opInput); 00189 void set(portMessage* messageInput); 00190 void set(event* eventInput); 00191 //void set(event* eventInput, uint32_t delay); 00192 00193 void set(displayAction* displayInput); 00194 void set(soundControl* soundInput); 00195 void set(int8_t sysCommandInput); 00196 void execute(); 00197 void execute(uint32_t blockExecTime); 00198 void release(); 00199 bool isUsed; 00200 00201 private: 00202 intOperation* op; 00203 portMessage* message; 00204 event* eventToCreate; 00205 displayAction* displayActionPtr; 00206 soundControl* sound; 00207 //uint32_t eventDelay; 00208 int8_t sysCommand; 00209 char actionType; 00210 00211 }; 00212 //----------------------------------------------------- 00213 00214 //CONDITION SECTION-- a 'condition' is used in the beginning of a block (if-else blocks or while blocks) 00215 //If the condition is true, the block is exectuted during a callback 00216 //------------------------------------------------------------------------------------ 00217 00218 00219 //intCompare is a condition class that compares the state value of a port or 00220 //an integer variable to another integer variable or operation output 00221 class intCompare { 00222 00223 public: 00224 intCompare(); 00225 intCompare(digitalPort* portInput, const char* cmpString, int cmpValInput, int whichToUse); 00226 intCompare(digitalPort* portInput, const char* cmpString, int* cmpIntVarInput, int whichToUse); 00227 intCompare(int* intVarInput, const char* cmpString, int cmpValInput); 00228 intCompare(int* intVarInput, const char* cmpString, int* cmpIntVarInput); 00229 intCompare(int* intVarInput, const char* cmpString, intOperation* cmpIntOpInput); 00230 intCompare(digitalPort* portInput, const char* cmpString, intOperation* cmpIntOpInput, int whichToUse); 00231 00232 void set(digitalPort* portInput, const char* cmpString, int cmpValInput, int whichToUse); 00233 void set(digitalPort* portInput, const char* cmpString, int* cmpIntVarInput, int whichToUse); 00234 void set(int* intVarInput, const char* cmpString, int cmpValInput); 00235 void set(int* intVarInput, const char* cmpString, int* cmpIntVarInput); 00236 void set(int* intVarInput, const char* cmpString, intOperation* cmpIntOpInput); 00237 void set(digitalPort* portInput, const char* cmpString, intOperation* cmpIntOpInput, int whichToUse); 00238 00239 void release(); 00240 00241 ~intCompare(); 00242 bool isTrue(); 00243 bool isUsed; 00244 00245 private: 00246 digitalPort* port; 00247 int* portValPtr; 00248 int* cmpVal; 00249 int* intVal; 00250 intOperation* intOp; 00251 void setPointer(const char* cmpString); 00252 void setPointer_operation(const char* cmpString); 00253 bool (intCompare::*isTruePtr)(); 00254 bool cmpValGlobal; 00255 bool greaterThan(); 00256 bool greaterOrEqual(); 00257 bool lessThan(); 00258 bool lessOrEqual(); 00259 bool equal(); 00260 bool notEqual(); 00261 bool greaterThan_op(); 00262 bool greaterOrEqual_op(); 00263 bool lessThan_op(); 00264 bool lessOrEqual_op(); 00265 bool equal_op(); 00266 bool notEqual_op(); 00267 }; 00268 00269 00270 //holder class for all possible conditions (so far only intCompare) 00271 class condition { 00272 public: 00273 00274 condition(); 00275 condition(intCompare* compareInput); 00276 condition(condition* condition1, char condType, condition* condition2); 00277 ~condition(); 00278 void set(intCompare* compareInput); 00279 void set(condition* condition1, char condType, condition* condition2); 00280 bool isTrue(); 00281 bool isUsed; 00282 void release(); //called when the event is no longer being used; 00283 private: 00284 00285 //char conditionType; //1 for intCompare 00286 intCompare* intCmp; 00287 condition* conditionPtrs[2]; 00288 char conditionType; 00289 00290 00291 }; 00292 //-------------------------------------------- 00293 00294 00295 //queueItem connects a pre-defined event with an exectution time. 00296 //They are placed in the eventQueue 00297 struct queueItem { 00298 uint32_t timeToExecute; 00299 event* eventPtr; 00300 }; 00301 00302 00303 //Organizes events in a temporal queue. check() is called from the main loop. 00304 //If the execution time of the event has passed, then the event is exectuted. 00305 class eventQueue { 00306 public: 00307 eventQueue(digitalPort** portVectorInput, uint32_t* timeKeeperSlaveInput); 00308 void addEventToQueue(event* eventInput, uint32_t delay); 00309 void eraseQueue(); //clear all future events 00310 void check(void); 00311 00312 private: 00313 std::vector<queueItem> events; 00314 digitalPort** portVector; 00315 uint32_t* timeKeeperPtr; 00316 int queueSize; 00317 00318 }; 00319 00320 //An 'event' is a block of 'actions' that can be gated with a boolean 'condition' set. All 00321 //conditions in the set must be true for the block of actions to be executed. Right now, 00322 //there is no OR logic (||), only AND (&&). 00323 //The entire event is placed on the event queue to be executed at a given delay. 00324 //At that future time, the condition is checked and if true, the block of actions 00325 //is exectuted. Note: an 'action' can be another event (or even the parent event), allowing 00326 //nested 'if' and 'while' statements. 00327 class event { 00328 public: 00329 00330 event(); 00331 event(eventQueue* queueInput); 00332 ~event(); 00333 void setTimeLag(uint32_t timeLagInput); //the event will be exectuted at this time from now 00334 void setTimeLag(int* timeLagInput); //the event will be exectuted at this time from now 00335 void setWhileLoopPeriod(uint32_t period); 00336 void setWhileLoopPeriod(int* period); 00337 void addCondition(condition* conditionInput); //contains a set of conditions to check and a truth table 00338 bool isConditionTrue(void); //checks if the condition is true 00339 void addAction(action* actionInput); //called during script parsing, when the block is being defined 00340 void addToQueue(void); //places the event on the event queue with default time lag. When the time 00341 //lag has expired, the the block is executed 00342 void addToQueue(uint32_t delay); 00343 void execute(void); //Execute without checking the condition. Called only from the event queue 00344 void setNextElseEvent(event* eventInput); //allows for else event block 00345 uint32_t timeLag; //default time from now when the event will be executed (this is ignored once placed in event queue) 00346 int* timeLagVar; //exectution time lab defined by a variable 00347 eventQueue* queuePtr; 00348 void release(); //called when the event is no longer being used; 00349 00350 char blockType; //0 callback 00351 //1 if ... do block (with conditions) 00352 //2 do block (no conditions) 00353 //3 else if ... do block 00354 //4 else do (no conditions) 00355 //5 while ... do every ... block 00356 //6 else while ... do every ... block 00357 //7 then if ... do block 00358 //8 then do (no conditions) 00359 00360 uint32_t whileLoopPeriod; //if non-zero, the block is a while loop (executed at regular intervals) 00361 int* whileLoopPeriodVar; 00362 event* nextElseEventPtr; 00363 bool isUsed; 00364 bool timeLagIsConstant; 00365 bool whileLoopPeriodIsConstant; 00366 bool hasWhileLoop; 00367 00368 private: 00369 int numConditions; 00370 int numActions; 00371 condition* conditionToCheck; 00372 action* actionArray[20]; 00373 00374 //if statement (can be left empty, which is interpreted as 'true') 00375 //std::vector<condition*> conditionArray; 00376 //std::deque<action*> actionArray; 00377 00378 }; 00379 00380 //each functionItem help a poiter to an action, and the name of the function 00381 class functionItem { 00382 public: 00383 functionItem(action* actionInput, string tagInput); 00384 ~functionItem(); 00385 string tag; 00386 action* actionPtr; 00387 }; 00388 00389 class blockBuffer { 00390 00391 public: 00392 blockBuffer(); 00393 bool addLine(char* input, int numChars); 00394 string getNextLine(); 00395 int16_t linesAvailable(); 00396 bool empty(); 00397 void resetBuffer(); 00398 00399 private: 00400 //__attribute((section("AHBSRAM1"),aligned)) char charBuffer[INPUTCHARBUFFERSIZE]; 00401 char charBuffer[INPUTCHARBUFFERSIZE]; 00402 int16_t bufferWritePos; 00403 int16_t bufferReadPos; 00404 int16_t _linesAvailable; 00405 00406 }; 00407 00408 //Parser for the incoming text. The parser is called when a line terminates with a semicolon (;). 00409 //Only the final line in a callback block should have a semicolon. 00410 class scriptStream { 00411 public: 00412 scriptStream(Serial* serialInput, digitalPort** portVectorInput, int numPortsInput, eventQueue* queueInput); 00413 void parseBlock(); 00414 void addLineToCurrentBlock(char* lineInput); // if the line did not end with a semicolon, add it to the current block 00415 int* findIntVariable(string nameInput); //used to retrieve the pointer to the designated variable if it exists 00416 bool createIntVariable(string nameInput); // creates a new interger variable 00417 action* evaluateAssignmentForAction(string expression); //parses a numerical assignment or operation (a = b - c) 00418 bool evaluateConditions(string expression, event* currentEvent); //parses a condition statement (a == b && c > d) 00419 condition* parseConditions(string expression); //parses a condition statement (a == b && c > d) 00420 std::size_t findFirstOrOutsideParenth(string expression); 00421 std::size_t findFirstAndOutsideParenth(string expression); 00422 bool isOutsideParenth(string expression,std::size_t foundItem); 00423 00424 int getRandomParam(string expression); 00425 00426 00427 00428 private: 00429 00430 int currentTriggerPort; 00431 int currentTriggerDir; 00432 int currentPort; 00433 int currentFunction; 00434 00435 string tmpLine; 00436 vector<string> tokens; 00437 00438 bool lineError; 00439 int blockDepth; 00440 bool ifBlockInit; 00441 bool whileBlockInit; 00442 bool elseFlag; 00443 bool thenFlag; 00444 int currentDelay; 00445 event* tmpEvent; 00446 string tmpString; 00447 00448 vector<intVariable*> globalVariables; 00449 vector<event*> tmpEventPtrArray; 00450 vector<functionItem*> functionArray; //any blocks declared outsite callback blocks are stored here 00451 //list<string> currentBlock; 00452 blockBuffer currentBlock; 00453 digitalPort** portVector; 00454 00455 00456 int numPorts; 00457 Serial* pcPtr; 00458 eventQueue* queuePtr; 00459 00460 }; 00461 00462 00463 //Used to buffer output text. Used mainly for 'display' commands within the script, 00464 //and alloed the reset of the block to execute quickly instead. The text is then streamed out 00465 //slowly via serial (one character per main loop execution). outputStream is a simple circular 00466 //buffer that cannot be resized after initiation. 00467 class outputStream { 00468 00469 public: 00470 outputStream(int bufferSizeIn); 00471 ~outputStream(); 00472 void send(string outputString); 00473 char getNextChar(); 00474 bool unsentData; 00475 00476 private: 00477 int readHead; 00478 int writeHead; 00479 int totalWriteHead; 00480 int totalReadHead; 00481 int bufferSize; 00482 char tmpOut; 00483 char* outputBuffer; 00484 };
Generated on Sun Jul 17 2022 23:34:35 by 1.7.2