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 main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include <stdint.h>
00003 #include "behave.h"
00004 #include <string.h>
00005 #include <sstream>
00006 #include "SMARTWAV.h"
00007 
00008 
00009 uint32_t timeKeeper; //the main clock (updated every ms) 
00010 bool resetTimer = false; //if true, the clock is reset 
00011 bool clockSlave = false; //slave mode
00012 bool changeToSlave = false;
00013 bool changeToStandAlone = false;
00014 
00015 //static char buf1[0x2000] __attribute__((section("AHBSRAM0")));
00016 __attribute((section("AHBSRAM0"),aligned)) outputStream textDisplay(512);
00017 __attribute((section("AHBSRAM0"),aligned)) char buffer[256];
00018 
00019 
00020 __attribute((section("AHBSRAM1"),aligned)) event eventBlock[NUMEVENTS];
00021 
00022 __attribute((section("AHBSRAM1"),aligned)) condition conditionBlock[NUMCONDITIONS];
00023 
00024 __attribute((section("AHBSRAM1"),aligned)) intCompare intCompareBlock[NUMINTCOMPARE];
00025 
00026 __attribute((section("AHBSRAM0"),aligned)) action actionBlock[NUMACTIONS];
00027 
00028 __attribute((section("AHBSRAM0"),aligned)) portMessage portMessageBlock[NUMPORTMESSAGES];
00029 
00030 //__attribute((section("AHBSRAM1"),aligned)) intVariable intVariableBlock[10];
00031 
00032 __attribute((section("AHBSRAM0"),aligned)) intOperation intOperationBlock[NUMINTOPERATIONS];
00033 
00034 __attribute((section("AHBSRAM0"),aligned)) displayAction displayActionBlock[NUMDISPLAYACTIONS];
00035 
00036 
00037 
00038 Ticker clockBroadCast; //timer used when sending out timestamps on a GPIO
00039 uint32_t currentBroadcastTime;
00040 int currentBroadcastBit = 0;
00041 bool broadcastHigh = false;
00042 
00043 int currentDIOstate[2] = {0,0}; //the first number is a bit-wise representaion of the digital inputs, the 2nd is for the outputs 
00044 bool digitalInChanged = false;
00045 bool digitalOutChanged = false;
00046 bool broadCastStateChanges = true;
00047 bool textStreaming = true;
00048 uint32_t changeTime;
00049 
00050 LocalFileSystem local("local");  
00051 
00052 digitalPort* portVector[NUMPORTS+1]; //create the digital ports
00053 
00054 float brightness = 0.0;
00055 
00056 //Define the digial ports
00057 
00058 //Pins for clock syncing
00059 InterruptIn clockResetInt(p5);
00060 DigitalOut clockOutSync(p6);
00061 DigitalOut clockOutSignal(p7);
00062 InterruptIn clockExternalIncrement(p8);
00063 
00064 //Camera trigger signal
00065 //DigitalOut camera30Hz(p27);
00066 
00067 
00068 //Pins for digital ports.  Each port has 1 out and 1 in
00069 //DigitalOut out1(LED1); //route to LED for debugging
00070 DigitalOut out1(p11);
00071 DigitalIn in1(p12);
00072 InterruptIn int1(p12);
00073 __attribute((section("AHBSRAM0"),aligned)) digitalPort port1(&out1, &in1);
00074 
00075 DigitalOut out2(p13);
00076 DigitalIn in2(p14);
00077 InterruptIn int2(p14);
00078 __attribute((section("AHBSRAM0"),aligned)) digitalPort port2(&out2, &in2);
00079 
00080 
00081 DigitalOut out3(p15);
00082 DigitalIn in3(p16);
00083 InterruptIn int3(p16);
00084 __attribute((section("AHBSRAM0"),aligned)) digitalPort port3(&out3, &in3);
00085 
00086 DigitalOut out4(p18);
00087 DigitalIn in4(p17);
00088 InterruptIn int4(p17);
00089 __attribute((section("AHBSRAM0"),aligned)) digitalPort port4(&out4, &in4);
00090 
00091 DigitalOut out5(p21);
00092 DigitalIn in5(p22);
00093 InterruptIn int5(p22);
00094 __attribute((section("AHBSRAM0"),aligned)) digitalPort port5(&out5, &in5);
00095 
00096 DigitalOut out6(p23);
00097 DigitalIn in6(p24);
00098 InterruptIn int6(p24);
00099 __attribute((section("AHBSRAM0"),aligned)) digitalPort port6(&out6, &in6);
00100 
00101 DigitalOut out7(p25);
00102 DigitalIn in7(p26);
00103 InterruptIn int7(p26);
00104 __attribute((section("AHBSRAM0"),aligned)) digitalPort port7(&out7, &in7);
00105 
00106 DigitalOut out8(p29);
00107 DigitalIn in8(p30);
00108 InterruptIn int8(p30);
00109 __attribute((section("AHBSRAM0"),aligned)) digitalPort port8(&out8, &in8);
00110 //Serial communication
00111 Serial pc(USBTX, USBRX); // tx, rx
00112 
00113 //Main event queue
00114 eventQueue mainQueue(portVector, &timeKeeper);
00115 
00116 //The script parser 
00117 scriptStream parser(&pc, portVector, NUMPORTS, &mainQueue);
00118 
00119 //The sound output uses a SmartWav device and their simple serial library
00120 SMARTWAV sWav(p9,p10,p19);    //(TX,RX,Reset);
00121 
00122 //Erases the input buffer for serial input
00123 void eraseBuffer(char* buffer,int numToErase) {
00124     for (int i = 0; i < numToErase; i++) {
00125         buffer[i] = NULL;
00126     }
00127 }
00128 
00129 
00130 //Called by clockBroadCast timer to output a 32-bit timestamp.  When the timestmap has been
00131 //sent, the function is detached from the timer.
00132 void broadcastNextBit() {
00133        
00134     if (currentBroadcastBit < 32) {
00135         broadcastHigh = !broadcastHigh; //flip the sync signal
00136         if (broadcastHigh) {
00137             clockOutSync = 1;
00138             clockOutSignal = (currentBroadcastTime & ( 1 << currentBroadcastBit)) >> currentBroadcastBit;
00139             
00140         } else {
00141             clockOutSync = 0;
00142             clockOutSignal = 0;
00143             currentBroadcastBit++;
00144         }
00145     }
00146 }
00147 
00148 
00149 //intiatiation of timer2 (specific to the LPC17xx chip). This is used in 
00150 //standalone mode to increment the clock every ms.
00151 //we use lower-lever code here to get better control over the timer if we reset it
00152 void timer0_init(void)
00153 {
00154     //LPC_SC->PCLKSEL1 &= (3 << 12); //mask
00155     //LPC_SC->PCLKSEL1 |= (1 << 12); //sets it to 1*SystemCoreClock - table 42 (page 57 in user manual)
00156     
00157     //LPC_SC->PCLKSEL0 &= (3 << 3); //mask
00158     //LPC_SC->PCLKSEL0 |= (1 << 3); //sets it to 1*SystemCoreClock - table 42 (page 57 in user manual)
00159     LPC_SC->PCONP |=1<1;            //timer0 power on
00160     LPC_TIM0->MR0 = 23980;        //1 msec
00161     //LPC_TIM0->PR  = (SystemCoreClock / 1000000); //microsecond steps
00162     //LPC_TIM0->MR0 = 1000;        //100 msec
00163     //LPC_TIM0->MR0  = (SystemCoreClock / 1000000); //microsecond steps
00164     LPC_TIM0->MCR = 3;              //interrupt and reset control
00165                                     //3 = Interrupt & reset timer0 on match
00166                                     //1 = Interrupt only, no reset of timer0
00167     NVIC_EnableIRQ(TIMER0_IRQn);    //enable timer0 interrupt
00168     LPC_TIM0->TCR = 1;              //enable Timer0
00169     
00170     
00171     /*
00172     LPC_SC->PCONP |= (0x1<<22);     // turn on power for timer 2
00173     LPC_TIM2->TCR = 0x02;           // reset timer
00174     LPC_TIM2->PR  = (SystemCoreClock / 1000000); //microsecond steps
00175     LPC_TIM2->MR0 = 1000;            // 1000 microsecond interval interrupts
00176     LPC_TIM2->IR  = 0x3f;           // reset all interrrupts
00177     LPC_TIM2->MCR = 0x03;           // reset timer on match and generate interrupt (MR0)
00178     LPC_TIM2->TCR = 0x01;           // start timer
00179     
00180     NVIC_EnableIRQ(TIMER2_IRQn); // Enable the interrupt
00181     */
00182     //pc.printf("Done timer_init\n\r");
00183 }
00184 
00185 //This is the callback for timer2
00186 extern "C" void TIMER0_IRQHandler (void) {
00187 
00188     if((LPC_TIM0->IR & 0x01) == 0x01) {  // if MR0 interrupt, proceed
00189     
00190         LPC_TIM0->IR |= 1 << 0;         // Clear MR0 interrupt flag
00191         timeKeeper++;
00192         
00193         if (resetTimer) {
00194             timeKeeper = 0;
00195             resetTimer = false; 
00196         }
00197        
00198         if (currentBroadcastBit > 31) {
00199             clockBroadCast.detach();
00200             currentBroadcastBit = 0;
00201         }
00202     
00203                 
00204         //Every second, we broadcast out the current time 
00205         if ((timeKeeper % 1000) == 0) {
00206             currentBroadcastTime = timeKeeper;
00207             clockOutSync = 1;
00208         
00209             currentBroadcastBit = 0;
00210      
00211             clockOutSignal = (currentBroadcastTime & ( 1 << currentBroadcastBit)) >> currentBroadcastBit;
00212             broadcastHigh = true;
00213             clockBroadCast.attach_us(&broadcastNextBit, 1000);
00214         }               
00215     }
00216 }
00217 
00218 
00219 //In slave mode, the clock is updated with an external trigger every ms.  No need for
00220 //100us resolution.
00221 void callback_clockExternalIncrement(void) {
00222     
00223     timeKeeper++;
00224        
00225     if (resetTimer) {
00226         timeKeeper = 0;
00227         resetTimer = false; 
00228     }
00229       
00230     if (currentBroadcastBit > 31) {
00231         clockBroadCast.detach();
00232         currentBroadcastBit = 0;
00233     }
00234     
00235     //Every second, we broadcast out the current time 
00236     if ((timeKeeper % 1000) == 0) {
00237         currentBroadcastTime = timeKeeper;
00238         clockOutSync = 1;
00239         
00240         currentBroadcastBit = 0;
00241      
00242         clockOutSignal = (currentBroadcastTime & ( 1 << currentBroadcastBit)) >> currentBroadcastBit;
00243         broadcastHigh = true;
00244         clockBroadCast.attach_us(&broadcastNextBit, 1000);
00245     }
00246 }
00247 
00248 //Every digital port's in pin has a hardware interrupt.  We use a callback stub for each port
00249 //that routes the int_callback.
00250 void int_callback(int portNum, int direction) {
00251     portVector[portNum]->addStateChange(direction, timeKeeper);   
00252 }
00253 
00254 //Callback stubs
00255 void callback_port1_rise(void) { int_callback(1, 1); }
00256 void callback_port1_fall(void) { int_callback(1, 0); }
00257 void callback_port2_rise(void) { int_callback(2, 1); }
00258 void callback_port2_fall(void) { int_callback(2, 0); }
00259 void callback_port3_rise(void) { int_callback(3, 1); }
00260 void callback_port3_fall(void) { int_callback(3, 0); }
00261 void callback_port4_rise(void) { int_callback(4, 1); }
00262 void callback_port4_fall(void) { int_callback(4, 0); }
00263 void callback_port5_rise(void) { int_callback(5, 1); }
00264 void callback_port5_fall(void) { int_callback(5, 0); }
00265 void callback_port6_rise(void) { int_callback(6, 1); }
00266 void callback_port6_fall(void) { int_callback(6, 0); }
00267 void callback_port7_rise(void) { int_callback(7, 1); }
00268 void callback_port7_fall(void) { int_callback(7, 0); }
00269 void callback_port8_rise(void) { int_callback(8, 1); }
00270 void callback_port8_fall(void) { int_callback(8, 0); }
00271 
00272 //This function is attached to an interrupt pin for external clock reset
00273 void callback_clockReset(void) {
00274     if (timeKeeper > 100) {
00275         LPC_TIM2->TCR = 0x02;    // reset timer
00276         timeKeeper = 0;
00277         pc.printf("%d Clock reset\r\n", timeKeeper);
00278     }      
00279 }
00280 
00281 
00282 int main() {
00283     timeKeeper = 0; //set main clock to 0;
00284     sWav.reset(); 
00285     pc.baud(115200);
00286     //pc.baud(9600);
00287    
00288     for (int i = 0; i < 9; i++) {
00289         portVector[i] = NULL;
00290     }
00291     //We keep portVector 1-based to eliminate confusion
00292     portVector[1] = &port1;
00293     portVector[2] = &port2;
00294     portVector[3] = &port3;
00295     portVector[4] = &port4;
00296     portVector[5] = &port5;
00297     portVector[6] = &port6;
00298     portVector[7] = &port7;
00299     portVector[8] = &port8;
00300    
00301     //Callback to update the main clock 
00302     //timeTick1.attach_us(&incrementTime, 100);
00303     
00304     timer0_init();
00305     
00306     
00307     //Set up callbacks for the port interrupts   
00308     int1.rise(&callback_port1_rise);
00309     int1.fall(&callback_port1_fall);
00310     int2.rise(&callback_port2_rise);
00311     int2.fall(&callback_port2_fall);
00312     int3.rise(&callback_port3_rise);
00313     int3.fall(&callback_port3_fall);
00314     int4.rise(&callback_port4_rise);
00315     int4.fall(&callback_port4_fall);
00316     int5.rise(&callback_port5_rise);
00317     int5.fall(&callback_port5_fall);
00318     int6.rise(&callback_port6_rise);
00319     int6.fall(&callback_port6_fall);
00320     int7.rise(&callback_port7_rise);
00321     int7.fall(&callback_port7_fall);
00322     int8.rise(&callback_port8_rise);
00323     int8.fall(&callback_port8_fall);
00324     
00325     clockResetInt.rise(&callback_clockReset);
00326     clockResetInt.mode(PullDown);
00327     
00328     clockExternalIncrement.mode(PullDown);
00329       
00330     //The inputs are set for pull-up mode (might need to change this)
00331     in1.mode(PullDown);
00332     in2.mode(PullDown);
00333     in3.mode(PullDown);
00334     in4.mode(PullDown);
00335     in5.mode(PullDown);
00336     in6.mode(PullDown);
00337     in7.mode(PullDown);
00338     in8.mode(PullDown);
00339      
00340     //Set up input buffer for the serial port
00341     //char buffer[128];
00342     int bufferPos = 0;
00343     eraseBuffer(buffer,256);
00344     
00345     ostringstream timeConvert;   // stream used for the conversion
00346     ostringstream stateConvert; 
00347     char junkChar;
00348     int tmpChar;
00349     
00350     while (pc.readable()) {
00351         junkChar = pc.getc();
00352     }   
00353          
00354     FILE *fp = fopen("/local/STARTUP.TXT", "r");
00355     if (fp != NULL) {
00356         pc.printf("Executing startup script...\r\n");  
00357         do { 
00358             tmpChar = fgetc(fp);
00359             if ((tmpChar >= 32) && (tmpChar <= 126)) {
00360                 buffer[bufferPos] = tmpChar;
00361                 bufferPos++;
00362             }
00363             if ((tmpChar == 13) || (tmpChar == 10)) { //carrriage return
00364                 parser.addLineToCurrentBlock(buffer);                          
00365                 bufferPos = 0;
00366                 eraseBuffer(buffer,256);             
00367             }            
00368             //pc.putc(tmpChar);
00369         } while (tmpChar != EOF);
00370         
00371         buffer[bufferPos] = 59;
00372         parser.addLineToCurrentBlock(buffer);
00373         eraseBuffer(buffer,256);  
00374         fclose(fp);
00375     } else {
00376         pc.printf("No startup script found.\r\n"); 
00377     }
00378     
00379     //main loop
00380     while(1) {
00381        //check the main event queue to see if anything needs to be done
00382        mainQueue.check();
00383        
00384        //check if anything has been written to the serial input
00385        if (pc.readable()) {
00386                 
00387             buffer[bufferPos] = pc.getc();
00388             bufferPos++;
00389             
00390             //'Return' key pressed
00391             if ((buffer[bufferPos-1] == 13) || (buffer[bufferPos-1] == 10)) {
00392                 //pc.printf("\r\n");
00393                 buffer[bufferPos-1] = '\0';
00394                 parser.addLineToCurrentBlock(buffer);              
00395                 bufferPos = 0;
00396                 eraseBuffer(buffer,128);
00397                 
00398             } else {
00399                 //pc.putc(buffer[bufferPos-1]);
00400                 //Backspace was pressed
00401                 if (((buffer[bufferPos-1] == 127)||(buffer[bufferPos-1] == 8)) && (bufferPos > 0)) {                                                  
00402                     
00403                     bufferPos = bufferPos-2;                   
00404                 } 
00405             }
00406        }
00407        
00408       // __disable_irq();
00409        
00410        
00411        //Check all the digital ports to see if anything has changed. In the update routine, the port's
00412        //script callbacks are called if the port was triggered 
00413        digitalInChanged = false;
00414        digitalOutChanged = false;
00415        changeTime = timeKeeper;
00416        for (int i = 0; i < NUMPORTS; i++) {
00417              if (portVector[i+1]->update()) {
00418                 digitalInChanged = true;
00419                 changeTime = min(changeTime,portVector[i+1]->lastChangeTime);
00420                 
00421                 //The input state of all the ports in condensed into one number (each bit contains the info)
00422                 if (portVector[i+1]->getLastChangeState() == 1) {
00423                     currentDIOstate[0] = currentDIOstate[0] | (1 << i);
00424                 } else {
00425                     currentDIOstate[0] = currentDIOstate[0] & (255^(1 << i));
00426                 }
00427              }
00428              if (portVector[i+1]->outStateChanged) {
00429                 digitalOutChanged = true;
00430                 changeTime = min(changeTime,portVector[i+1]->lastOutChangeTime);
00431                 //The out state of all the ports in condensed into one number (each bit contains the info)
00432                 if (portVector[i+1]->outState == 1) {
00433                     currentDIOstate[1] = currentDIOstate[1] | (1 << i);
00434                 } else {
00435                     currentDIOstate[1] = currentDIOstate[1] & (255^(1 << i));
00436                 }
00437                 portVector[i+1]->outStateChanged = false;
00438              }
00439        }
00440            
00441        //If anything changed, we write the new values to the serial port (this can be turned off 
00442        //with broadCastStateChanges)
00443        if ( (digitalInChanged||digitalOutChanged) && broadCastStateChanges) {
00444             timeConvert << changeTime; //broadcast the earliest timestamp when a change occured
00445             //stateConvert << currentDIOstate[0] << " " << currentDIOstate[1];
00446             stateConvert << currentDIOstate[0] << " " << currentDIOstate[1] << "       ";
00447             textDisplay.send(timeConvert.str() + " " + stateConvert.str() + "\r\n");
00448             timeConvert.clear();
00449             timeConvert.seekp(0);
00450             stateConvert.clear();
00451             stateConvert.seekp(0);
00452             digitalInChanged = false;
00453             digitalOutChanged = false;
00454        }
00455        
00456        //We use a buffer to send text via the serial port.  For every loop
00457        //in the main loop, we send one character if there is enything to send.
00458        //This way, outputting text to serial does not hold up other time-sensitive
00459        //things in the event queue
00460        if ((textDisplay.unsentData) && (textStreaming)) {
00461             pc.printf("%c", textDisplay.getNextChar());
00462        }
00463        
00464        //Here is how we toggle between standalone and slave mode for the clock updating.
00465        if (changeToSlave) {
00466             //timeTick1.detach();
00467             NVIC_DisableIRQ(TIMER2_IRQn); // Disable the interrupt
00468             clockExternalIncrement.rise(&callback_clockExternalIncrement);
00469             clockSlave = true;
00470             changeToSlave = false;
00471             changeToStandAlone = false;
00472        } else if (changeToStandAlone) {
00473             //timeTick1.attach_us(&incrementTime, 100);
00474             timer0_init();         
00475             clockExternalIncrement.rise(NULL); //remove the callback to the external interrupt
00476             clockSlave = false;
00477             changeToSlave = false;
00478             changeToStandAlone = false;
00479        }
00480                     
00481        //__enable_irq();
00482        
00483     }
00484 }