Untitled diff
351 lines
/*
/*STAR Firmware 1.1 - Strobe Added (Use 254 as mode level for strobe, can be modified for beacon if wanted)
 * By JonnyC 
 * Free to use, modify, and share. 
 *
 * NANJG 105C Diagram
 * NANJG 105C Diagram
 *           ---
 *           ---
 *         -|   |- VCC
 *         -|   |- VCC
 *  Star 4 -|   |- Voltage ADC
 *  Star 4 -|   |- Voltage ADC
 *  Star 3 -|   |- PWM
 *  Star 3 -|   |- PWM
 *     GND -|   |- Star 2
 *     GND -|   |- Star 2
 *           ---
 *           ---
 * CPU speed is 4.8Mhz without the 8x divider when low fuse is 0x75
 * CPU speed is 4.8Mhz without the 8x divider when low fuse is 0x75
 *
 *
 * define F_CPU 4800000  CPU: 4.8MHz  PWM: 9.4kHz       ####### use low fuse: 0x75  #######
 * define F_CPU 4800000  CPU: 4.8MHz  PWM: 9.4kHz       ####### use low fuse: 0x75  #######
 *                             /8     PWM: 1.176kHz     ####### use low fuse: 0x65  #######
 *                             /8     PWM: 1.176kHz     ####### use low fuse: 0x65  #######
 * define F_CPU 9600000  CPU: 9.6MHz  PWM: 19kHz        ####### use low fuse: 0x7a  #######
 * define F_CPU 9600000  CPU: 9.6MHz  PWM: 19kHz        ####### use low fuse: 0x7a  #######
 *                             /8     PWM: 2.4kHz       ####### use low fuse: 0x6a  #######
 *                             /8     PWM: 2.4kHz       ####### use low fuse: 0x6a  #######
 * 
 * 
 * Above PWM speeds are for phase-correct PWM.  This program uses Fast-PWM, which when the CPU is 4.8MHz will be 18.75 kHz
 * Above PWM speeds are for phase-correct PWM.  This program uses Fast-PWM, which when the CPU is 4.8MHz will be 18.75 kHz
 *
 *
 * FUSES
 * FUSES
 *		I use these fuse settings
 *		I use these fuse settings
 *		Low:  0x75
 *		Low:  0x75
 *		High: 0xff
 *		High: 0xff
 *
 *
 * STARS
 * STARS
 *		Star 2 = Moon if connected
 *		Star 2 = Moon if connected
 *		Star 3 = H-L if connected, L-H if not
 *		Star 3 = H-L if connected, L-H if not
 *		Star 4 = Memory if not connected
 *		Star 4 = Memory if not connected
 *
 *
 * VOLTAGE
 * VOLTAGE
 *		Resistor values for voltage divider (reference BLF-VLD README for more info)
 *		Resistor values for voltage divider (reference BLF-VLD README for more info)
 *		Reference voltage can be anywhere from 1.0 to 1.2, so this cannot be all that accurate
 *		Reference voltage can be anywhere from 1.0 to 1.2, so this cannot be all that accurate
 *
 *
 *           VCC
 *           VCC
 *            |
 *            |
 *           Vd (~.25 v drop from protection diode)
 *           Vd (~.25 v drop from protection diode)
 *            |
 *            |
 *          1912 (R1 19,100 ohms)
 *          1912 (R1 19,100 ohms)
 *            |
 *            |
 *            |---- PB2 from MCU
 *            |---- PB2 from MCU
 *            |
 *            |
 *          4701 (R2 4,700 ohms)
 *          4701 (R2 4,700 ohms)
 *            |
 *            |
 *           GND
 *           GND
 *
 *
 *		ADC = ((V_bat - V_diode) * R2   * 255) / ((R1    + R2  ) * V_ref)
 *		ADC = ((V_bat - V_diode) * R2   * 255) / ((R1    + R2  ) * V_ref)
 *		125 = ((3.0   - .25    ) * 4700 * 255) / ((19100 + 4700) * 1.1  )
 *		125 = ((3.0   - .25    ) * 4700 * 255) / ((19100 + 4700) * 1.1  )
 *		121 = ((2.9   - .25    ) * 4700 * 255) / ((19100 + 4700) * 1.1  )
 *		121 = ((2.9   - .25    ) * 4700 * 255) / ((19100 + 4700) * 1.1  )
 *
 *
 *		Well 125 and 121 were too close, so it shut off right after lowering to low mode, so I went with
 *		Well 125 and 121 were too close, so it shut off right after lowering to low mode, so I went with
 *		130 and 120
 *		130 and 120
 *
 *
 *		To find out what value to use, plug in the target voltage (V) to this equation
 *		To find out what value to use, plug in the target voltage (V) to this equation
 *			value = (V * 4700 * 255) / (23800 * 1.1)
 *			value = (V * 4700 * 255) / (23800 * 1.1)
 *      
 *      
 */
 */
