perturh room legacy
Dependencies: SMARTWAV USBDevice mbed stateScript
Fork of stateScript by
main.cpp
- 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 "behave.h" #include <string.h> #include <sstream> #include "SMARTWAV.h" #include "USBSerial.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(p24); DigitalOut clockOutSync(p19); DigitalOut clockOutSignal(p29); InterruptIn clockExternalIncrement(p30); //Pins for digital ports. Each port has 1 out and 1 in //DigitalOut out1(LED1); //route to LED for debugging //1A,1B DigitalOut out1(p5); DigitalIn in1(p6); InterruptIn int1(p6); __attribute((section("AHBSRAM0"),aligned)) digitalPort port1(&out1, &in1); //1C,1D DigitalOut out2(p9); DigitalIn in2(p10); InterruptIn int2(p10); __attribute((section("AHBSRAM0"),aligned)) digitalPort port2(&out2, &in2); //2A,2B DigitalOut out3(p13); DigitalIn in3(p14); InterruptIn int3(p14); __attribute((section("AHBSRAM0"),aligned)) digitalPort port3(&out3, &in3); //2C,2D DigitalOut out4(p17); DigitalIn in4(p18); InterruptIn int4(p18); __attribute((section("AHBSRAM0"),aligned)) digitalPort port4(&out4, &in4); //3A,3B DigitalOut out5(p21); DigitalIn in5(p22); InterruptIn int5(p22); __attribute((section("AHBSRAM0"),aligned)) digitalPort port5(&out5, &in5); ////3C,3D //DigitalOut out6(p21); //DigitalIn in6(p22); //InterruptIn int6(p22); //__attribute((section("AHBSRAM0"),aligned)) digitalPort port6(&out6, &in6); ////4A,4B ////DigitalOut out7(p9); ////DigitalIn in7(p10); ////InterruptIn int7(p10); ////__attribute((section("AHBSRAM0"),aligned)) digitalPort port7(&out7, &in7); ////5A,5B //DigitalOut out7(p13); //DigitalIn in7(p14); //InterruptIn int7(p14); //__attribute((section("AHBSRAM0"),aligned)) digitalPort port7(&out7, &in7); ////6A,6B //DigitalOut out8(p23); //DigitalIn in8(p24); //InterruptIn int8(p24); //__attribute((section("AHBSRAM0"),aligned)) digitalPort port8(&out8, &in8); ////Pump1 //DigitalOut out9(p25); //__attribute((section("AHBSRAM0"),aligned)) digitalPort port9(&out9); ////Pump2 //DigitalOut out10(p26); //__attribute((section("AHBSRAM0"),aligned)) digitalPort port10(&out10); //Serial communication //Serial pc(USBTX, USBRX); // tx, rx USBSerial pc; //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(p28,p27,p26); //(TX,RX,Reset); //Serial device(p9,p10); //Erases the input buffer for serial input void eraseBuffer(char* buffer,int numToErase) { for (int i = 0; i < numToErase; i++) { buffer[i] = NULL; } } //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); } //void callback_port9_rise(void) { int_callback(9, 1); } //void callback_port9_fall(void) { int_callback(9, 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); //device.baud(4800); //pc.baud(9600); for (int i = 0; i <NUMPORTS+1; 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; // portVector[9] = &port9; // portVector[10] = &port10; //portVector[11] = &port11; //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); // int9.rise(&callback_port9_rise); // int9.fall(&callback_port9_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); // in9.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()) { while (pc.available()) { 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) { //check the main event queue to see if anything needs to be done mainQueue.check(); //https://developer.mbed.org/handbook/Serial //if(device.readable()) { // pc.putc(device.getc()); // } //check if anything has been written to the serial input //if (pc.readable()) { if (pc.available()) { 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] == 127)||(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(); } }