A scripting environment used to define precise output/input temporal relationships.
Dependencies: SMARTWAV mbed HelloWorld
Dependents: perturbRoom_legacy
Fork of HelloWorld by
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 }
Generated on Sun Jul 17 2022 23:34:35 by 1.7.2