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
Parent:
0:fb6bbc10ffa0
Child:
3:ae33b7f5a7c1
diff -r 03c191369089 -r 298679fff37c main.cpp
--- a/main.cpp	Sun Jan 01 20:57:57 2012 +0000
+++ b/main.cpp	Tue Jul 08 21:51:16 2014 +0000
@@ -1,12 +1,479 @@
 #include "mbed.h"
+#include <stdint.h>
+#include "behave.h"
+#include <string.h>
+#include <sstream>
+#include "SMARTWAV.h"
+
+
+uint32_t timeKeeper; //the main clock (updated every ms) 
+bool resetTimer = false; //if true, the clock is reset 
+bool clockSlave = false; //slave mode
+bool changeToSlave = false;
+bool changeToStandAlone = false;
+
+//static char buf1[0x2000] __attribute__((section("AHBSRAM0")));
+__attribute((section("AHBSRAM0"),aligned)) outputStream textDisplay(512);
+__attribute((section("AHBSRAM0"),aligned)) char buffer[128];
+
+
+__attribute((section("AHBSRAM1"),aligned)) event eventBlock[NUMEVENTS];
+
+__attribute((section("AHBSRAM1"),aligned)) condition conditionBlock[NUMCONDITIONS];
+
+__attribute((section("AHBSRAM1"),aligned)) intCompare intCompareBlock[NUMINTCOMPARE];
+
+__attribute((section("AHBSRAM0"),aligned)) action actionBlock[NUMACTIONS];
+
+__attribute((section("AHBSRAM0"),aligned)) portMessage portMessageBlock[NUMPORTMESSAGES];
+
+//__attribute((section("AHBSRAM1"),aligned)) intVariable intVariableBlock[10];
+
+__attribute((section("AHBSRAM0"),aligned)) intOperation intOperationBlock[NUMINTOPERATIONS];
+
+__attribute((section("AHBSRAM0"),aligned)) displayAction displayActionBlock[NUMDISPLAYACTIONS];
+
+
+
+Ticker clockBroadCast; //timer used when sending out timestamps on a GPIO
+uint32_t currentBroadcastTime;
+int currentBroadcastBit = 0;
+bool broadcastHigh = false;
+
+int currentDIOstate[2] = {0,0}; //the first number is a bit-wise representaion of the digital inputs, the 2nd is for the outputs 
+bool digitalInChanged = false;
+bool digitalOutChanged = false;
+bool broadCastStateChanges = true;
+bool textStreaming = true;
+uint32_t changeTime;
+
+LocalFileSystem local("local");  
+
+digitalPort* portVector[NUMPORTS+1]; //create the digital ports
+
+float brightness = 0.0;
+
+//Define the digial ports
+
+//Pins for clock syncing
+InterruptIn clockResetInt(p5);
+DigitalOut clockOutSync(p6);
+DigitalOut clockOutSignal(p7);
+InterruptIn clockExternalIncrement(p8);
+
+
+//Pins for digital ports.  Each port has 1 out and 1 in
+//DigitalOut out1(LED1); //route to LED for debugging
+DigitalOut out1(p11);
+DigitalIn in1(p12);
+InterruptIn int1(p12);
+__attribute((section("AHBSRAM0"),aligned)) digitalPort port1(&out1, &in1);
+
+DigitalOut out2(p13);
+DigitalIn in2(p14);
+InterruptIn int2(p14);
+__attribute((section("AHBSRAM0"),aligned)) digitalPort port2(&out2, &in2);
+
+
+DigitalOut out3(p15);
+DigitalIn in3(p16);
+InterruptIn int3(p16);
+__attribute((section("AHBSRAM0"),aligned)) digitalPort port3(&out3, &in3);
+
+DigitalOut out4(p18);
+DigitalIn in4(p17);
+InterruptIn int4(p17);
+__attribute((section("AHBSRAM0"),aligned)) digitalPort port4(&out4, &in4);
+
+DigitalOut out5(p21);
+DigitalIn in5(p22);
+InterruptIn int5(p22);
+__attribute((section("AHBSRAM0"),aligned)) digitalPort port5(&out5, &in5);
+
+DigitalOut out6(p23);
+DigitalIn in6(p24);
+InterruptIn int6(p24);
+__attribute((section("AHBSRAM0"),aligned)) digitalPort port6(&out6, &in6);
+
+DigitalOut out7(p25);
+DigitalIn in7(p26);
+InterruptIn int7(p26);
+__attribute((section("AHBSRAM0"),aligned)) digitalPort port7(&out7, &in7);
+
+DigitalOut out8(p29);
+DigitalIn in8(p30);
+InterruptIn int8(p30);
+__attribute((section("AHBSRAM0"),aligned)) digitalPort port8(&out8, &in8);
+//Serial communication
+Serial pc(USBTX, USBRX); // tx, rx
+
+//Main event queue
+eventQueue mainQueue(portVector, &timeKeeper);
+
+//The script parser 
+scriptStream parser(&pc, portVector, NUMPORTS, &mainQueue);
+
+//The sound output uses a SmartWav device and their simple serial library
+SMARTWAV sWav(p9,p10,p19);    //(TX,RX,Reset);
+
+//Erases the input buffer for serial input
+void eraseBuffer(char* buffer,int numToErase) {
+    for (int i = 0; i < numToErase; i++) {
+        buffer[i] = NULL;
+    }
+}
+
 
