Beispiel #1
0
void
next_rnd_mode (mpc_fun_param_t *params)
/* cycle through all valid rounding modes and finish with an invalid one */
{
  int last = params->nbout + params->nbin - 1;
  int index = params->nbout + params->nbin - params->nbrnd;
  int carry = 1;

  while (carry && index <= last) {
    next_mode (params, index);
    if (!is_valid_mode (params, index) && index < last)
      first_mode (params, index);
    else
      carry = 0;
    index++;
  }
}
int main(void)
{	
	uint8_t short_click = 0;
	
	// All ports default to input, but turn pull-up resistors on for the stars (not the ADC input!  Made that mistake already)
	PORTB = (1 << STAR2_PIN) | (1 << STAR3_PIN);
	
	// Start up ADC for capacitor pin
	DIDR0 |= (1 << CAP_DIDR);							// disable digital input on ADC pin to reduce power consumption
	ADMUX  = (1 << REFS0) | (1 << ADLAR) | CAP_CHANNEL; // 1.1v reference, left-adjust, ADC3/PB3
	ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
	
	// Wait for completion
	while (ADCSRA & (1 << ADSC))
		;
	// Start again as datasheet says first result is unreliable
	ADCSRA |= (1 << ADSC);
	// Wait for completion
	while (ADCSRA & (1 << ADSC))
		;

	if(ADCH > CAP_THRESHOLD) 
		short_click = 1;

	// Turn off ADC
	ADC_off();

	// Charge up the capacitor by setting CAP_PIN to output
	DDRB  |= (1 << CAP_PIN);	// Output
    PORTB |= (1 << CAP_PIN);	// High

    // Set PWM pin to output
    DDRB = (1 << PWM_PIN);

    // Set timer to do PWM for correct output pin and set prescaler timing
    TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
    TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
	
	// Turn features on or off as needed
#ifdef ENABLE_VOLTAGE_MONITORING
	ADC_on();
#else
	ADC_off();
#endif
	ACSR   |=  (1<<7); //AC off
	
#ifdef ENABLE_TURNING_OFF_TURBO_TIMER
	turbo_timer_enabled = ((PINB & (1 << STAR2_PIN)) > 0) ? 1 : 0;
#endif

#ifdef ENABLE_SINGLE_MODE
	if((PINB & (1 << STAR2_PIN)) == 0)
	{
			modes[0] = modes[1] = 
#ifdef FOUR_MODES
			modes[2] = 
#endif
			MODE_TURBO;

			// Last basic mode is already MODE_TURBO - no need to waste bytes changing that
	}		
#endif

#ifdef ENABLE_HIGH_TO_LOW
#ifdef HIGH_TO_LOW_ON_BY_DEFAULT
	if((PINB & (1 << STAR3_PIN)) > 0)
#else
	if((PINB & (1 << STAR3_PIN)) == 0)
#endif
		revert_modes();
#endif
	
#ifdef ENABLE_TACTICAL_MODE
#ifdef TACTICAL_MODE_ON_BY_DEFAULT
	if((PINB & (1 << STAR2_PIN)) > 0)
#else
	if((PINB & (1 << STAR2_PIN)) == 0)
#endif
	{
		modes[1] = MODE_TURBO;

		if(modes[0] == MODE_TURBO) // Single mode
		{
			modes[2] = 
#ifdef FOUR_MODES
			modes[3] = 
#endif
			MODE_TURBO;
		}
		else
		{
			modes[0] = MODE_STROBE;
			modes[2] = MODE_LOW;
#ifdef FOUR_MODES
			modes[3] = MODE_LOWLOW;
#endif
		}
	}
#endif


	// Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
	// Will allow us to go idle between WDT interrupts
	set_sleep_mode(SLEEP_MODE_IDLE);
	
	// Mode memory handling block
	{
		uint8_t n_short_clicks = 0;

		// Determine what mode we should fire up
		// Read the last mode that was saved
		mode_idx = read_stored_idx();

		// Handle short press counter
		n_short_clicks = (mode_idx & 0xf0);
		mode_idx &= 0x0f;

		if(short_click) // This click was short
		{
			if(n_short_clicks == MODE_INDEX_TURBO_RAMPDOWN) // TODO: Test if this logic works in practice, or do we need to use always double tap from turbo?
				n_short_clicks = 0; // Keep turbo, reset counter
			else
				next_mode(n_short_clicks); // Will handle wrap arounds

			store_mode_idx(mode_idx | ((n_short_clicks < HIDDEN_MODE_THRESHOLD) ? n_short_clicks+0x10 : n_short_clicks));
		} 
		else // Didn't have a short press, keep the same mode, stored without short click counter
		{
			if((PINB & (1 << STAR2_PIN)) == 0) // Tactical or Single or No memory, reset to 1st mode
				mode_idx = 0;

			store_mode_idx(mode_idx);
		}
	}		
	
	// Start watchdog timer (used for storing the mode after delay, turbo timer, and voltage monitoring)
	WDT_on();
	
	// Now just fire up the mode
	selected_pwm = modes[mode_idx]; // Note: Actual PWM can be less than selected PWM (e.g. in case of low voltage)
	
	if(selected_pwm < PWM_MIN) // Hidden blinky modes
		adjusted_pwm = PWM_MAX; // All blinky modes initially with full power
	else
		adjusted_pwm = selected_pwm;

	// block for main loop
	{
		uint8_t ii = 0; // Loop counter, used by multiple branches
#ifdef ENABLE_BEACONS
		uint8_t beacon_background = PWM_OFF;
#endif
	
		while(1)
		{
#ifdef ENABLE_VOLTAGE_MONITORING
			if(adjusted_pwm == PWM_OFF) // Voltage monitoring signaled us to turn off the light -> break out of the main loop
				break;
#endif

			PWM_LVL = adjusted_pwm; // must be set inside loop, is volatile & might have changed because of voltage monitoring

			switch(selected_pwm)
			{
			case MODE_STROBE: // Disorienting alternating strobe
#ifdef NORMAL_STROBE
				// 51ms = ~19.5Hz, ~60% DC
				_delay_ms(25);
				PWM_LVL = 0;
				_delay_ms(26);
#endif
#ifdef ALTERNATING_STROBE
				_delay_ms(31);
				PWM_LVL = 0;
				if(ii < 19) // 51ms = ~19.5Hz, ~60% DC
					_delay_ms(20);
				else if(ii < 32) // 77ms = ~13Hz, ~40% DC
					_delay_ms(46);
				else
					ii = 255;
#endif
#ifdef RANDOM_STROBE 
				{   // 77ms = 13Hz, 51ms = 19.5Hz / 40-60% DC
					ii = (5 * ii) + 128;
					_delay_ms(31);
					PWM_LVL = 0;
					_delay_ms(ii > 127 ? 46 : 20);
				}					
#endif
				break;
			case MODE_MOTION_STOPPING_STROBE: // 8Hz, 1.6% DC
				_delay_ms(2);
				PWM_LVL = 0;
				_delay_ms(123);
				break;
#ifdef ENABLE_SOS
			case MODE_SOS:
				if(ii / 3 == 1)
					_delay_ms(600);  // Dash for 'O' (3xDot)
				else
					_delay_ms(200);  // Dot for 'S'

				PWM_LVL = 0;

				switch(ii)
				{
				default:
					_delay_ms(200);  // Pause inside a letter (1xDot)
					break;
				case 2:
				case 5:
					_delay_ms(600); // Pause between letters (3xDot)
					break;
				case 8:
					_delay_ms(2500); // Pause between "words" (should be 7xDot, but I like it longer)
					ii = 255;
					break;
				}
				break;
#endif
#ifdef ENABLE_BEACONS
			case MODE_BEACON_WITH_BACKGROUND:
				beacon_background = PWM_BEACON_BACKGROUND;
				goto beacon_common;
			case MODE_SLOW_BEACON_WITH_BACKGROUND:
				beacon_background = PWM_SLOW_BEACON_BACKGROUND;
				// no break - fall through to beacon code
			case MODE_BEACON:
			case MODE_ALPINE_DISTRESS_BEACON:
			beacon_common:
				_delay_ms(50);
				PWM_LVL = beacon_background;
				_delay_ms(950);
				
				if(selected_pwm == MODE_ALPINE_DISTRESS_BEACON)
				{
					if(ii > 5)
					{
						_delay_ms(59000);
						ii = 255;
					}
					else
						_delay_ms(9000);
				}
				else if(selected_pwm == MODE_SLOW_BEACON_WITH_BACKGROUND)
					_delay_ms(1500);
#endif
				break;
			default:
				sleep_mode();
				break;
			}

			ii++; // Loop counter, used by multiple branches
		}
	}

#ifdef ENABLE_VOLTAGE_MONITORING
	//
	// Critically low voltage -> Turn off the light
	// 
		
	// Disable WDT so it doesn't wake us up from sleep
	WDT_off();

	// Would be nice to blink a couple of times with lowest brightness to notify the user, but not implemented due space restrictions

	// Turn the light off
	PWM_LVL = 0;

	// Disable ADC so it doesn't consume power
	ADC_off();

	// Power down as many components as possible
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);

	// Deep sleep until powered off - consumes ~110uA during the deep sleep
	while(1)
		sleep_mode();
