perturh room legacy

Dependencies:   SMARTWAV USBDevice mbed stateScript

Fork of stateScript by Mattias Karlsson

behave.h

Committer:
alustig3
Date:
2015-05-16
Revision:
5:e62cd80aa22f
Parent:
4:34aca2142df9

File content as of revision 5:e62cd80aa22f:

#include "mbed.h"
#include <stdint.h>
#include <string.h>
#include <string>
#include <vector>
#include <list>
#include <deque>
#include <queue>
#include "soundControl.h"
#include "USBSerial.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 5

extern "C" void mbed_reset();//MAX and ANDY
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);
    digitalPort(DigitalOut* DOP);
    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, USBSerial* pcPtrInput);
    displayAction(string text, USBSerial* pcPtrInput);
    void set(int* variable, string varNameInput, USBSerial* pcPtrInput);
    void set(string text, USBSerial* pcPtrInput);
    bool isUsed;
    void execute();
    void release();

private:
    int* dVariable;
    string dText;
    USBSerial* 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(USBSerial* 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;
    USBSerial* 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;
};