// HoloBot.nqc // Copyright (c) 2003-2004 Dragon's Eye Software // All Rights Reserved // // sensors #define TIMEBUTTONDN SENSOR_1 #define TIMEBUTTONUP SENSOR_3 // dual use sensor, in button mode when waiting for input and in light meter // mode when calibrating or making an exposure #define LIGHTMETER SENSOR_2 #define ACCEPTBUTTON SENSOR_2 // shutter control #define SHUTTER OUT_A // events #define EVENT_TIMEDEC 0 // decrement the desired time #define EVENT_TIMEINC 1 // increment the desired time #define EVENT_ACCEPT 2 // accept the latest input #define DEFAULT_EXPOSURE 100 // 10 seconds #define EXPOSURE_INCREMENT 5 // increment/decrement by half seconds #define EXPOSURE_INCREMENT2 20 // increment/decrement by 2 seconds #define EXPOSURE_INCREMENT3 100 // increment/decrement by 10 seconds #define EXPOSURE_INCREMENT4 600 // increment/decrement by 60 seconds #define EXPOSURE_MIN 5 // min exposure is 1/2 second #define EXPOSURE_MAX 27000 // max exposure is 120 seconds #define EXPOSURE_THRESHOLD1 200 // go to increment 2 at this point #define EXPOSURE_THRESHOLD2 600 // go to increment 3 at this point #define EXPOSURE_THRESHOLD3 1200 // go to increment 4 at this point #define DEFAULT_SETTLETIME 9000 // 15 minutes #define SETTLE_INCREMENT1 600 // increment/decrement by 1min #define SETTLE_INCREMENT2 3000 // increment/decrement by 5min #define SETTLE_MIN 600 // min settle is 5 minutes #define SETTLE_MAX 27000 // max settle is 45 min // various states the program enters #define STATE_INIT 0 // basic initialization #define STATE_SETTLETIMESELECT 1 // settling time select mode #define STATE_EXPTIMESELECT 2 // exposure time select mode #define STATE_STARTSETTLING 3 // begin settling stage #define STATE_SETTLING 4 // waiting for the table to settle #define STATE_STARTEXPOSING 5 // start the exposure stage #define STATE_EXPOSING 6 // exposing #define STATE_EXPOSUREDONE 7 // exposure done #define STATE_WAITING 8 // waiting for confirmation #define STATE_SHUTTERFAILED 9 // shutter failed to open #define STATE_DELAYTIMESELECT 10 // select the multi-exposure delay time #define ShutterOpen() { OnRev( SHUTTER ); SetPower( SHUTTER, OUT_FULL ); } #define ShutterClosed() { OnFwd( SHUTTER ); SetPower( SHUTTER, OUT_FULL ); Wait(25); SetOutput( SHUTTER, OUT_OFF ); } #define PlayBumperSound() {PlayTone(2670, 10); Wait(30); PlayTone(3623, 10); Wait(20); PlayTone(2499, 10); Wait(10); PlayTone(2320, 10);} #define PlayWakeUpSound() {PlayTone(1983, 10); PlayTone(2692, 10); Wait(30); PlayTone(2692, 10); Wait(20); PlayTone(2320, 10);} #define PlaySleepSound() {PlayTone(2136, 10); PlayTone(2478, 10); PlayTone(2923, 10); Wait(50); PlayTone(1940, 10);} #define PlaySeekSound() {PlayTone(1150, 10); PlayTone(2250, 10); PlayTone(4500, 10); PlayTone(1100, 10); Wait(80); PlayTone(2000, 10); PlayTone(1641, 10); Wait(80); repeat(2) {PlayTone(2000, 10); PlayTone(1281, 10); PlayTone(2000, 10); PlayTone(1634, 10);}} #define PlayTiltSound() {PlayTone(1450, 10); PlayTone(1967, 10); PlayTone(2136, 10); PlayTone(1826, 10); PlayTone(1474, 10); PlayTone(2016, 10); PlayTone(1710, 10); PlayTone(2301, 10); PlayTone(2692, 10); PlayTone(1122, 10); Wait(100); } // variables int desiredExposureTime; int desiredSettlingTime; int lastTickTime; // last time we made a tick sound int timeRemaining; // the amount of time remaining if waiting for an exposure int curState; int darkLevel; // value computed when calibrating to determine the base dark light level int temp; int delayTime; // how long to delay between exposures void Initializing() { timeRemaining = desiredSettlingTime / 10; // clear our events ClearEvent( EVENT_TIMEDEC ); ClearEvent( EVENT_TIMEINC ); ClearEvent( EVENT_ACCEPT ); // make sure the shutter is closed ShutterClosed(); // configure the time select button & event SetSensor( TIMEBUTTONDN, SENSOR_TOUCH ); SetEvent( EVENT_TIMEDEC, TIMEBUTTONDN, EVENT_TYPE_CLICK ); SetUpperLimit( EVENT_TIMEDEC, 0 ); SetLowerLimit( EVENT_TIMEDEC, 1 ); SetClickTime( EVENT_TIMEDEC, 50 ); SetSensor( TIMEBUTTONUP, SENSOR_TOUCH ); SetEvent( EVENT_TIMEINC, TIMEBUTTONUP, EVENT_TYPE_CLICK ); SetUpperLimit( EVENT_TIMEINC, 0 ); SetLowerLimit( EVENT_TIMEINC, 1 ); SetClickTime( EVENT_TIMEINC, 50 ); // configure the accept button & event SetSensor( ACCEPTBUTTON, SENSOR_TOUCH ); SetEvent( EVENT_ACCEPT, ACCEPTBUTTON, EVENT_TYPE_CLICK ); SetUpperLimit( EVENT_ACCEPT, 0 ); SetLowerLimit( EVENT_ACCEPT, 1 ); SetClickTime( EVENT_ACCEPT, 50 ); // set our display variable SetUserDisplay( timeRemaining, 0 ); // play our wakeup sound PlayWakeUpSound(); } void SetState( int state ) { curState = state; } task main() { SetState( STATE_INIT ); desiredExposureTime = DEFAULT_EXPOSURE; desiredSettlingTime = DEFAULT_SETTLETIME; delayTime = 0; // enter the real main loop while( true ) { monitor( EVENT_MASK( EVENT_TIMEDEC ) | EVENT_MASK( EVENT_TIMEINC ) | EVENT_MASK( EVENT_ACCEPT ) ) { switch( curState ) { case STATE_INIT: Initializing(); SetState( STATE_SETTLETIMESELECT ); break; case STATE_SETTLETIMESELECT: break; case STATE_EXPTIMESELECT: break; case STATE_STARTSETTLING: SetSleepTime(90); ShutterClosed(); SetState( STATE_SETTLING ); ClearTimer(0); lastTickTime = desiredSettlingTime - Timer(0); break; case STATE_SETTLING: temp = desiredSettlingTime - Timer(0); if ( temp <= 0 ) SetState( STATE_STARTEXPOSING ); timeRemaining = temp / 10; if ( timeRemaining <= 10 ) { if ( lastTickTime - temp > 10 ) { lastTickTime = temp; PlayTone( 2670, 10 ); } } break; case STATE_STARTEXPOSING: // configure light sensor SetSensor( LIGHTMETER, SENSOR_LIGHT ); SetSensorMode( LIGHTMETER, SENSOR_MODE_RAW ); darkLevel = LIGHTMETER; PlayBumperSound(); SetState( STATE_EXPOSING ); ShutterOpen(); ClearTimer(0); break; case STATE_EXPOSING: temp = desiredExposureTime - Timer(0); timeRemaining = temp; if ( timeRemaining <= 0 ) SetState( STATE_EXPOSUREDONE ); break; case STATE_EXPOSUREDONE: if ( LIGHTMETER > darkLevel - 50 ) SetState( STATE_SHUTTERFAILED ); else { if ( delayTime == 0 ) { ShutterClosed(); PlaySleepSound(); SetState( STATE_WAITING ); SetSleepTime(10); Wait(500); SleepNow(); } else { PlaySeekSound(); desiredSettlingTime = delayTime; delayTime = 0; SetState( STATE_STARTSETTLING ); } } break; case STATE_WAITING: break; case STATE_SHUTTERFAILED: ShutterClosed(); PlayTiltSound(); PlayTiltSound(); PlayTiltSound(); SetState( STATE_WAITING ); break; } } catch( EVENT_MASK( EVENT_TIMEDEC ) ) { switch( curState ) { case STATE_SETTLETIMESELECT: if ( desiredSettlingTime > SETTLE_INCREMENT2 ) desiredSettlingTime = desiredSettlingTime - SETTLE_INCREMENT2; else desiredSettlingTime = desiredSettlingTime - SETTLE_INCREMENT1; if ( desiredSettlingTime < SETTLE_MIN ) desiredSettlingTime = SETTLE_MAX; timeRemaining = desiredSettlingTime / 10; break; // decrement the current desired time case STATE_EXPTIMESELECT: if ( desiredExposureTime < EXPOSURE_THRESHOLD1 ) desiredExposureTime = desiredExposureTime - EXPOSURE_INCREMENT; else if ( desiredExposureTime < EXPOSURE_THRESHOLD2 ) desiredExposureTime = desiredExposureTime - EXPOSURE_INCREMENT2; else if ( desiredExposureTime < EXPOSURE_THRESHOLD3 ) desiredExposureTime = desiredExposureTime - EXPOSURE_INCREMENT3; else desiredExposureTime = desiredExposureTime - EXPOSURE_INCREMENT4; if ( desiredExposureTime < EXPOSURE_MIN ) desiredExposureTime = EXPOSURE_MAX; timeRemaining = desiredExposureTime; break; case STATE_DELAYTIMESELECT: if ( delayTime > SETTLE_INCREMENT2 ) delayTime = delayTime - SETTLE_INCREMENT2; else delayTime = delayTime - SETTLE_INCREMENT1; if ( delayTime < SETTLE_MIN ) delayTime = SETTLE_MAX; timeRemaining = delayTime / 10; break; case STATE_WAITING: SetState( STATE_EXPTIMESELECT ); break; // if we're in anything but time select mode, cancel // the current operation and go to time select mode default: SetState( STATE_EXPTIMESELECT ); PlayTiltSound(); break; } } catch( EVENT_MASK( EVENT_TIMEINC ) ) { switch( curState ) { case STATE_SETTLETIMESELECT: if ( desiredSettlingTime < SETTLE_INCREMENT2 ) desiredSettlingTime = desiredSettlingTime + SETTLE_INCREMENT1; else desiredSettlingTime = desiredSettlingTime + SETTLE_INCREMENT2; if ( desiredSettlingTime > SETTLE_MAX ) desiredSettlingTime = SETTLE_MIN; timeRemaining = desiredSettlingTime / 10; break; case STATE_EXPTIMESELECT: if ( desiredExposureTime < EXPOSURE_THRESHOLD1 ) desiredExposureTime = desiredExposureTime + EXPOSURE_INCREMENT; else if ( desiredExposureTime < EXPOSURE_THRESHOLD2 ) desiredExposureTime = desiredExposureTime + EXPOSURE_INCREMENT2; else if ( desiredExposureTime < EXPOSURE_THRESHOLD3 ) desiredExposureTime = desiredExposureTime + EXPOSURE_INCREMENT3; else desiredExposureTime = desiredExposureTime + EXPOSURE_INCREMENT4; if ( desiredExposureTime > EXPOSURE_MAX ) desiredExposureTime = EXPOSURE_MIN; timeRemaining = desiredExposureTime; break; case STATE_DELAYTIMESELECT: if ( delayTime < SETTLE_INCREMENT2 ) delayTime = delayTime + SETTLE_INCREMENT1; else delayTime = delayTime + SETTLE_INCREMENT2; if ( delayTime > SETTLE_MAX ) delayTime = SETTLE_MIN; timeRemaining = delayTime / 10; break; case STATE_WAITING: SetState( STATE_EXPTIMESELECT ); break; // if we're in anything else, cancel // the current operation and go to time select mode default: SetState( STATE_EXPTIMESELECT ); PlayTiltSound(); break; } } catch( EVENT_MASK( EVENT_ACCEPT ) ) { switch( curState ) { case STATE_SETTLETIMESELECT: SetState( STATE_EXPTIMESELECT ); timeRemaining = desiredExposureTime; PlaySleepSound(); break; case STATE_EXPTIMESELECT: SetState( STATE_DELAYTIMESELECT ); timeRemaining = delayTime; PlaySleepSound(); break; case STATE_DELAYTIMESELECT: SetState( STATE_STARTSETTLING ); PlaySleepSound(); break; default: PlayTiltSound(); break; } } } }