#endif

    return 0; // Standard Return Code -> would return to idle loop with interrupts disabled.
}
int main(void)
{

	DDRB |= (1 << PWM_PIN);	 // Set PWM pin to output, enable main channel
	TCCR0A = FAST; // Set timer to do PWM for correct output pin and set prescaler timing
	TCCR0B = 0x01; // Set timer to do PWM for correct output pin and set prescaler timing

	restore_state(); // Read config values and saved state

	count_modes(); // Enable the current mode group
	 // check button press time, unless we're in group selection mode
	if (mode_idx != GROUP_SELECT_MODE) {
		if ( we_did_a_fast_press() ) { // sram hasn't decayed yet, must have been a short press
			increment_fast_presses();
			next_mode(); // Will handle wrap arounds
		} else { // Long press, keep the same mode
			reset_fast_presses();
			if( !memory_is_enabled() ) {mode_idx = 0;}  // if memory is turned off, set mode_idx to 0
		}
	}
	save_mode();

	// Turn features on or off as needed
	#ifdef VOLTAGE_MON
	ADC_on();
	#else
	ADC_off();
	#endif

	uint8_t output;
	uint8_t i = 0;
	uint16_t ticks = 0;
#ifdef TURBO_RAMP_DOWN
	uint8_t adj_output = 255;
#endif
	
#ifdef VOLTAGE_MON
	uint8_t lowbatt_cnt = 0;
	uint8_t voltage;
	ADCSRA |= (1 << ADSC); // Make sure voltage reading is running for later
#endif

	if(mode_idx > num_modes) { output = mode_idx; }  // special modes, override output
	else { output = modes[mode_idx]; }
	
	while(1) {
		if (fast_presses[0] >= 12) {  // Config mode if 12 or more fast presses
			_delay_s();	   // wait for user to stop fast-pressing button
			reset_fast_presses(); // exit this mode after one use

			toggle_mode(GROUP_SELECT_MODE, 1); // Enter the mode group selection mode?
			toggle_options((options ^ 0b00010000), 2); // memory
			toggle_options((options ^ 0b00100000), 3); // hidden blinkies
			toggle_options((options ^ 0b01000000), 4); // hidden battcheck
			toggle_options((options ^ 0b10000000), 5); // turbo timer
			toggle_options(DEFAULTS, 6); // reset to defaults
		}
		else if (output == STROBE) { // 10Hz tactical strobe
			for(i=0;i<8;i++) {
				set_level(RAMP_SIZE);
				_delay_ms(33);
				set_output(0);
				_delay_ms(67);
			}
		}
		else if (output == BEACON) {
			set_level(RAMP_SIZE);
			_delay_ms(10);
			set_output(0);
			_delay_s(); _delay_s();
		}
		else if (output == SOS) {  // dot = 1 unit, dash = 3 units, space betwen parts of a letter = 1 unit, space between letters = 3 units
			#define SOS_SPEED 200  // these speeds aren't perfect, but they'll work for the [never] times they'll actually get used
			blink(3, SOS_SPEED); // 200 on, 400 off, 200 on, 400 off, 200 on, 400 off
			_delay_ms(SOS_SPEED);  // wait for 200
			blink(3, SOS_SPEED*5/2);  // 500 on, 1000 off, 500 on, 1000 off, 500 on, 1000 off (techically too long on that last off beat, but oh well)
			blink(3, SOS_SPEED);  // 200 on, 400 off, 200 on, 400 off, 200 on, 400 off
			_delay_s(); _delay_s();
		}
		else if (output == BATT_CHECK) {
			 blink(battcheck(), BLINK_SPEED/4);
			 _delay_s(); _delay_s();
		}
		else if (output == GROUP_SELECT_MODE) {
			mode_idx = 0; // exit this mode after one use

			for(i=0; i<NUM_MODEGROUPS; i++) {
				toggle_options(((options & 0b11110000) | i), i+1);
			}
			_delay_s();
		}
		else {
			if ((output == TURBO) && ( ttimer_is_enabled() ) && (ticks > (TURBO_MINUTES * TICKS_PER_MINUTE))) {
	#ifdef TURBO_RAMP_DOWN
				if (adj_output > TURBO_LOWER) { adj_output = adj_output - 2; }
				set_output(adj_output);
	#else
				set_output(TURBO_LOWER);
	#endif
			}
			else {
				ticks ++; // count ticks for turbo timer
				set_level(output);
			}

			_delay_ms(500);  // Otherwise, just sleep.

		}
		reset_fast_presses();
#ifdef VOLTAGE_MON
		if (ADCSRA & (1 << ADIF)) {  // if a voltage reading is ready
			voltage = ADCH;  // get the waiting value
	
			if (voltage < ADC_LOW) { // See if voltage is lower than what we were looking for
				lowbatt_cnt ++;
			} else {
				lowbatt_cnt = 0;
			}
			
			if (lowbatt_cnt >= 8) {  // See if it's been low for a while, and maybe step down
				//set_output(0);  _delay_ms(100); // blink on step-down:

				if (output > RAMP_SIZE) {  // blinky modes 
					output = RAMP_SIZE / 2; // step down from blinky modes to medium
				} else if (output > 1) {  // regular solid mode
					output = output - 1; // step down from solid modes somewhat gradually
				} else { // Already at the lowest mode
					set_output(0); // Turn off the light
					set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Power down as many components as possible
					sleep_mode();
				}
				set_level(output);
				lowbatt_cnt = 0;
				_delay_s(); // Wait before lowering the level again
			}

			ADCSRA |= (1 << ADSC); // Make sure conversion is running for next time through
		}
#endif  // ifdef VOLTAGE_MON
	}
}
Beispiel #4
0
int main(void)
{
    // All ports default to input, but turn pull-up resistors on for the stars
    // (not the ADC input!  Made that mistake already)
    // (stars not used)
    //PORTB = (1 << STAR2_PIN) | (1 << STAR3_PIN) | (1 << STAR4_PIN);

    // Set PWM pin to output
    DDRB = (1 << PWM_PIN);

    // Turn features on or off as needed
    #ifdef VOLTAGE_MON
    ADC_on();
    #else
    ADC_off();
    #endif
    ACSR   |=  (1<<7); //AC off

    // Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
    // Will allow us to go idle between WDT interrupts (which we're not using anyway)
    set_sleep_mode(SLEEP_MODE_IDLE);

    // Determine what mode we should fire up
    // Read the last mode that was saved
    if (noinit_decay) // not short press, forget mode
    {
        noinit_mode = 0;
        mode_idx = 0;
    } else { // short press, advance to next mode
        mode_idx = noinit_mode;
        next_mode();
        noinit_mode = mode_idx;
    }
    // set noinit data for next boot
    noinit_decay = 0;

    // set PWM mode
    if (modes[mode_idx] < FAST_PWM_START) {
        // Set timer to do PWM for correct output pin and set prescaler timing
        TCCR0A = 0x21; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
    } else {
        // Set timer to do PWM for correct output pin and set prescaler timing
        TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
    }
    TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)

    // Now just fire up the mode
    PWM_LVL = modes[mode_idx];

    uint8_t i = 0;
    uint8_t j = 0;
    uint8_t strobe_len = 0;
