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

Dependencies:   SMARTWAV mbed HelloWorld

Dependents:   perturbRoom_legacy

Fork of HelloWorld by Simon Ford

Revision:
2:298679fff37c
Child:
4:34aca2142df9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/behave.h	Tue Jul 08 21:51:16 2014 +0000
@@ -0,0 +1,461 @@
+#include "mbed.h"
+#include <stdint.h>
+#include <string.h>
+#include <string>
+#include <vector>
+#include <list>
+#include <deque>
+#include <queue>
+#include "soundControl.h"
+
+
+#define NUMEVENTS 50
+#define NUMCONDITIONS 150
+#define NUMINTCOMPARE 150
+#define NUMACTIONS 150
+#define NUMPORTMESSAGES 150
+#define NUMINTOPERATIONS 150
+#define NUMDISPLAYACTIONS 30
+
+#define ARITHMATIC_CONDITION    0
+#define OR_CONDITION    1
+#define AND_CONDITION    2
+
+#define NUMPORTS 8
+
+
+class event; //we foreward declare this because of class interdependencies
+
+//used in the digital port class to organize digital change events
+struct changeEvent {
+    uint32_t timeStamp;
+    bool triggered;
+};
+
+//The digitalPort object directly controls and keeps data about the port. Each port has
+//one digital out and one digital in.
+class digitalPort {
+public:
+    digitalPort(DigitalOut* DOP, DigitalIn* DIP);
+    void setDigitalOut(int outVal);
+    //int  getDigitalOut();
+    int  getDigitalIn();
+    int getLastChangeState();
+    uint32_t getTimeSinceLastChange();
+    uint32_t lastChangeTime;
+    uint32_t lastOutChangeTime;
+    
+    void setTriggerUpEvent(event* eventInput); //attahces a routine to an upward change
+    void setTriggerDownEvent(event* eventInput); //attahces a routine to a downward change
+    void addStateChange(int newState, uint32_t timeStamp);
+    
+    bool update(); //called from the main loop
+    
+    int inState;
+    int outState;
+    
+    bool outStateChanged;
+   
+    event* triggerUpEventPtr;
+    event* triggerDownEventPtr;
+
+private:
+
+    DigitalOut* outPin;
+    DigitalIn*  inPin;
+    int lastInState;
+    uint32_t lastChangeInterval;
+    
+    changeEvent lastUpEvent;
+    changeEvent lastDownEvent; 
+};
+
+
+//an intVariable contains an integer value and the name of that variable within the script
+class intVariable {
+
+public:
+    intVariable();
+    intVariable(string tagInput, int initialValue); 
+    void set(string tagInput, int initialValue);
+    int value;
+    string tag;
+    bool isUsed;
+      
+};
+
+
+//ACTION SECTION-- an 'action' is a command in the script. It can be a single command, 
+//or a block containing a set of actions
+//------------------------------------------------------------------------------------
+
+//display actions are used to output text messages via the serial port.  The user can display 
+//either a static text string or the value of a single variable. 
+class displayAction {
+
+public:
+    displayAction();
+    displayAction(int* variable, string varNameInput, Serial* pcPtrInput);
+    displayAction(string text, Serial* pcPtrInput);
+    void set(int* variable, string varNameInput, Serial* pcPtrInput);
+    void set(string text, Serial* pcPtrInput);
+    bool isUsed;
+    void execute();
+    void release();
+
+private:
+    int* dVariable;
+    string dText;
+    Serial* pcPtr;
+};
+
+//intOpertaion is an action that does addition or subtraction of integers and returns/stores the result
+//these operation are very limited so far (only + or - allowed, and only one operation per object, 
+//for example a = b + b works but a = b + c + d does not. The output value can also be set to a random number.
+class intOperation {
+
+public:
+    intOperation();
+    intOperation(int randParam, const char* cmpString, int cmpValInput);
+    intOperation(int randParam, const char* cmpString, int* cmpIntVarInput);
+    intOperation(int* intVarInput, const char* cmpString, int cmpValInput);
+    intOperation(int* intVarInput, const char* cmpString, int* cmpIntVarInput);
+    intOperation(int* intVarInput, intOperation* operationInput);
+    
+    ~intOperation();
+    
+    void set(int randParam, const char* cmpString, int cmpValInput);
+    void set(int randParam, const char* cmpString, int* cmpIntVarInput);
+    void set(int* intVarInput, const char* cmpString, int cmpValInput);
+    void set(int* intVarInput, const char* cmpString, int* cmpIntVarInput);
+    void set(int* intVarInput, intOperation* operationInput);
+    void release();
+    bool isUsed;
+    int execute();
+    
+private:
+    int randHigh;
+    int* cmpVal;
+    int* intVal;
+    intOperation* opPtr;
+    bool cmpValGlobal;
+    int (intOperation::*executePtr)();
+    int addAndStore();
+    int subtractAndStore();
+    int add();
+    int subtract();
+    int equals();
+    
+};
+
+//portMessage is an action to change a digital port.  So far, You can only change the digital out (0 or 1) 
+class portMessage {
+public:
+
+    portMessage();
+    //portMessage(digitalPort* portIn, int whichToSet, int value); //whichToSet: 1 DigitalOut; 2 State
+    //void setMessage(digitalPort* portIn, int whichToSet, int value); //whichToSet: 1 DigitalOut; 2 State
+    portMessage(int* portIn, int whichToSet, int value); //whichToSet: 
+    void setMessage(int* portIn, int whichToSet, int value); //whichToSet: 
+
+    void execute();
+    void release();
+    bool isUsed;
+
+private:
+    int whichToSet; //hard coded port number
+    int* port; //alternative variable port number
+    int value;
+    //digitalPort* port;
+
+};
+
+//holder class for all possible actions. This include general system commands.
+class action {
+public:
+    
+    action();
+    ~action();
+    action(intOperation* opInput);
+    action(portMessage* messageInput);
+    action(event* eventInput);
+    //action(event* eventInput, uint32_t delay);
+    action(displayAction* displayInput);
+    action(soundControl* soundInput);
+    action(int8_t sysCommandInput); //for general system commands 
+       
+    void set(intOperation* opInput);
+    void set(portMessage* messageInput);
+    void set(event* eventInput);
+    //void set(event* eventInput, uint32_t delay);
+    
+    void set(displayAction* displayInput);
+    void set(soundControl* soundInput);
+    void set(int8_t sysCommandInput);
+    void execute();
+    void execute(uint32_t blockExecTime);
+    void release();
+    bool isUsed;
+        
+private:
+    intOperation* op;
+    portMessage* message;
+    event* eventToCreate;
+    displayAction* displayActionPtr;
+    soundControl* sound;
+    //uint32_t eventDelay;
+    int8_t sysCommand;   
+    char actionType;
+    
+};
+//-----------------------------------------------------
+
+//CONDITION SECTION-- a 'condition' is used in the beginning of a block (if-else blocks or while blocks)
+//If the condition is true, the block is exectuted during a callback 
+//------------------------------------------------------------------------------------
+
+
+//intCompare is a condition class that compares the state value of a port or 
+//an integer variable to another integer variable or operation output
+class intCompare {
+
+public:
+    intCompare();
+    intCompare(digitalPort* portInput, const char* cmpString, int cmpValInput, int whichToUse);
+    intCompare(digitalPort* portInput, const char* cmpString, int* cmpIntVarInput, int whichToUse);
+    intCompare(int* intVarInput, const char* cmpString, int cmpValInput);
+    intCompare(int* intVarInput, const char* cmpString, int* cmpIntVarInput);
+    intCompare(int* intVarInput, const char* cmpString, intOperation* cmpIntOpInput);
+    intCompare(digitalPort* portInput, const char* cmpString, intOperation* cmpIntOpInput, int whichToUse);
+    
+    void set(digitalPort* portInput, const char* cmpString, int cmpValInput, int whichToUse);
+    void set(digitalPort* portInput, const char* cmpString, int* cmpIntVarInput, int whichToUse);
+    void set(int* intVarInput, const char* cmpString, int cmpValInput);
+    void set(int* intVarInput, const char* cmpString, int* cmpIntVarInput);
+    void set(int* intVarInput, const char* cmpString, intOperation* cmpIntOpInput);
+    void set(digitalPort* portInput, const char* cmpString, intOperation* cmpIntOpInput, int whichToUse);
+    
+    void release();
+    
+    ~intCompare();
+    bool isTrue();
+    bool isUsed;
+    
+private:
+    digitalPort* port;
+    int* portValPtr;
+    int* cmpVal;
+    int* intVal;
+    intOperation* intOp;
+    void setPointer(const char* cmpString);
+    void setPointer_operation(const char* cmpString);
+    bool (intCompare::*isTruePtr)();
+    bool cmpValGlobal;
+    bool greaterThan();
+    bool greaterOrEqual();
+    bool lessThan();
+    bool lessOrEqual();
+    bool equal();
+    bool notEqual();
+    bool greaterThan_op();
+    bool greaterOrEqual_op();
+    bool lessThan_op();
+    bool lessOrEqual_op();
+    bool equal_op();
+    bool notEqual_op();
+};
+
+
+//holder class for all possible conditions (so far only intCompare)
+class condition {
+public:
+    
+    condition();
+    condition(intCompare* compareInput);
+    condition(condition* condition1, char condType, condition* condition2);
+    ~condition();
+    void set(intCompare* compareInput);
+    void set(condition* condition1, char condType, condition* condition2);
+    bool isTrue();
+    bool isUsed;
+    void release(); //called when the event is no longer being used;
+private:
+
+    //char conditionType; //1 for intCompare
+    intCompare* intCmp;
+    condition*  conditionPtrs[2];
+    char        conditionType;
+    
+       
+};
+//--------------------------------------------
+
+
+//queueItem connects a pre-defined event with an exectution time.
+//They are placed in the eventQueue
+struct queueItem {
+    uint32_t timeToExecute;
+    event* eventPtr;
+};
+
+
+//Organizes events in a temporal queue.  check() is called from the main loop. 
+//If the execution time of the event has passed, then the event is exectuted.
+class eventQueue {
+public:
+    eventQueue(digitalPort** portVectorInput, uint32_t* timeKeeperSlaveInput);
+    void addEventToQueue(event* eventInput, uint32_t delay);
+    void eraseQueue(); //clear all future events
+    void check(void);
+         
+private:
+    std::vector<queueItem> events;
+    digitalPort** portVector;
+    uint32_t* timeKeeperPtr;
+    int queueSize; 
+    
+};
+
+//An 'event' is a block of 'actions' that can be gated with a boolean 'condition' set. All 
+//conditions in the set must be true for the block of actions to be executed. Right now, 
+//there is no OR logic (||), only AND (&&).
+//The entire event is placed on the event queue to be executed at a given delay.  
+//At that future time, the condition is checked and if true, the block of actions
+//is exectuted. Note: an 'action' can be another event (or even the parent event), allowing
+//nested 'if' and 'while' statements.
+class event {
+public:
+    
+    event();
+    event(eventQueue* queueInput);
+    ~event();
+    void setTimeLag(uint32_t timeLagInput); //the event will be exectuted at this time from now
+    void setTimeLag(int* timeLagInput); //the event will be exectuted at this time from now
+    void setWhileLoopPeriod(uint32_t period);
+    void setWhileLoopPeriod(int* period);
+    void addCondition(condition* conditionInput); //contains a set of conditions to check and a truth table
+    bool isConditionTrue(void); //checks if the condition is true
+    void addAction(action* actionInput); //called during script parsing, when the block is being defined
+    void addToQueue(void); //places the event on the event queue with default time lag.  When the time
+    //lag has expired, the the block is executed
+    void addToQueue(uint32_t delay);
+    void execute(void); //Execute without checking the condition. Called only from the event queue 
+    void setNextElseEvent(event* eventInput); //allows for else event block
+    uint32_t timeLag; //default time from now when the event will be executed (this is ignored once placed in event queue)
+    int* timeLagVar; //exectution time lab defined by a variable
+    eventQueue* queuePtr;
+    void release(); //called when the event is no longer being used;
+    
+    char blockType;  //0 callback
+                    //1 if ... do block (with conditions)
+                    //2 do block (no conditions)
+                    //3 else if ... do block
+                    //4 else do (no conditions)
+                    //5 while ... do every ... block
+                    //6 else while ... do every ... block
+                    //7 then if ... do block
+                    //8 then do (no conditions)
+   
+    uint32_t whileLoopPeriod; //if non-zero, the block is a while loop (executed at regular intervals)
+    int* whileLoopPeriodVar;
+    event* nextElseEventPtr;
+    bool isUsed;
+    bool timeLagIsConstant;
+    bool whileLoopPeriodIsConstant;
+    bool hasWhileLoop;
+    
+private:
+    int numConditions;
+    int numActions;
+    condition* conditionToCheck; 
+    action* actionArray[20]; 
+    
+    //if statement (can be left empty, which is interpreted as 'true')
+    //std::vector<condition*> conditionArray;
+    //std::deque<action*> actionArray; 
+      
+};
+
+//each functionItem help a poiter to an action, and the name of the function
+class functionItem {
+public:
+    functionItem(action* actionInput, string tagInput);
+    ~functionItem();
+    string tag;
+    action* actionPtr;
+};
+
+//Parser for the incoming text.  The parser is called when a line terminates with a semicolon (;).
+//Only the final line in a callback block should have a semicolon.  
+class scriptStream {
+public:
+    scriptStream(Serial* serialInput, digitalPort** portVectorInput, int numPortsInput, eventQueue* queueInput);
+    void parseBlock();
+    void addLineToCurrentBlock(char* lineInput); // if the line did not end with a semicolon, add it to the current block
+    int* findIntVariable(string nameInput); //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)
+    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);
+    
+    int getRandomParam(string expression);
+    
+private:
+
+    int currentTriggerPort;
+    int currentTriggerDir;
+    int currentPort;
+    int currentFunction;
+    
+    string tmpLine; 
+    vector<string> tokens;
+    
+    bool lineError;
+    int blockDepth;
+    bool ifBlockInit;
+    bool whileBlockInit;
+    bool elseFlag;
+    bool thenFlag;
+    int currentDelay;
+    event* tmpEvent;
+    string tmpString;
+    
+    vector<intVariable*> globalVariables;
+    vector<event*> tmpEventPtrArray;
+    vector<functionItem*> functionArray; //any blocks declared outsite callback blocks are stored here
+    list<string> currentBlock;
+    digitalPort** portVector;
+    
+    
+    int numPorts;
+    Serial* pcPtr;
+    eventQueue* queuePtr;
+
+};
+
+
+//Used to buffer output text. Used mainly for 'display' commands within the script,
+//and alloed the reset of the block to execute quickly instead.  The text is then streamed out
+//slowly via serial (one character per main loop execution). outputStream is a simple circular 
+//buffer that cannot be resized after initiation.  
+class outputStream {
+
+public:
+    outputStream(int bufferSizeIn);
+    ~outputStream();
+    void send(string outputString);
+    char getNextChar();
+    bool unsentData;
+
+private:
+    int readHead;
+    int writeHead;
+    int totalWriteHead;
+    int totalReadHead;
+    int bufferSize;
+    char tmpOut;
+    char* outputBuffer;
+};
\ No newline at end of file