#define F_CPU 4800000UL
#define F_CPU 4800000UL
/*
/*
 * =========================================================================
 * =========================================================================
 * Settings to modify per driver
 * Settings to modify per driver
 * Strobe turns on when MODE_IDX==254, so 254 is your strobe mode
 */
 */
#define VOLTAGE_MON			// Comment out to disable
#define VOLTAGE_MON			// Comment out to disable
#define MODE_MOON			8	// Can comment out to remove mode, but should be set through soldering stars
#define MODE_MOON			8	// Can comment out to remove mode, but should be set through soldering stars
#define MODE_LOW			14  // Can comment out to remove mode
#define MODE_LOW			14  // Can comment out to remove mode
#define MODE_MED			39	// Can comment out to remove mode
#define MODE_MED			40	// Can comment out to remove mode
#define MODE_HIGH_W_TURBO	110	// MODE_HIGH value when turbo is enabled
#define MODE_HIGH_W_TURBO	100	// MODE_HIGH value when turbo is enabled
#define MODE_HIGH			120	// Can comment out to remove mode
#define MODE_HIGH			255	// Can comment out to remove mode
#define MODE_TURBO			255	// Can comment out to remove mode
#define MODE_TURBO			255	// Can comment out to remove mode
#define TURBO_TIMEOUT		240 // How many WTD ticks before before dropping down (.5 sec each)
#define TURBO_TIMEOUT		240 // How many WTD ticks before before dropping down (.5 sec each)
#define WDT_TIMEOUT			2	// Number of WTD ticks before mode is saved (.5 sec each)
#define WDT_TIMEOUT			2	// Number of WTD ticks before mode is saved (.5 sec each)
#define ADC_LOW				130	// When do we start ramping
#define ADC_LOW				130	// When do we start ramping
#define ADC_CRIT			120 // When do we shut the light off
#define ADC_CRIT			120 // When do we shut the light off
/*
/*
 * =========================================================================
 * =========================================================================
 */
 */
#ifdef MODE_TURBO
#ifdef MODE_TURBO
#undef  MODE_HIGH
#undef  MODE_HIGH
#define MODE_HIGH	MODE_HIGH_W_TURBO
#define MODE_HIGH	MODE_HIGH_W_TURBO
#endif
#endif
//#include <avr/pgmspace.h>
//#include <avr/pgmspace.h>
#include <avr/io.h>
#include <avr/io.h>
#include <util/delay.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>	
#include <avr/wdt.h>	
#include <avr/eeprom.h>
#include <avr/eeprom.h>
#include <avr/sleep.h>
#include <avr/sleep.h>
//#include <avr/power.h>
//#include <avr/power.h>
#define STAR2_PIN   PB0
#define STAR2_PIN   PB0
#define STAR3_PIN   PB4
#define STAR3_PIN   PB4
#define STAR4_PIN   PB3
#define STAR4_PIN   PB3
#define PWM_PIN     PB1
#define PWM_PIN     PB1
#define VOLTAGE_PIN PB2
#define VOLTAGE_PIN PB2
#define ADC_CHANNEL 0x01	// MUX 01 corresponds with PB2
#define ADC_CHANNEL 0x01	// MUX 01 corresponds with PB2
#define ADC_DIDR 	ADC1D	// Digital input disable bit corresponding with PB2
#define ADC_DIDR 	ADC1D	// Digital input disable bit corresponding with PB2
#define ADC_PRSCL   0x06	// clk/64
#define ADC_PRSCL   0x06	// clk/64
#define PWM_LVL		OCR0B	// OCR0B is the output compare register for PB1
#define PWM_LVL		OCR0B	// OCR0B is the output compare register for PB1
/*
/*
 * global variables
 * global variables
 */
 */
