A scripting environment used to define precise output/input temporal relationships.

Dependencies:   SMARTWAV mbed HelloWorld

Dependents:   perturbRoom_legacy

Fork of HelloWorld by Simon Ford

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers behave.h Source File

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 };