#ifdef VOLTAGE_MON
    uint8_t lowbatt_cnt = 0;
    uint8_t voltage;
#endif
    while(1) {
        if(mode_idx < SOLID_MODES) { // Just stay on at a given brightness
            sleep_mode();
        } else if (mode_idx < BATT_CHECK_MODE) {
            PWM_LVL = 0;
            get_voltage();  _delay_ms(200);  // the first reading is junk
#ifdef BATTCHECK_VpT
            uint8_t result = battcheck();
            blink(result >> 5, BLINK_SPEED/8);
            _delay_ms(BLINK_SPEED);
            blink(1,5);
            _delay_ms(BLINK_SPEED*3/2);
            blink(result & 0b00011111, BLINK_SPEED/8);
#else
            blink(battcheck());
#endif  // BATTCHECK_VpT
            _delay_ms(2000);  // wait at least 2 seconds between readouts
        } else if (mode_idx < SINGLE_BEACON_MODES) { // heartbeat flasher
int main(void)
{	
	// All ports default to input, but turn pull-up resistors on for the stars (not the ADC input!  Made that mistake already)
	PORTB = (1 << STAR2_PIN) | (1 << STAR3_PIN) | (1 << STAR4_PIN);
	
    // Set PWM pin to output
    DDRB = (1 << PWM_PIN);

    // Set timer to do PWM for correct output pin and set prescaler timing
    TCCR0A = 0x23; // phase corrected PWM is 0x21 for PB1, fast-PWM is 0x23
    TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
	
	// Turn features on or off as needed
	#ifdef ENABLE_VOLTAGE_MONITORING
	ADC_on();
	#else
	ADC_off();
	#endif
	ACSR   |=  (1<<7); //AC off
	
#ifdef ENABLE_TURNING_OFF_MEMORY
	// Soldering Star 4 disables memory
#ifdef MEMORY_ON_BY_DEFAULT
	memory_enabled = ((PINB & (1 << STAR4_PIN)) > 0) ? 1 : 0;
#else
	memory_enabled = ((PINB & (1 << STAR4_PIN)) == 0) ? 1 : 0;
#endif
#endif

#ifdef ENABLE_TURNING_OFF_TURBO_TIMER
	turbo_timer_enabled = ((PINB & (1 << STAR2_PIN)) > 0) ? 1 : 0;
#endif

#ifdef ENABLE_SINGLE_MODE
	if((PINB & (1 << STAR2_PIN)) == 0)
	{
			modes[0] = modes[1] = 
#ifdef FOUR_MODES
			modes[2] = 
#endif
			MODE_TURBO;

			// Last basic mode is already MODE_TURBO - no need to waste bytes changing that
	}		
#endif

#ifdef ENABLE_TACTICAL_MODE
#ifdef TACTICAL_MODE_ON_BY_DEFAULT
	if((PINB & (1 << STAR2_PIN)) > 0)
#else
	if((PINB & (1 << STAR2_PIN)) == 0)
#endif
	{
#ifdef ENABLE_TURNING_OFF_MEMORY
		if(memory_enabled) // Single mode
		{
			modes[0] = modes[1] = 
#ifdef FOUR_MODES
			modes[2] = 
#endif
			MODE_TURBO;

			// Last basic mode is already MODE_TURBO - no need to waste bytes changing that
		}
		else
#endif
		{
			modes[0] = MODE_STROBE;
			modes[1] = MODE_TURBO;
			modes[2] = MODE_LOW;
#ifdef FOUR_MODES
			modes[3] = MODE_LOWLOW;
#endif
			wdt_timeout = 1;
		}
	}
#endif


#ifdef ENABLE_HIGH_TO_LOW
#ifdef HIGH_TO_LOW_ON_BY_DEFAULT
	if((PINB & (1 << STAR3_PIN)) > 0)
#else
	if((PINB & (1 << STAR3_PIN)) == 0)
#endif
		revert_modes();
#endif
	
	// Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
	// Will allow us to go idle between WDT interrupts
	set_sleep_mode(SLEEP_MODE_IDLE);
	
	// Mode memory handling block
	{
		uint8_t short_clicks = 0;

		// Determine what mode we should fire up
		// Read the last mode that was saved
		mode_idx = read_stored_idx();

		// Handle short press indicator
		short_clicks = (mode_idx & 0xf0);
		mode_idx &= 0x0f;
		
		if(short_clicks) // One or more short clicks
		{
			// Indicates we did a short press last time, go to the next mode
			next_mode(short_clicks); // Will handle wrap arounds
		} 
		// else: Didn't have a short press, keep the same mode, nothing to do
	
		// Store mode with short press indicator
		store_mode_idx(mode_idx | ((short_clicks < HIDDEN_MODE_THRESHOLD) ? short_clicks+0x10 : short_clicks));
	}		
	
	// Start watchdog timer (used for storing the mode after delay, turbo timer, and voltage monitoring)
	WDT_on();
	
	// Now just fire up the mode
	selected_pwm = modes[mode_idx]; // Note: Actual PWM can be less than selected PWM (e.g. in case of low voltage)
	
	if(selected_pwm < PWM_MIN) // Hidden blinky modes
		adjusted_pwm = PWM_MAX; // All blinky modes initially with full power
	else
		adjusted_pwm = selected_pwm;

	// block for main loop
	{
		uint8_t ii = 0; // Loop counter, used by multiple branches
#ifdef ENABLE_BEACONS
		uint8_t beacon_background = PWM_OFF;
#endif
	
		while(1)
		{
#ifdef ENABLE_VOLTAGE_MONITORING
			if(adjusted_pwm == PWM_OFF) // Voltage monitoring signaled us to turn off the light -> break out of the main loop
				break;
#endif

			PWM_LVL = adjusted_pwm; // must be set inside loop, is volatile & might have changed because of voltage monitoring

			switch(selected_pwm)
			{
			case MODE_STROBE: // Disorienting alternating strobe
#ifdef NORMAL_STROBE
				_delay_ms(20);
				PWM_LVL = 0;
				_delay_ms(40);
#endif
#ifdef ALTERNATING_STROBE
				_delay_ms(20);
				PWM_LVL = 0;
				if(ii < 22) // 60ms = ~16.7Hz, ~33% DC
					_delay_ms(40);
				else if(ii < 36) // 111ms = ~9Hz, ~18% DC
					_delay_ms(90);
				else
					ii = 255;
#endif
#ifdef RANDOM_STROBE 
				{   // 77ms = 13Hz, 51ms = 19.5Hz / 40-60% DC
					ii = (5 * ii) + 128;
					_delay_ms(31);
					PWM_LVL = 0;
					_delay_ms(ii > 127 ? 46 : 20);
				}					
#endif
				break;
			case MODE_MOTION_STOPPING_STROBE: // 10Hz, 2% DC
				_delay_ms(2);
				PWM_LVL = 0;
				_delay_ms(98);
				break;
#ifdef ENABLE_SOS
			case MODE_SOS:
				if(ii / 3 == 1)
					_delay_ms(600);  // Dash for 'O' (3xDot)
				else
					_delay_ms(200);  // Dot for 'S'

				PWM_LVL = 0;

				switch(ii)
				{
				default:
					_delay_ms(200);  // Pause inside a letter (1xDot)
					break;
				case 2:
				case 5:
					_delay_ms(600); // Pause between letters (3xDot)
					break;
				case 8:
					_delay_ms(2500); // Pause between "words" (should be 7xDot, but I like it longer)
					ii = 255;
					break;
				}
				break;
#endif
#ifdef ENABLE_BEACONS
			case MODE_BEACON_WITH_BACKGROUND:
			case MODE_SLOW_BEACON_WITH_BACKGROUND:
#ifdef FOUR_MODES
				beacon_background = PWM_SLOW_BEACON_BACKGROUND;
#else
				switch(selected_pwm)
				{
				case MODE_BEACON_WITH_BACKGROUND:
					beacon_background = PWM_BEACON_BACKGROUND;
					break;
				case MODE_SLOW_BEACON_WITH_BACKGROUND:
					beacon_background = PWM_SLOW_BEACON_BACKGROUND;
					break;
				}
#endif
				// no break - fall through to beacon code
			case MODE_BEACON:
			case MODE_ALPINE_DISTRESS_BEACON:
				_delay_ms(50);
				PWM_LVL = beacon_background;

				_delay_ms(950);
				if(selected_pwm == MODE_ALPINE_DISTRESS_BEACON)
				{
					if(ii > 5)
					{
						_delay_ms(59000);
						ii = 255;
					}
					else
						_delay_ms(9000);
				}
				else if(selected_pwm == MODE_SLOW_BEACON_WITH_BACKGROUND)
					_delay_ms(1500);
#endif
				break;
			default:
				sleep_mode();
				break;
			}

			ii++; // Loop counter, used by multiple branches
		}
	}

#ifdef ENABLE_VOLTAGE_MONITORING
	//
	// Critically low voltage -> Turn off the light
	// 
		
	// Disable WDT so it doesn't wake us up from sleep
	WDT_off();

	// Would be nice to blink a couple of times with lowest brightness to notify the user, but not implemented due space restrictions

	// Turn the light off
	PWM_LVL = 0;

	// Disable ADC so it doesn't consume power
	ADC_off();

	// Power down as many components as possible
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);

	// Deep sleep until powered off - consumes ~110uA during the deep sleep
	while(1)
		sleep_mode();
#endif

    return 0; // Standard Return Code -> would return to idle loop with interrupts disabled.
}