![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
perturh room legacy
Dependencies: SMARTWAV USBDevice mbed stateScript
Fork of stateScript by
main.cpp
- Committer:
- mkarlsso
- Date:
- 2014-07-08
- Revision:
- 2:298679fff37c
- Parent:
- 0:fb6bbc10ffa0
- Child:
- 3:ae33b7f5a7c1
File content as of revision 2:298679fff37c:
#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; } } //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) { //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(); } }