// Mode storage
// Mode storage
uint8_t eepos = 0;
uint8_t eepos = 0;
uint8_t eep[32];
uint8_t eep[32];
uint8_t memory = 0;
uint8_t memory = 0;
// Modes (gets set when the light starts up based on stars)
// Modes (gets set when the light starts up based on stars)
static uint8_t modes[10];  // Don't need 10, but keeping it high enough to handle all
static uint8_t modes[10];  // Don't need 10, but keeping it high enough to handle all
volatile uint8_t mode_idx = 0;
volatile uint8_t mode_idx = 0;
int     mode_dir = 0; // 1 or -1. Determined when checking stars. Do we increase or decrease the idx when moving up to a higher mode.
int     mode_dir = 0; // 1 or -1. Determined when checking stars. Do we increase or decrease the idx when moving up to a higher mode.
uint8_t mode_cnt = 0;
uint8_t mode_cnt = 0;
uint8_t lowbatt_cnt = 0;
uint8_t lowbatt_cnt = 0;
void store_mode_idx(uint8_t lvl) {  //central method for writing (with wear leveling)
void store_mode_idx(uint8_t lvl) {  //central method for writing (with wear leveling)
	uint8_t oldpos=eepos;
	uint8_t oldpos=eepos;
	eepos=(eepos+1)&31;  //wear leveling, use next cell
	eepos=(eepos+1)&31;  //wear leveling, use next cell
	// Write the current mode
	// Write the current mode
	EEARL=eepos;  EEDR=lvl; EECR=32+4; EECR=32+4+2;  //WRITE  //32:write only (no erase)  4:enable  2:go
	EEARL=eepos;  EEDR=lvl; EECR=32+4; EECR=32+4+2;  //WRITE  //32:write only (no erase)  4:enable  2:go
	while(EECR & 2); //wait for completion
	while(EECR & 2); //wait for completion
	// Erase the last mode
	// Erase the last mode
	EEARL=oldpos;           EECR=16+4; EECR=16+4+2;  //ERASE  //16:erase only (no write)  4:enable  2:go
	EEARL=oldpos;           EECR=16+4; EECR=16+4+2;  //ERASE  //16:erase only (no write)  4:enable  2:go
}
}
inline void read_mode_idx() {
inline void read_mode_idx() {
	eeprom_read_block(&eep, 0, 32);
	eeprom_read_block(&eep, 0, 32);
	while((eep[eepos] == 0xff) && (eepos < 32)) eepos++;
	while((eep[eepos] == 0xff) && (eepos < 32)) eepos++;
	if (eepos < 32) mode_idx = eep[eepos];//&0x10; What the?
	if (eepos < 32) mode_idx = eep[eepos];//&0x10; What the?
	else eepos=0;
	else eepos=0;
}
}
inline void next_mode() {
inline void next_mode() {
	if (mode_idx == 0 && mode_dir == -1) {
	if (mode_idx == 0 && mode_dir == -1) {
		// Wrap around
		// Wrap around
		mode_idx = mode_cnt - 1;
		mode_idx = mode_cnt - 1;
	} else {
	} else {
		mode_idx += mode_dir;
		mode_idx += mode_dir;
		if (mode_idx > (mode_cnt - 1)) {
		if (mode_idx > (mode_cnt - 1)) {
			// Wrap around
			// Wrap around
			mode_idx = 0;
			mode_idx = 0;
		}
		}
	}
	}
}
}
inline void WDT_on() {
inline void WDT_on() {
	// Setup watchdog timer to only interrupt, not reset, every 500ms.
	// Setup watchdog timer to only interrupt, not reset, every 500ms.
	cli();							// Disable interrupts
	cli();							// Disable interrupts
	wdt_reset();					// Reset the WDT
	wdt_reset();					// Reset the WDT
	WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
	WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
	WDTCR = (1<<WDTIE) | (1<<WDP2) | (1<<WDP0); // Enable interrupt every 500ms
	WDTCR = (1<<WDTIE) | (1<<WDP2) | (1<<WDP0); // Enable interrupt every 500ms
	sei();							// Enable interrupts
	sei();							// Enable interrupts
}
}
inline void WDT_off()
inline void WDT_off()
{
{
	cli();							// Disable interrupts
	cli();							// Disable interrupts
	wdt_reset();					// Reset the WDT
	wdt_reset();					// Reset the WDT
	MCUSR &= ~(1<<WDRF);			// Clear Watchdog reset flag
	MCUSR &= ~(1<<WDRF);			// Clear Watchdog reset flag
	WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
	WDTCR |= (1<<WDCE) | (1<<WDE);  // Start timed sequence
	WDTCR = 0x00;					// Disable WDT
	WDTCR = 0x00;					// Disable WDT
	sei();							// Enable interrupts
	sei();							// Enable interrupts
}
}
inline void ADC_on() {
inline void ADC_on() {
	ADMUX  = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
	ADMUX  = (1 << REFS0) | (1 << ADLAR) | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
    DIDR0 |= (1 << ADC_DIDR);							// disable digital input on ADC pin to reduce power consumption
    DIDR0 |= (1 << ADC_DIDR);							// disable digital input on ADC pin to reduce power consumption
	ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
	ADCSRA = (1 << ADEN ) | (1 << ADSC ) | ADC_PRSCL;   // enable, start, prescale
}
}
inline void ADC_off() {
inline void ADC_off() {
	ADCSRA &= ~(1<<7); //ADC off
	ADCSRA &= ~(1<<7); //ADC off
}
}
#ifdef VOLTAGE_MON
#ifdef VOLTAGE_MON
uint8_t low_voltage(uint8_t voltage_val) {
uint8_t low_voltage(uint8_t voltage_val) {
	// Start conversion
	// Start conversion
	ADCSRA |= (1 << ADSC);
	ADCSRA |= (1 << ADSC);
	// Wait for completion
	// Wait for completion
	while (ADCSRA & (1 << ADSC));
	while (ADCSRA & (1 << ADSC));
	// See if voltage is lower than what we were looking for
	// See if voltage is lower than what we were looking for
	if (ADCH < voltage_val) {
	if (ADCH < voltage_val) {
		// See if it's been low for a while
		// See if it's been low for a while
		if (++lowbatt_cnt > 8) {
		if (++lowbatt_cnt > 8) {
			lowbatt_cnt = 0;
			lowbatt_cnt = 0;
			return 1;
			return 1;
		}
		}
	} else {
	} else {
		lowbatt_cnt = 0;
		lowbatt_cnt = 0;
	}
	}
	return 0;
	return 0;
}
}
#endif
#endif
ISR(WDT_vect) {
ISR(WDT_vect) {
	static uint8_t ticks = 0;
	static uint8_t ticks = 0;
	if (ticks < 255) ticks++;
	if (ticks < 255) ticks++;
	if (ticks == WDT_TIMEOUT) {
	if (ticks == WDT_TIMEOUT) {
		if (memory) {
		if (memory) {
			store_mode_idx(mode_idx);
			store_mode_idx(mode_idx);
		} else {
		} else {
			// Reset the mode to the start for next time
			// Reset the mode to the start for next time
			store_mode_idx((mode_dir == 1) ? 0 : (mode_cnt - 1));
			store_mode_idx((mode_dir == 1) ? 0 : (mode_cnt - 1));
		}
		}
#ifdef MODE_TURBO	
#ifdef MODE_TURBO	
	//} else if (ticks == TURBO_TIMEOUT && modes[mode_idx] == MODE_TURBO) { // Doesn't make any sense why this doesn't work
	//} else if (ticks == TURBO_TIMEOUT && modes[mode_idx] == MODE_TURBO) { // Doesn't make any sense why this doesn't work
	} else if (ticks == TURBO_TIMEOUT && mode_idx == (mode_cnt - 1)) {
	} else if (ticks == TURBO_TIMEOUT && mode_idx == (mode_cnt - 1)) {
		// Turbo mode is always at end
		// Turbo mode is always at end
		PWM_LVL = modes[--mode_idx];
		PWM_LVL = modes[--mode_idx];
#endif
#endif
	}
	}
}
}
int main(void)
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)
	// 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);
	PORTB = (1 << STAR2_PIN) | (1 << STAR3_PIN) | (1 << STAR4_PIN);
    // Set PWM pin to output
    // Set PWM pin to output
    DDRB = (1 << PWM_PIN);
    DDRB = (1 << PWM_PIN);
    // Set timer to do PWM for correct output pin and set prescaler timing
    // 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
    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...)
    TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...)
	// Turn features on or off as needed
	// Turn features on or off as needed
	#ifdef VOLTAGE_MON
	#ifdef VOLTAGE_MON
	ADC_on();
	ADC_on();
	#else
	#else
	ADC_off();
	ADC_off();
	#endif
	#endif
	ACSR   |=  (1<<7); //AC off
	ACSR   |=  (1<<7); //AC off
	// Load up the modes based on stars
	// Load up the modes based on stars
	// Always load up the modes array in order of lowest to highest mode
	// Always load up the modes array in order of lowest to highest mode
	// 0 being low for soldered, 1 for pulled-up for not soldered
	// 0 being low for soldered, 1 for pulled-up for not soldered
	// Moon
	// Moon
	#ifdef MODE_MOON
	#ifdef MODE_MOON
	if ((PINB & (1 << STAR2_PIN)) == 0) {
	if ((PINB & (1 << STAR2_PIN)) == 0) {
		modes[mode_cnt++] = MODE_MOON;
		modes[mode_cnt++] = MODE_MOON;
	}
	}
	#endif
	#endif
	#ifdef MODE_LOW
	#ifdef MODE_LOW
	modes[mode_cnt++] = MODE_LOW;
	modes[mode_cnt++] = MODE_LOW;
	#endif
	#endif
	#ifdef MODE_MED
	#ifdef MODE_MED
	modes[mode_cnt++] = MODE_MED;
	modes[mode_cnt++] = MODE_MED;
	#endif
	#endif
	#ifdef MODE_HIGH
	#ifdef MODE_HIGH
	modes[mode_cnt++] = MODE_HIGH;
	modes[mode_cnt++] = MODE_HIGH;
	#endif
	#endif
	#ifdef MODE_TURBO
	#ifdef MODE_TURBO
	modes[mode_cnt++] = MODE_TURBO;
	modes[mode_cnt++] = MODE_TURBO;
	#endif
	#endif
	if ((PINB & (1 << STAR3_PIN)) == 0) {
	if ((PINB & (1 << STAR3_PIN)) == 0) {
		// High to Low
		// High to Low
		mode_dir = -1;
		mode_dir = -1;
	} else {
	} else {
		mode_dir = 1;
		mode_dir = 1;
	}
	}
	// Not soldered (1) should enable memory
	// Not soldered (1) should enable memory
	memory = ((PINB & (1 << STAR4_PIN)) > 0) ? 1 : 0;
	memory = ((PINB & (1 << STAR4_PIN)) > 0) ? 1 : 0;
	// Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
	// Enable sleep mode set to Idle that will be triggered by the sleep_mode() command.
	// Will allow us to go idle between WDT interrupts
	// Will allow us to go idle between WDT interrupts
	set_sleep_mode(SLEEP_MODE_IDLE);
	set_sleep_mode(SLEEP_MODE_IDLE);
	// Determine what mode we should fire up
	// Determine what mode we should fire up
	// Read the last mode that was saved
	// Read the last mode that was saved
	read_mode_idx();
	read_mode_idx();
	if (mode_idx&0x10) {
	if (mode_idx&0x10) {
		// Indicates we did a short press last time, go to the next mode
		// Indicates we did a short press last time, go to the next mode
		// Remove short press indicator first
		// Remove short press indicator first
		mode_idx &= 0x0f;
		mode_idx &= 0x0f;
		next_mode(); // Will handle wrap arounds
		next_mode(); // Will handle wrap arounds
	} else {
	} else {
		// Didn't have a short press, keep the same mode
		// Didn't have a short press, keep the same mode
	}
	}
	// Store mode with short press indicator
	// Store mode with short press indicator
	store_mode_idx(mode_idx|0x10);
	store_mode_idx(mode_idx|0x10);
	WDT_on();
	WDT_on();
	// Now just fire up the mode
	// Now just fire up the mode
	PWM_LVL = modes[mode_idx];
	//mode_idx==254 is the Strobe Mode
	if (modes[mode_idx]==254) {
  while (1) {
    PWM_LVL = 255;
    _delay_ms(20);
    PWM_LVL=0;
    _delay_ms(60);
	//Can modify these values to change strobe frequency, change to beacon, etc.
  }
} else {
  PWM_LVL = modes[mode_idx];
}
	uint8_t i = 0;
	uint8_t i = 0;
	uint8_t hold_pwm;
	uint8_t hold_pwm;
	while(1) {
	while(1) {
	#ifdef VOLTAGE_MON
	#ifdef VOLTAGE_MON
		if (low_voltage(ADC_LOW)) {
		if (low_voltage(ADC_LOW)) {
			// We need to go to a lower level
			// We need to go to a lower level
			if (mode_idx == 0 && PWM_LVL <= modes[mode_idx]) {
			if (mode_idx == 0 && PWM_LVL <= modes[mode_idx]) {
				// Can't go any lower than the lowest mode
				// Can't go any lower than the lowest mode
				// Wait until we hit the critical level before flashing 10 times and turning off
				// Wait until we hit the critical level before flashing 10 times and turning off
				while (!low_voltage(ADC_CRIT));
				while (!low_voltage(ADC_CRIT));
				i = 0;
				i = 0;
				while (i++<10) {
				while (i++<10) {
					PWM_LVL = 0;
					PWM_LVL = 0;
					_delay_ms(250);
					_delay_ms(250);
					PWM_LVL = modes[0];
					PWM_LVL = modes[0];
					_delay_ms(500);
					_delay_ms(500);
				}
				}
				// Turn off the light
				// Turn off the light
				PWM_LVL = 0;
				PWM_LVL = 0;
				// Disable WDT so it doesn't wake us up
				// Disable WDT so it doesn't wake us up
				WDT_off();
				WDT_off();
				// Power down as many components as possible
				// Power down as many components as possible
				set_sleep_mode(SLEEP_MODE_PWR_DOWN);
				set_sleep_mode(SLEEP_MODE_PWR_DOWN);
				sleep_mode();
				sleep_mode();
			} else {
			} else {
				// Flash 3 times before lowering
				// Flash 3 times before lowering
				hold_pwm = PWM_LVL;
				hold_pwm = PWM_LVL;
				i = 0;
				i = 0;
				while (i++<3) {
				while (i++<3) {
					PWM_LVL = 0;
					PWM_LVL = 0;
					_delay_ms(250);
					_delay_ms(250);
					PWM_LVL = hold_pwm;
					PWM_LVL = hold_pwm;
					_delay_ms(500);
					_delay_ms(500);
				}
				}
				// Lower the mode by half, but don't go below lowest level
				// Lower the mode by half, but don't go below lowest level
				if ((PWM_LVL >> 1) < modes[0]) {
				if ((PWM_LVL >> 1) < modes[0]) {
					PWM_LVL = modes[0];
					PWM_LVL = modes[0];
					mode_idx = 0;
					mode_idx = 0;
				} else {					
				} else {					
					PWM_LVL = (PWM_LVL >> 1);
					PWM_LVL = (PWM_LVL >> 1);
				}					
				}					
				// See if we should change the current mode level if we've gone under the current mode.
				// See if we should change the current mode level if we've gone under the current mode.
				if (PWM_LVL < modes[mode_idx]) {
				if (PWM_LVL < modes[mode_idx]) {
					// Lower our recorded mode
					// Lower our recorded mode
					mode_idx--;
					mode_idx--;
				}
				}
			}
			}
			// Wait 3 seconds before lowering the level again
			// Wait 3 seconds before lowering the level again
			_delay_ms(3000);
			_delay_ms(3000);
		}
		}
	#endif
	#endif
		sleep_mode();
		sleep_mode();
	}
	}
    return 0; // Standard Return Code
    return 0; // Standard Return Code
}
}