-DigitalOut myled(LED1);
+//Called by clockBroadCast timer to output a 32-bit timestamp.  When the timestmap has been
+//sent, the function is detached from the timer.
+void broadcastNextBit() {
+       
+    if (currentBroadcastBit < 32) {
+        broadcastHigh = !broadcastHigh; //flip the sync signal
+        if (broadcastHigh) {
+            clockOutSync = 1;
+            clockOutSignal = (currentBroadcastTime & ( 1 << currentBroadcastBit)) >> currentBroadcastBit;
+            
+        } else {
+            clockOutSync = 0;
+            clockOutSignal = 0;
+            currentBroadcastBit++;
+        }
+    }
+}
+
+
+//intiatiation of timer2 (specific to the LPC17xx chip). This is used in 
+//standalone mode to increment the clock every ms.
+//we use lower-lever code here to get better control over the timer if we reset it
+void timer0_init(void)
+{
+    //LPC_SC->PCLKSEL1 &= (3 << 12); //mask
+    //LPC_SC->PCLKSEL1 |= (1 << 12); //sets it to 1*SystemCoreClock - table 42 (page 57 in user manual)
+    
+    //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
+    LPC_TIM0->MCR = 3;              //interrupt and reset control
+                                    //3 = Interrupt & reset timer0 on match
+                                    //1 = Interrupt only, no reset of timer0
+    NVIC_EnableIRQ(TIMER0_IRQn);    //enable timer0 interrupt
+    LPC_TIM0->TCR = 1;              //enable Timer0
+    
+    
+    /*
+    LPC_SC->PCONP |= (0x1<<22);     // turn on power for timer 2
+    LPC_TIM2->TCR = 0x02;           // reset timer
+    LPC_TIM2->PR  = (SystemCoreClock / 1000000); //microsecond steps
+    LPC_TIM2->MR0 = 1000;            // 1000 microsecond interval interrupts
+    LPC_TIM2->IR  = 0x3f;           // reset all interrrupts
+    LPC_TIM2->MCR = 0x03;           // reset timer on match and generate interrupt (MR0)
+    LPC_TIM2->TCR = 0x01;           // start timer
+    
+    NVIC_EnableIRQ(TIMER2_IRQn); // Enable the interrupt
+    */
+    //pc.printf("Done timer_init\n\r");
+}
+
+//This is the callback for timer2
+extern "C" void TIMER0_IRQHandler (void) {
+
+    if((LPC_TIM0->IR & 0x01) == 0x01) {  // if MR0 interrupt, proceed
+    
+        LPC_TIM0->IR |= 1 << 0;         // Clear MR0 interrupt flag
+        timeKeeper++;
+        
+        if (resetTimer) {
+            timeKeeper = 0;
+            resetTimer = false; 
+        }
+       
+        if (currentBroadcastBit > 31) {
+            clockBroadCast.detach();
+            currentBroadcastBit = 0;
+        }
+    
+        //Every second, we broadcast out the current time 
+        if ((timeKeeper % 1000) == 0) {
+            currentBroadcastTime = timeKeeper;
+            clockOutSync = 1;
+        
+            currentBroadcastBit = 0;
+     
+            clockOutSignal = (currentBroadcastTime & ( 1 << currentBroadcastBit)) >> currentBroadcastBit;
+            broadcastHigh = true;
+            clockBroadCast.attach_us(&broadcastNextBit, 1000);
+        }               
+    }
+}
+
+
+//In slave mode, the clock is updated with an external trigger every ms.  No need for
+//100us resolution.
+void callback_clockExternalIncrement(void) {
+    
+    timeKeeper++;
+       
+    if (resetTimer) {
+        timeKeeper = 0;
+        resetTimer = false; 
+    }
+      
+    if (currentBroadcastBit > 31) {
+        clockBroadCast.detach();
+        currentBroadcastBit = 0;
+    }
+    
+    //Every second, we broadcast out the current time 
+    if ((timeKeeper % 1000) == 0) {
+        currentBroadcastTime = timeKeeper;
+        clockOutSync = 1;
+        
+        currentBroadcastBit = 0;
+     
+        clockOutSignal = (currentBroadcastTime & ( 1 << currentBroadcastBit)) >> currentBroadcastBit;
+        broadcastHigh = true;
+        clockBroadCast.attach_us(&broadcastNextBit, 1000);
+    }
+}
+
+//Every digital port's in pin has a hardware interrupt.  We use a callback stub for each port
+//that routes the int_callback.
+void int_callback(int portNum, int direction) {
+    portVector[portNum]->addStateChange(direction, timeKeeper);   
+}
+
+//Callback stubs
+void callback_port1_rise(void) { int_callback(1, 1); }
+void callback_port1_fall(void) { int_callback(1, 0); }
+void callback_port2_rise(void) { int_callback(2, 1); }
+void callback_port2_fall(void) { int_callback(2, 0); }
+void callback_port3_rise(void) { int_callback(3, 1); }
+void callback_port3_fall(void) { int_callback(3, 0); }
+void callback_port4_rise(void) { int_callback(4, 1); }
+void callback_port4_fall(void) { int_callback(4, 0); }
+void callback_port5_rise(void) { int_callback(5, 1); }
+void callback_port5_fall(void) { int_callback(5, 0); }
+void callback_port6_rise(void) { int_callback(6, 1); }
+void callback_port6_fall(void) { int_callback(6, 0); }
+void callback_port7_rise(void) { int_callback(7, 1); }
+void callback_port7_fall(void) { int_callback(7, 0); }
+void callback_port8_rise(void) { int_callback(8, 1); }
+void callback_port8_fall(void) { int_callback(8, 0); }
+
+//This function is attached to an interrupt pin for external clock reset
+void callback_clockReset(void) {
+    if (timeKeeper > 100) {
+        LPC_TIM2->TCR = 0x02;    // reset timer
+        timeKeeper = 0;
+        pc.printf("%d Clock reset\r\n", timeKeeper);
+    }      
+}
+
 
 int main() {
+    timeKeeper = 0; //set main clock to 0;
+    sWav.reset(); 
+    pc.baud(115200);
+    //pc.baud(9600);
+   
+    for (int i = 0; i < 9; i++) {
+        portVector[i] = NULL;
+    }
+    //We keep portVector 1-based to eliminate confusion
+    portVector[1] = &port1;
+    portVector[2] = &port2;
+    portVector[3] = &port3;
+    portVector[4] = &port4;
+    portVector[5] = &port5;
+    portVector[6] = &port6;
+    portVector[7] = &port7;
+    portVector[8] = &port8;
+   
+    //Callback to update the main clock 
+    //timeTick1.attach_us(&incrementTime, 100);
+    
+    timer0_init();
+    
+    
+    //Set up callbacks for the port interrupts   
+    int1.rise(&callback_port1_rise);
+    int1.fall(&callback_port1_fall);
+    int2.rise(&callback_port2_rise);
+    int2.fall(&callback_port2_fall);
+    int3.rise(&callback_port3_rise);
+    int3.fall(&callback_port3_fall);
+    int4.rise(&callback_port4_rise);
+    int4.fall(&callback_port4_fall);
+    int5.rise(&callback_port5_rise);
+    int5.fall(&callback_port5_fall);
+    int6.rise(&callback_port6_rise);
+    int6.fall(&callback_port6_fall);
+    int7.rise(&callback_port7_rise);
+    int7.fall(&callback_port7_fall);
+    int8.rise(&callback_port8_rise);
+    int8.fall(&callback_port8_fall);
+    
+    clockResetInt.rise(&callback_clockReset);
+    clockResetInt.mode(PullDown);
+    
+    clockExternalIncrement.mode(PullDown);
+      
+    //The inputs are set for pull-up mode (might need to change this)
+    in1.mode(PullDown);
+    in2.mode(PullDown);
+    in3.mode(PullDown);
+    in4.mode(PullDown);
+    in5.mode(PullDown);
+    in6.mode(PullDown);
+    in7.mode(PullDown);
+    in8.mode(PullDown);
+     
+    //Set up input buffer for the serial port
+    //char buffer[128];
+    int bufferPos = 0;
+    eraseBuffer(buffer,128);
+    
+    ostringstream timeConvert;   // stream used for the conversion
+    ostringstream stateConvert; 
+    char junkChar;
+    int tmpChar;
+    
+    while (pc.readable()) {
+        junkChar = pc.getc();
+    }   
+         
+    FILE *fp = fopen("/local/STARTUP.TXT", "r");
+    if (fp != NULL) {
+        pc.printf("Executing startup script...\r\n");  
+        do { 
+            tmpChar = fgetc(fp);
+            if ((tmpChar >= 32) && (tmpChar <= 126)) {
+                buffer[bufferPos] = tmpChar;
+                bufferPos++;
+            }
+            if ((tmpChar == 13) || (tmpChar == 10)) { //carrriage return
+                parser.addLineToCurrentBlock(buffer);                          
+                bufferPos = 0;
+                eraseBuffer(buffer,128);             
+            }            
+            //pc.putc(tmpChar);
+        } while (tmpChar != EOF);
+        
+        buffer[bufferPos] = 59;
+        parser.addLineToCurrentBlock(buffer);
+        eraseBuffer(buffer,128);  
+        fclose(fp);
+    } else {
+        pc.printf("No startup script found.\r\n"); 
+    }
+    
+    //main loop
     while(1) {
-        myled = 1;
-        wait(0.2);
-        myled = 0;
-        wait(0.2);
+       //check the main event queue to see if anything needs to be done
+       mainQueue.check();
+       
+       //check if anything has been written to the serial input
+       if (pc.readable()) {
+                
+            buffer[bufferPos] = pc.getc();
+            bufferPos++;
+            
+            //'Return' key pressed
+            if ((buffer[bufferPos-1] == 13) || (buffer[bufferPos-1] == 10)) {
+                //pc.printf("\r\n");
+                buffer[bufferPos-1] = '\0';
+                parser.addLineToCurrentBlock(buffer);              
+                bufferPos = 0;
+                eraseBuffer(buffer,128);
+                
+            } else {
+                //pc.putc(buffer[bufferPos-1]);
+                //Backspace was pressed
+                if ((buffer[bufferPos-1] == 8) && (bufferPos > 0)) {                              
+                    bufferPos = bufferPos-2;                   
+                } 
+            }
+       }
+       
+      // __disable_irq();
+       
+       
+       //Check all the digital ports to see if anything has changed. In the update routine, the port's
+       //script callbacks are called if the port was triggered 
+       digitalInChanged = false;
+       digitalOutChanged = false;
+       changeTime = timeKeeper;
+       for (int i = 0; i < NUMPORTS; i++) {
+             if (portVector[i+1]->update()) {
+                digitalInChanged = true;
+                changeTime = min(changeTime,portVector[i+1]->lastChangeTime);
+                
+                //The input state of all the ports in condensed into one number (each bit contains the info)
+                if (portVector[i+1]->getLastChangeState() == 1) {
+                    currentDIOstate[0] = currentDIOstate[0] | (1 << i);
+                } else {
+                    currentDIOstate[0] = currentDIOstate[0] & (255^(1 << i));
+                }
+             }
+             if (portVector[i+1]->outStateChanged) {
+                digitalOutChanged = true;
+                changeTime = min(changeTime,portVector[i+1]->lastOutChangeTime);
+                //The out state of all the ports in condensed into one number (each bit contains the info)
+                if (portVector[i+1]->outState == 1) {
+                    currentDIOstate[1] = currentDIOstate[1] | (1 << i);
+                } else {
+                    currentDIOstate[1] = currentDIOstate[1] & (255^(1 << i));
+                }
+                portVector[i+1]->outStateChanged = false;
+             }
+       }
+           
+       //If anything changed, we write the new values to the serial port (this can be turned off 
+       //with broadCastStateChanges)
+       if ( (digitalInChanged||digitalOutChanged) && broadCastStateChanges) {
+            timeConvert << changeTime; //broadcast the earliest timestamp when a change occured
+            //stateConvert << currentDIOstate[0] << " " << currentDIOstate[1];
+            stateConvert << currentDIOstate[0] << " " << currentDIOstate[1] << "       ";
+            textDisplay.send(timeConvert.str() + " " + stateConvert.str() + "\r\n");
+            timeConvert.clear();
+            timeConvert.seekp(0);
+            stateConvert.clear();
+            stateConvert.seekp(0);
+            digitalInChanged = false;
+            digitalOutChanged = false;
+       }
+       
+       //We use a buffer to send text via the serial port.  For every loop
+       //in the main loop, we send one character if there is enything to send.
+       //This way, outputting text to serial does not hold up other time-sensitive
+       //things in the event queue
+       if ((textDisplay.unsentData) && (textStreaming)) {
+            pc.printf("%c", textDisplay.getNextChar());
+       }
+       
+       //Here is how we toggle between standalone and slave mode for the clock updating.
+       if (changeToSlave) {
+            //timeTick1.detach();
+            NVIC_DisableIRQ(TIMER2_IRQn); // Disable the interrupt
+            clockExternalIncrement.rise(&callback_clockExternalIncrement);
+            clockSlave = true;
+            changeToSlave = false;
+            changeToStandAlone = false;
+       } else if (changeToStandAlone) {
+            //timeTick1.attach_us(&incrementTime, 100);
+            timer0_init();         
+            clockExternalIncrement.rise(NULL); //remove the callback to the external interrupt
+            clockSlave = false;
+            changeToSlave = false;
+            changeToStandAlone = false;
+       }
+                    
+       //__enable_irq();
+       
     }
 }