From af90d238d4cfbbe0c611a88dd96c05a47079e45e Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Fri, 13 Jun 2014 13:54:12 +0200 Subject: [PATCH] Start of example conversion. Added sleep to MySensors API. --- .../idleWakePeriodic/idleWakePeriodic.ino | 31 + .../powerDownWakeExternalInterrupt.ino | 33 + .../powerDownWakePeriodic.ino | 16 + libraries/LowPower/LowPower.cpp | 856 ++++++++++++++++++ libraries/LowPower/LowPower.h | 137 +++ libraries/LowPower/keywords.txt | 68 ++ libraries/MySensors/LowPower.cpp | 856 ++++++++++++++++++ libraries/MySensors/LowPower.h | 137 +++ libraries/MySensors/MySensor.cpp | 45 +- libraries/MySensors/MySensor.h | 21 +- .../BatteryPoweredSensor.ino | 18 +- .../BinarySwitchSensor/BinarySwitchSensor.ino | 11 +- .../DallasTemperatureSensor.ino | 8 +- .../DistanceSensor/DistanceSensor.ino | 23 +- .../EnergyMeterPulseSensor.ino | 60 +- .../HumiditySensor/HumiditySensor.ino | 32 +- .../MySensors/examples/IrSensor/IrSensor.ino | 42 +- .../LightLuxSensor/LightLuxSensor.ino | 23 +- .../examples/LightSensor/LightSensor.ino | 20 +- .../examples/MotionSensor/MotionSensor.ino | 15 +- .../PressureSensor/PressureSensor.ino | 35 +- .../examples/RelayActuator/RelayActuator.ino | 1 + .../RelayWithButtonActuator.ino | 91 +- .../examples/RelayingNode/RelayingNode.ino | 15 +- .../examples/ServoActuator/ServoActuator.ino | 7 +- 25 files changed, 2377 insertions(+), 224 deletions(-) create mode 100644 libraries/LowPower/Examples/idleWakePeriodic/idleWakePeriodic.ino create mode 100644 libraries/LowPower/Examples/powerDownWakeExternalInterrupt/powerDownWakeExternalInterrupt.ino create mode 100644 libraries/LowPower/Examples/powerDownWakePeriodic/powerDownWakePeriodic.ino create mode 100644 libraries/LowPower/LowPower.cpp create mode 100644 libraries/LowPower/LowPower.h create mode 100644 libraries/LowPower/keywords.txt create mode 100644 libraries/MySensors/LowPower.cpp create mode 100644 libraries/MySensors/LowPower.h diff --git a/libraries/LowPower/Examples/idleWakePeriodic/idleWakePeriodic.ino b/libraries/LowPower/Examples/idleWakePeriodic/idleWakePeriodic.ino new file mode 100644 index 0000000..e93072d --- /dev/null +++ b/libraries/LowPower/Examples/idleWakePeriodic/idleWakePeriodic.ino @@ -0,0 +1,31 @@ +// **** INCLUDES ***** +#include "LowPower.h" + +void setup() +{ + // No setup is required for this library +} + +void loop() +{ + // Enter idle state for 8 s with the rest of peripherals turned off + // Each microcontroller comes with different number of peripherals + // Comment off line of code where necessary + + // ATmega328P, ATmega168 + LowPower.idle(SLEEP_8S, ADC_OFF, TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, + SPI_OFF, USART0_OFF, TWI_OFF); + + // ATmega32U4 + //LowPower.idle(SLEEP_8S, ADC_OFF, TIMER4_OFF, TIMER3_OFF, TIMER1_OFF, + // TIMER0_OFF, SPI_OFF, USART1_OFF, TWI_OFF, USB_OFF); + + // ATmega2560 + //LowPower.idle(SLEEP_8S, ADC_OFF, TIMER5_OFF, TIMER4_OFF, TIMER3_OFF, + // TIMER2_OFF, TIMER1_OFF, TIMER0_OFF, SPI_OFF, USART3_OFF, + // USART2_OFF, USART1_OFF, USART0_OFF, TWI_OFF); + + // Do something here + // Example: Read sensor, data logging, data transmission. +} + diff --git a/libraries/LowPower/Examples/powerDownWakeExternalInterrupt/powerDownWakeExternalInterrupt.ino b/libraries/LowPower/Examples/powerDownWakeExternalInterrupt/powerDownWakeExternalInterrupt.ino new file mode 100644 index 0000000..f914bd6 --- /dev/null +++ b/libraries/LowPower/Examples/powerDownWakeExternalInterrupt/powerDownWakeExternalInterrupt.ino @@ -0,0 +1,33 @@ +// **** INCLUDES ***** +#include "LowPower.h" + +// Use pin 2 as wake up pin +const int wakeUpPin = 2; + +void wakeUp() +{ + // Just a handler for the pin interrupt. +} + +void setup() +{ + // Configure wake up pin as input. + // This will consumes few uA of current. + pinMode(wakeUpPin, INPUT); +} + +void loop() +{ + // Allow wake up pin to trigger interrupt on low. + attachInterrupt(0, wakeUp, LOW); + + // Enter power down state with ADC and BOD module disabled. + // Wake up when wake up pin is low. + LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); + + // Disable external pin interrupt on wake up pin. + detachInterrupt(0); + + // Do something here + // Example: Read sensor, data logging, data transmission. +} diff --git a/libraries/LowPower/Examples/powerDownWakePeriodic/powerDownWakePeriodic.ino b/libraries/LowPower/Examples/powerDownWakePeriodic/powerDownWakePeriodic.ino new file mode 100644 index 0000000..bce822a --- /dev/null +++ b/libraries/LowPower/Examples/powerDownWakePeriodic/powerDownWakePeriodic.ino @@ -0,0 +1,16 @@ +// **** INCLUDES ***** +#include "LowPower.h" + +void setup() +{ + // No setup is required for this library +} + +void loop() +{ + // Enter power down state for 8 s with ADC and BOD module disabled + LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); + + // Do something here + // Example: Read sensor, data logging, data transmission. +} diff --git a/libraries/LowPower/LowPower.cpp b/libraries/LowPower/LowPower.cpp new file mode 100644 index 0000000..a72cc31 --- /dev/null +++ b/libraries/LowPower/LowPower.cpp @@ -0,0 +1,856 @@ +/******************************************************************************* +* LowPower Library +* Version: 1.30 +* Date: 22-05-2013 +* Company: Rocket Scream Electronics +* Website: www.rocketscream.com +* +* This is a lightweight low power library for Arduino. Please check our wiki +* (www.rocketscream.com/wiki) for more information on using this piece of +* library. +* +* This library is licensed under Creative Commons Attribution-ShareAlike 3.0 +* Unported License. +* +* Revision Description +* ======== =========== +* 1.30 Added support for ATMega168, ATMega2560, ATMega1280 & ATMega32U4. +* Tested to work with Arduino IDE 1.0.1 - 1.0.4. +* 1.20 Remove typo error in idle method for checking whether Timer 0 was +* turned off. +* Remove dependecy on WProgram.h which is not required. +* Tested to work with Arduino IDE 1.0. +* 1.10 Added #ifndef for sleep_bod_disable() for compatibility with future +* Arduino IDE release. +* 1.00 Initial public release. +*******************************************************************************/ +#include +#include +#include +#include +#include "LowPower.h" + +// Only Pico Power devices can change BOD settings through software +#if defined __AVR_ATmega328P__ +#ifndef sleep_bod_disable +#define sleep_bod_disable() \ +do { \ + unsigned char tempreg; \ + __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \ + "ori %[tempreg], %[bods_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" "\n\t" \ + "andi %[tempreg], %[not_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" \ + : [tempreg] "=&d" (tempreg) \ + : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \ + [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \ + [not_bodse] "i" (~_BV(BODSE))); \ +} while (0) +#endif +#endif + +#define lowPowerBodOn(mode) \ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); + +// Only Pico Power devices can change BOD settings through software +#if defined __AVR_ATmega328P__ +#define lowPowerBodOff(mode)\ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sleep_bod_disable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); +#endif + +// Some macros is still missing from AVR GCC distribution for ATmega32U4 +#if defined __AVR_ATmega32U4__ + // Timer 4 PRR bit is currently not defined in iom32u4.h + #ifndef PRTIM4 + #define PRTIM4 4 + #endif + + // Timer 4 power reduction macro is not defined currently in power.h + #ifndef power_timer4_disable + #define power_timer4_disable() (PRR1 |= (uint8_t)(1 << PRTIM4)) + #endif + + #ifndef power_timer4_enable + #define power_timer4_enable() (PRR1 &= (uint8_t)~(1 << PRTIM4)) + #endif +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega328P/168 into idle state. Please make sure you +* understand the implication and result of disabling module. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 4. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 5. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 6. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 7. usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 8. twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) +void LowPowerClass::idle(period_t period, adc_t adc, timer2_t timer2, + timer1_t timer1, timer0_t timer0, + spi_t spi, usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega32U4 into idle state. Please make sure you +* understand the implication and result of disabling module. +* Take note that Timer 2 is not available and USART0 +* is replaced with USART1 on ATmega32U4. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 4. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 5. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 6. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 7. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 8. usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 9. twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +* 10.usb USB module disable control: +* (a) USB_OFF - Turn off USB module +* (b) USB_ON - Leave USB module in its default state +*******************************************************************************/ +#if defined __AVR_ATmega32U4__ +void LowPowerClass::idle(period_t period, adc_t adc, + timer4_t timer4, timer3_t timer3, + timer1_t timer1, timer0_t timer0, + spi_t spi, usart1_t usart1, twi_t twi, usb_t usb) +{ + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (twi == TWI_OFF) power_twi_disable(); + if (usb == USB_OFF) power_usb_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (twi == TWI_OFF) power_twi_enable(); + if (usb == USB_OFF) power_usb_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega2560 & ATmega1280 into idle state. Please make sure +* you understand the implication and result of disabling module. +* Take note that extra Timer 5, 4, 3 compared to an ATmega328P/168. +* Also take note that extra USART 3, 2, 1 compared to an +* ATmega328P/168. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer5 Timer 5 module disable control: +* (a) TIMER5_OFF - Turn off Timer 5 module +* (b) TIMER5_ON - Leave Timer 5 module in its default state +* +* 4. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 5. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 6. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 7. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 8. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 9. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 10.usart3 USART3 module disable control: +* (a) USART3_OFF - Turn off USART3 module +* (b) USART3_ON - Leave USART3 module in its default state +* +* 11.usart2 USART2 module disable control: +* (a) USART2_OFF - Turn off USART2 module +* (b) USART2_ON - Leave USART2 module in its default state +* +* 12.usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 13.usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 14.twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega2560__) || defined (__AVR_ATmega1280__) +void LowPowerClass::idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart3_t usart3, usart2_t usart2, usart1_t usart1, + usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_disable(); + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart3 == USART3_OFF) power_usart3_disable(); + if (usart2 == USART2_OFF) power_usart2_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_enable(); + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart3 == USART3_OFF) power_usart3_enable(); + if (usart2 == USART2_OFF) power_usart2_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + +/******************************************************************************* +* Name: adcNoiseReduction +* Description: Putting microcontroller into ADC noise reduction state. This is +* a very useful state when using the ADC to achieve best and low +* noise signal. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. Turning off the ADC module is +* basically removing the purpose of this low power mode. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::adcNoiseReduction(period_t period, adc_t adc, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_ADC); + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + } + #endif +} + +/******************************************************************************* +* Name: powerDown +* Description: Putting microcontroller into power down state. This is +* the lowest current consumption state. Use this together with +* external pin interrupt to wake up through external event +* triggering (example: RTC clockout pin, SD card detect pin). +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. Turning off the ADC module is +* basically removing the purpose of this low power mode. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. bod Brown Out Detector (BOD) module disable control: +* (a) BOD_OFF - Turn off BOD module +* (b) BOD_ON - Leave BOD module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerDown(period_t period, adc_t adc, bod_t bod) +{ + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + if (bod == BOD_OFF) + { + #if defined __AVR_ATmega328P__ + lowPowerBodOff(SLEEP_MODE_PWR_DOWN); + #else + lowPowerBodOn(SLEEP_MODE_PWR_DOWN); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_PWR_DOWN); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); +} + +/******************************************************************************* +* Name: powerSave +* Description: Putting microcontroller into power save state. This is +* the lowest current consumption state after power down. +* Use this state together with an external 32.768 kHz crystal (but +* 8/16 MHz crystal/resonator need to be removed) to provide an +* asynchronous clock source to Timer 2. Please take note that +* Timer 2 is also used by the Arduino core for PWM operation. +* Please refer to wiring.c for explanation. Removal of the external +* 8/16 MHz crystal/resonator requires the microcontroller to run +* on its internal RC oscillator which is not so accurate for time +* critical operation. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. Turning off the ADC module is +* basically removing the purpose of this low power mode. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. bod Brown Out Detector (BOD) module disable control: +* (a) BOD_OFF - Turn off BOD module +* (b) BOD_ON - Leave BOD module in its default state +* +* 4. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerSave(period_t period, adc_t adc, bod_t bod, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + if (bod == BOD_OFF) + { + #if defined __AVR_ATmega328P__ + lowPowerBodOff(SLEEP_MODE_PWR_SAVE); + #else + lowPowerBodOn(SLEEP_MODE_PWR_SAVE); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_PWR_SAVE); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + } + #endif +} + +/******************************************************************************* +* Name: powerStandby +* Description: Putting microcontroller into power standby state. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. Turning off the ADC module is +* basically removing the purpose of this low power mode. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. bod Brown Out Detector (BOD) module disable control: +* (a) BOD_OFF - Turn off BOD module +* (b) BOD_ON - Leave BOD module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerStandby(period_t period, adc_t adc, bod_t bod) +{ + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + if (bod == BOD_OFF) + { + #if defined __AVR_ATmega328P__ + lowPowerBodOff(SLEEP_MODE_STANDBY); + #else + lowPowerBodOn(SLEEP_MODE_STANDBY); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_STANDBY); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); +} + +/******************************************************************************* +* Name: powerExtStandby +* Description: Putting microcontroller into power extended standby state. This +* is different from the power standby state as it has the +* capability to run Timer 2 asynchronously. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. bod Brown Out Detector (BOD) module disable control: +* (a) BOD_OFF - Turn off BOD module +* (b) BOD_ON - Leave BOD module in its default state +* +* 4. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerExtStandby(period_t period, adc_t adc, bod_t bod, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + if (bod == BOD_OFF) + { + #if defined __AVR_ATmega328P__ + lowPowerBodOff(SLEEP_MODE_EXT_STANDBY); + #else + lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + } + #endif +} + +/******************************************************************************* +* Name: ISR (WDT_vect) +* Description: Watchdog Timer interrupt service routine. This routine is +* required to allow automatic WDIF and WDIE bit clearance in +* hardware. +* +*******************************************************************************/ +ISR (WDT_vect) +{ + // WDIE & WDIF is cleared in hardware upon entering this ISR + wdt_disable(); +} + +LowPowerClass LowPower; \ No newline at end of file diff --git a/libraries/LowPower/LowPower.h b/libraries/LowPower/LowPower.h new file mode 100644 index 0000000..ef05901 --- /dev/null +++ b/libraries/LowPower/LowPower.h @@ -0,0 +1,137 @@ +#ifndef LowPower_h +#define LowPower_h + +enum period_t +{ + SLEEP_15Ms, + SLEEP_30MS, + SLEEP_60MS, + SLEEP_120MS, + SLEEP_250MS, + SLEEP_500MS, + SLEEP_1S, + SLEEP_2S, + SLEEP_4S, + SLEEP_8S, + SLEEP_FOREVER +}; + +enum bod_t +{ + BOD_OFF, + BOD_ON +}; + +enum adc_t +{ + ADC_OFF, + ADC_ON +}; + +enum timer5_t +{ + TIMER5_OFF, + TIMER5_ON +}; + +enum timer4_t +{ + TIMER4_OFF, + TIMER4_ON +}; + +enum timer3_t +{ + TIMER3_OFF, + TIMER3_ON +}; + +enum timer2_t +{ + TIMER2_OFF, + TIMER2_ON +}; + +enum timer1_t +{ + TIMER1_OFF, + TIMER1_ON +}; + +enum timer0_t +{ + TIMER0_OFF, + TIMER0_ON +}; + +enum spi_t +{ + SPI_OFF, + SPI_ON +}; + +enum usart0_t +{ + USART0_OFF, + USART0_ON +}; + +enum usart1_t +{ + USART1_OFF, + USART1_ON +}; + +enum usart2_t +{ + USART2_OFF, + USART2_ON +}; + +enum usart3_t +{ + USART3_OFF, + USART3_ON +}; + +enum twi_t +{ + TWI_OFF, + TWI_ON +}; + +enum usb_t +{ + USB_OFF, + USB_ON +}; + +class LowPowerClass +{ + public: + #if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) + void idle(period_t period, adc_t adc, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega2560__ + void idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart3_t usart3, usart2_t usart2, usart1_t usart1, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega32U4__ + void idle(period_t period, adc_t adc, timer4_t timer4, timer3_t timer3, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart1_t usart1, twi_t twi, usb_t usb); + #else + #error "Please ensure chosen MCU is either 328P, 32U4 or 2560." + #endif + void adcNoiseReduction(period_t period, adc_t adc, timer2_t timer2); + void powerDown(period_t period, adc_t adc, bod_t bod); + void powerSave(period_t period, adc_t adc, bod_t bod, timer2_t timer2); + void powerStandby(period_t period, adc_t adc, bod_t bod); + void powerExtStandby(period_t period, adc_t adc, bod_t bod, timer2_t timer2); +}; + +extern LowPowerClass LowPower; +#endif \ No newline at end of file diff --git a/libraries/LowPower/keywords.txt b/libraries/LowPower/keywords.txt new file mode 100644 index 0000000..ef2461c --- /dev/null +++ b/libraries/LowPower/keywords.txt @@ -0,0 +1,68 @@ +####################################### +# Syntax Coloring Map LowPower +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +idle KEYWORD2 +adcNoiseReduction KEYWORD2 +powerDown KEYWORD2 +powerSave KEYWORD2 +powerStandby KEYWORD2 +powerExtStandby KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +LowPower KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +SLEEP_15MS LITERAL1 +SLEEP_30MS LITERAL1 +SLEEP_60MS LITERAL1 +SLEEP_120MS LITERAL1 +SLEEP_250MS LITERAL1 +SLEEP_500MS LITERAL1 +SLEEP_1S LITERAL1 +SLEEP_2S LITERAL1 +SLEEP_4S LITERAL1 +SLEEP_8S LITERAL1 +SLEEP_FOREVER LITERAL1 +ADC_OFF LITERAL1 +ADC_ON LITERAL1 +BOD_OFF LITERAL1 +BOD_ON LITERAL1 +TIMER4_OFF LITERAL1 +TIMER4_ON LITERAL1 +TIMER3_OFF LITERAL1 +TIMER3_ON LITERAL1 +TIMER2_OFF LITERAL1 +TIMER2_ON LITERAL1 +TIMER1_OFF LITERAL1 +TIMER1_ON LITERAL1 +TIMER0_OFF LITERAL1 +TIMER0_ON LITERAL1 +USART3_OFF LITERAL1 +USART3_ON LITERAL1 +USART2_OFF LITERAL1 +USART2_ON LITERAL1 +USART1_OFF LITERAL1 +USART1_ON LITERAL1 +USART0_OFF LITERAL1 +USART0_ON LITERAL1 +SPI_OFF LITERAL1 +SPI_ON LITERAL1 +TWI_OFF LITERAL1 +TWI_ON LITERAL1 +USB_OFF LITERAL1 +USB_ON LITERAL1 \ No newline at end of file diff --git a/libraries/MySensors/LowPower.cpp b/libraries/MySensors/LowPower.cpp new file mode 100644 index 0000000..a72cc31 --- /dev/null +++ b/libraries/MySensors/LowPower.cpp @@ -0,0 +1,856 @@ +/******************************************************************************* +* LowPower Library +* Version: 1.30 +* Date: 22-05-2013 +* Company: Rocket Scream Electronics +* Website: www.rocketscream.com +* +* This is a lightweight low power library for Arduino. Please check our wiki +* (www.rocketscream.com/wiki) for more information on using this piece of +* library. +* +* This library is licensed under Creative Commons Attribution-ShareAlike 3.0 +* Unported License. +* +* Revision Description +* ======== =========== +* 1.30 Added support for ATMega168, ATMega2560, ATMega1280 & ATMega32U4. +* Tested to work with Arduino IDE 1.0.1 - 1.0.4. +* 1.20 Remove typo error in idle method for checking whether Timer 0 was +* turned off. +* Remove dependecy on WProgram.h which is not required. +* Tested to work with Arduino IDE 1.0. +* 1.10 Added #ifndef for sleep_bod_disable() for compatibility with future +* Arduino IDE release. +* 1.00 Initial public release. +*******************************************************************************/ +#include +#include +#include +#include +#include "LowPower.h" + +// Only Pico Power devices can change BOD settings through software +#if defined __AVR_ATmega328P__ +#ifndef sleep_bod_disable +#define sleep_bod_disable() \ +do { \ + unsigned char tempreg; \ + __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \ + "ori %[tempreg], %[bods_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" "\n\t" \ + "andi %[tempreg], %[not_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" \ + : [tempreg] "=&d" (tempreg) \ + : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \ + [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \ + [not_bodse] "i" (~_BV(BODSE))); \ +} while (0) +#endif +#endif + +#define lowPowerBodOn(mode) \ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); + +// Only Pico Power devices can change BOD settings through software +#if defined __AVR_ATmega328P__ +#define lowPowerBodOff(mode)\ +do { \ + set_sleep_mode(mode); \ + cli(); \ + sleep_enable(); \ + sleep_bod_disable(); \ + sei(); \ + sleep_cpu(); \ + sleep_disable(); \ + sei(); \ +} while (0); +#endif + +// Some macros is still missing from AVR GCC distribution for ATmega32U4 +#if defined __AVR_ATmega32U4__ + // Timer 4 PRR bit is currently not defined in iom32u4.h + #ifndef PRTIM4 + #define PRTIM4 4 + #endif + + // Timer 4 power reduction macro is not defined currently in power.h + #ifndef power_timer4_disable + #define power_timer4_disable() (PRR1 |= (uint8_t)(1 << PRTIM4)) + #endif + + #ifndef power_timer4_enable + #define power_timer4_enable() (PRR1 &= (uint8_t)~(1 << PRTIM4)) + #endif +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega328P/168 into idle state. Please make sure you +* understand the implication and result of disabling module. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 4. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 5. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 6. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 7. usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 8. twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) +void LowPowerClass::idle(period_t period, adc_t adc, timer2_t timer2, + timer1_t timer1, timer0_t timer0, + spi_t spi, usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega32U4 into idle state. Please make sure you +* understand the implication and result of disabling module. +* Take note that Timer 2 is not available and USART0 +* is replaced with USART1 on ATmega32U4. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 4. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 5. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 6. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 7. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 8. usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 9. twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +* 10.usb USB module disable control: +* (a) USB_OFF - Turn off USB module +* (b) USB_ON - Leave USB module in its default state +*******************************************************************************/ +#if defined __AVR_ATmega32U4__ +void LowPowerClass::idle(period_t period, adc_t adc, + timer4_t timer4, timer3_t timer3, + timer1_t timer1, timer0_t timer0, + spi_t spi, usart1_t usart1, twi_t twi, usb_t usb) +{ + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (twi == TWI_OFF) power_twi_disable(); + if (usb == USB_OFF) power_usb_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (twi == TWI_OFF) power_twi_enable(); + if (usb == USB_OFF) power_usb_enable(); +} +#endif + +/******************************************************************************* +* Name: idle +* Description: Putting ATmega2560 & ATmega1280 into idle state. Please make sure +* you understand the implication and result of disabling module. +* Take note that extra Timer 5, 4, 3 compared to an ATmega328P/168. +* Also take note that extra USART 3, 2, 1 compared to an +* ATmega328P/168. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control: +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer5 Timer 5 module disable control: +* (a) TIMER5_OFF - Turn off Timer 5 module +* (b) TIMER5_ON - Leave Timer 5 module in its default state +* +* 4. timer4 Timer 4 module disable control: +* (a) TIMER4_OFF - Turn off Timer 4 module +* (b) TIMER4_ON - Leave Timer 4 module in its default state +* +* 5. timer3 Timer 3 module disable control: +* (a) TIMER3_OFF - Turn off Timer 3 module +* (b) TIMER3_ON - Leave Timer 3 module in its default state +* +* 6. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +* 7. timer1 Timer 1 module disable control: +* (a) TIMER1_OFF - Turn off Timer 1 module +* (b) TIMER1_ON - Leave Timer 1 module in its default state +* +* 8. timer0 Timer 0 module disable control: +* (a) TIMER0_OFF - Turn off Timer 0 module +* (b) TIMER0_ON - Leave Timer 0 module in its default state +* +* 9. spi SPI module disable control: +* (a) SPI_OFF - Turn off SPI module +* (b) SPI_ON - Leave SPI module in its default state +* +* 10.usart3 USART3 module disable control: +* (a) USART3_OFF - Turn off USART3 module +* (b) USART3_ON - Leave USART3 module in its default state +* +* 11.usart2 USART2 module disable control: +* (a) USART2_OFF - Turn off USART2 module +* (b) USART2_ON - Leave USART2 module in its default state +* +* 12.usart1 USART1 module disable control: +* (a) USART1_OFF - Turn off USART1 module +* (b) USART1_ON - Leave USART1 module in its default state +* +* 13.usart0 USART0 module disable control: +* (a) USART0_OFF - Turn off USART0 module +* (b) USART0_ON - Leave USART0 module in its default state +* +* 14.twi TWI module disable control: +* (a) TWI_OFF - Turn off TWI module +* (b) TWI_ON - Leave TWI module in its default state +* +*******************************************************************************/ +#if defined (__AVR_ATmega2560__) || defined (__AVR_ATmega1280__) +void LowPowerClass::idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart3_t usart3, usart2_t usart2, usart1_t usart1, + usart0_t usart0, twi_t twi) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + + power_timer2_disable(); + } + + if (adc == ADC_OFF) + { + ADCSRA &= ~(1 << ADEN); + power_adc_disable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_disable(); + if (timer4 == TIMER4_OFF) power_timer4_disable(); + if (timer3 == TIMER3_OFF) power_timer3_disable(); + if (timer1 == TIMER1_OFF) power_timer1_disable(); + if (timer0 == TIMER0_OFF) power_timer0_disable(); + if (spi == SPI_OFF) power_spi_disable(); + if (usart3 == USART3_OFF) power_usart3_disable(); + if (usart2 == USART2_OFF) power_usart2_disable(); + if (usart1 == USART1_OFF) power_usart1_disable(); + if (usart0 == USART0_OFF) power_usart0_disable(); + if (twi == TWI_OFF) power_twi_disable(); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_IDLE); + + if (adc == ADC_OFF) + { + power_adc_enable(); + ADCSRA |= (1 << ADEN); + } + + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + power_timer2_enable(); + } + + if (timer5 == TIMER5_OFF) power_timer5_enable(); + if (timer4 == TIMER4_OFF) power_timer4_enable(); + if (timer3 == TIMER3_OFF) power_timer3_enable(); + if (timer1 == TIMER1_OFF) power_timer1_enable(); + if (timer0 == TIMER0_OFF) power_timer0_enable(); + if (spi == SPI_OFF) power_spi_enable(); + if (usart3 == USART3_OFF) power_usart3_enable(); + if (usart2 == USART2_OFF) power_usart2_enable(); + if (usart1 == USART1_OFF) power_usart1_enable(); + if (usart0 == USART0_OFF) power_usart0_enable(); + if (twi == TWI_OFF) power_twi_enable(); +} +#endif + +/******************************************************************************* +* Name: adcNoiseReduction +* Description: Putting microcontroller into ADC noise reduction state. This is +* a very useful state when using the ADC to achieve best and low +* noise signal. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. Turning off the ADC module is +* basically removing the purpose of this low power mode. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::adcNoiseReduction(period_t period, adc_t adc, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + lowPowerBodOn(SLEEP_MODE_ADC); + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + + } + #endif +} + +/******************************************************************************* +* Name: powerDown +* Description: Putting microcontroller into power down state. This is +* the lowest current consumption state. Use this together with +* external pin interrupt to wake up through external event +* triggering (example: RTC clockout pin, SD card detect pin). +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. Turning off the ADC module is +* basically removing the purpose of this low power mode. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. bod Brown Out Detector (BOD) module disable control: +* (a) BOD_OFF - Turn off BOD module +* (b) BOD_ON - Leave BOD module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerDown(period_t period, adc_t adc, bod_t bod) +{ + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + if (bod == BOD_OFF) + { + #if defined __AVR_ATmega328P__ + lowPowerBodOff(SLEEP_MODE_PWR_DOWN); + #else + lowPowerBodOn(SLEEP_MODE_PWR_DOWN); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_PWR_DOWN); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); +} + +/******************************************************************************* +* Name: powerSave +* Description: Putting microcontroller into power save state. This is +* the lowest current consumption state after power down. +* Use this state together with an external 32.768 kHz crystal (but +* 8/16 MHz crystal/resonator need to be removed) to provide an +* asynchronous clock source to Timer 2. Please take note that +* Timer 2 is also used by the Arduino core for PWM operation. +* Please refer to wiring.c for explanation. Removal of the external +* 8/16 MHz crystal/resonator requires the microcontroller to run +* on its internal RC oscillator which is not so accurate for time +* critical operation. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. Turning off the ADC module is +* basically removing the purpose of this low power mode. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. bod Brown Out Detector (BOD) module disable control: +* (a) BOD_OFF - Turn off BOD module +* (b) BOD_ON - Leave BOD module in its default state +* +* 4. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerSave(period_t period, adc_t adc, bod_t bod, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + if (bod == BOD_OFF) + { + #if defined __AVR_ATmega328P__ + lowPowerBodOff(SLEEP_MODE_PWR_SAVE); + #else + lowPowerBodOn(SLEEP_MODE_PWR_SAVE); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_PWR_SAVE); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + } + #endif +} + +/******************************************************************************* +* Name: powerStandby +* Description: Putting microcontroller into power standby state. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. Turning off the ADC module is +* basically removing the purpose of this low power mode. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. bod Brown Out Detector (BOD) module disable control: +* (a) BOD_OFF - Turn off BOD module +* (b) BOD_ON - Leave BOD module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerStandby(period_t period, adc_t adc, bod_t bod) +{ + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + + if (bod == BOD_OFF) + { + #if defined __AVR_ATmega328P__ + lowPowerBodOff(SLEEP_MODE_STANDBY); + #else + lowPowerBodOn(SLEEP_MODE_STANDBY); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_STANDBY); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); +} + +/******************************************************************************* +* Name: powerExtStandby +* Description: Putting microcontroller into power extended standby state. This +* is different from the power standby state as it has the +* capability to run Timer 2 asynchronously. +* +* Argument Description +* ========= =========== +* 1. period Duration of low power mode. Use SLEEP_FOREVER to use other wake +* up resource: +* (a) SLEEP_15MS - 15 ms sleep +* (b) SLEEP_30MS - 30 ms sleep +* (c) SLEEP_60MS - 60 ms sleep +* (d) SLEEP_120MS - 120 ms sleep +* (e) SLEEP_250MS - 250 ms sleep +* (f) SLEEP_500MS - 500 ms sleep +* (g) SLEEP_1S - 1 s sleep +* (h) SLEEP_2S - 2 s sleep +* (i) SLEEP_4S - 4 s sleep +* (j) SLEEP_8S - 8 s sleep +* (k) SLEEP_FOREVER - Sleep without waking up through WDT +* +* 2. adc ADC module disable control. +* (a) ADC_OFF - Turn off ADC module +* (b) ADC_ON - Leave ADC module in its default state +* +* 3. bod Brown Out Detector (BOD) module disable control: +* (a) BOD_OFF - Turn off BOD module +* (b) BOD_ON - Leave BOD module in its default state +* +* 4. timer2 Timer 2 module disable control: +* (a) TIMER2_OFF - Turn off Timer 2 module +* (b) TIMER2_ON - Leave Timer 2 module in its default state +* +*******************************************************************************/ +void LowPowerClass::powerExtStandby(period_t period, adc_t adc, bod_t bod, + timer2_t timer2) +{ + // Temporary clock source variable + unsigned char clockSource = 0; + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (TCCR2B & CS22) clockSource |= (1 << CS22); + if (TCCR2B & CS21) clockSource |= (1 << CS21); + if (TCCR2B & CS20) clockSource |= (1 << CS20); + + // Remove the clock source to shutdown Timer2 + TCCR2B &= ~(1 << CS22); + TCCR2B &= ~(1 << CS21); + TCCR2B &= ~(1 << CS20); + } + #endif + + if (adc == ADC_OFF) ADCSRA &= ~(1 << ADEN); + + if (period != SLEEP_FOREVER) + { + wdt_enable(period); + WDTCSR |= (1 << WDIE); + } + if (bod == BOD_OFF) + { + #if defined __AVR_ATmega328P__ + lowPowerBodOff(SLEEP_MODE_EXT_STANDBY); + #else + lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); + #endif + } + else + { + lowPowerBodOn(SLEEP_MODE_EXT_STANDBY); + } + + if (adc == ADC_OFF) ADCSRA |= (1 << ADEN); + + #if !defined(__AVR_ATmega32U4__) + if (timer2 == TIMER2_OFF) + { + if (clockSource & CS22) TCCR2B |= (1 << CS22); + if (clockSource & CS21) TCCR2B |= (1 << CS21); + if (clockSource & CS20) TCCR2B |= (1 << CS20); + } + #endif +} + +/******************************************************************************* +* Name: ISR (WDT_vect) +* Description: Watchdog Timer interrupt service routine. This routine is +* required to allow automatic WDIF and WDIE bit clearance in +* hardware. +* +*******************************************************************************/ +ISR (WDT_vect) +{ + // WDIE & WDIF is cleared in hardware upon entering this ISR + wdt_disable(); +} + +LowPowerClass LowPower; \ No newline at end of file diff --git a/libraries/MySensors/LowPower.h b/libraries/MySensors/LowPower.h new file mode 100644 index 0000000..ef05901 --- /dev/null +++ b/libraries/MySensors/LowPower.h @@ -0,0 +1,137 @@ +#ifndef LowPower_h +#define LowPower_h + +enum period_t +{ + SLEEP_15Ms, + SLEEP_30MS, + SLEEP_60MS, + SLEEP_120MS, + SLEEP_250MS, + SLEEP_500MS, + SLEEP_1S, + SLEEP_2S, + SLEEP_4S, + SLEEP_8S, + SLEEP_FOREVER +}; + +enum bod_t +{ + BOD_OFF, + BOD_ON +}; + +enum adc_t +{ + ADC_OFF, + ADC_ON +}; + +enum timer5_t +{ + TIMER5_OFF, + TIMER5_ON +}; + +enum timer4_t +{ + TIMER4_OFF, + TIMER4_ON +}; + +enum timer3_t +{ + TIMER3_OFF, + TIMER3_ON +}; + +enum timer2_t +{ + TIMER2_OFF, + TIMER2_ON +}; + +enum timer1_t +{ + TIMER1_OFF, + TIMER1_ON +}; + +enum timer0_t +{ + TIMER0_OFF, + TIMER0_ON +}; + +enum spi_t +{ + SPI_OFF, + SPI_ON +}; + +enum usart0_t +{ + USART0_OFF, + USART0_ON +}; + +enum usart1_t +{ + USART1_OFF, + USART1_ON +}; + +enum usart2_t +{ + USART2_OFF, + USART2_ON +}; + +enum usart3_t +{ + USART3_OFF, + USART3_ON +}; + +enum twi_t +{ + TWI_OFF, + TWI_ON +}; + +enum usb_t +{ + USB_OFF, + USB_ON +}; + +class LowPowerClass +{ + public: + #if defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168__) + void idle(period_t period, adc_t adc, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega2560__ + void idle(period_t period, adc_t adc, timer5_t timer5, + timer4_t timer4, timer3_t timer3, timer2_t timer2, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart3_t usart3, usart2_t usart2, usart1_t usart1, + usart0_t usart0, twi_t twi); + #elif defined __AVR_ATmega32U4__ + void idle(period_t period, adc_t adc, timer4_t timer4, timer3_t timer3, + timer1_t timer1, timer0_t timer0, spi_t spi, + usart1_t usart1, twi_t twi, usb_t usb); + #else + #error "Please ensure chosen MCU is either 328P, 32U4 or 2560." + #endif + void adcNoiseReduction(period_t period, adc_t adc, timer2_t timer2); + void powerDown(period_t period, adc_t adc, bod_t bod); + void powerSave(period_t period, adc_t adc, bod_t bod, timer2_t timer2); + void powerStandby(period_t period, adc_t adc, bod_t bod); + void powerExtStandby(period_t period, adc_t adc, bod_t bod, timer2_t timer2); +}; + +extern LowPowerClass LowPower; +#endif \ No newline at end of file diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 75bb89d..bdfa7ab 100644 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -10,6 +10,8 @@ */ #include "MySensor.h" +#include "LowPower.h" + // Inline function and macros inline MyMessage* build (MyMessage* msg, uint8_t sender, uint8_t destination, uint8_t sensor, uint8_t command, uint8_t type) { @@ -499,7 +501,7 @@ uint8_t MySensor::getChildRoute(uint8_t childId) { } -long MySensor::getInternalTemp(void) +float MySensor::getInternalTemp(void) { long result; // Read internal temp sensor against 1.1V reference @@ -511,9 +513,48 @@ long MySensor::getInternalTemp(void) result |= ADCH<<8; result = (result - 125) * 1075; - return result; + return static_cast(static_cast(result/1000.)) / 10.; } +int continueTimer = true; +void wakeUp() //place to send the interrupts +{ + continueTimer = false; +} + +void MySensor::internalSleep(int ms) { + while (continueTimer && ms >= 8000) { LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); ms -= 8000; } + if (continueTimer && ms >= 4000) { LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF); ms -= 4000; } + if (continueTimer && ms >= 2000) { LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF); ms -= 2000; } + if (continueTimer && ms >= 1000) { LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF); ms -= 1000; } + if (continueTimer && ms >= 500) { LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF); ms -= 500; } + if (continueTimer && ms >= 250) { LowPower.powerDown(SLEEP_250MS, ADC_OFF, BOD_OFF); ms -= 250; } + if (continueTimer && ms >= 125) { LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_OFF); ms -= 120; } + if (continueTimer && ms >= 64) { LowPower.powerDown(SLEEP_60MS, ADC_OFF, BOD_OFF); ms -= 60; } + if (continueTimer && ms >= 32) { LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_OFF); ms -= 30; } + if (continueTimer && ms >= 16) { LowPower.powerDown(SLEEP_15Ms, ADC_OFF, BOD_OFF); ms -= 15; } +} + +void MySensor::sleep(int ms) { + RF24::powerDown(); + continueTimer = true; + internalSleep(ms); +} + +void MySensor::sleep(int interrupt, int mode, int ms) { + RF24::powerDown(); + attachInterrupt(interrupt, wakeUp, mode); //Interrupt on pin 3 for any change in solar power + if (ms>0) { + continueTimer = true; + sleep(ms); + } else { + LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); + } + detachInterrupt(interrupt); +} + + + #ifdef DEBUG void MySensor::debugPrint(const char *fmt, ... ) { char fmtBuffer[300]; diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 94bdd84..2c1a025 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -24,6 +24,7 @@ #include #include #include +#include "LowPower.h" #ifdef DEBUG #define debug(x,...) debugPrint(x, ##__VA_ARGS__) @@ -193,15 +194,30 @@ class MySensor : public RF24 */ MyMessage* getLastMessage(void); + /** + * Sleep (PowerDownMode) the Arduino and radio. Wake up on timer. + * @param ms Number of milliseconds to sleep. + */ + void sleep(int ms); + + /** + * Sleep (PowerDownMode) the Arduino and radio. Wake up on timer or pin change. + * See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin + * is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3 + * @param interrupt Interrupt that should trigger the wakeup + * @param mode RISING, FALLING, CHANGE + * @param ms Number of milliseconds to sleep or 0 to sleep forever + */ + void sleep(int interrupt, int mode, int ms=0); /** * getInternalTemp * * Read temp from internal (ATMEGA328 only) temperature sensor * - * @return Temperature in milli-degrees Celsius + * @return Temperature in degrees Celsius (one decimal) */ - long getInternalTemp(void); + float getInternalTemp(void); @@ -240,6 +256,7 @@ class MySensor : public RF24 uint8_t getChildRoute(uint8_t childId); void addChildRoute(uint8_t childId, uint8_t route); void removeChildRoute(uint8_t childId); + void internalSleep(int ms); }; #endif diff --git a/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino b/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino index 70a8cf8..8322b50 100644 --- a/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino +++ b/libraries/MySensors/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino @@ -2,17 +2,13 @@ // Instructions for measuring battery capacity on A0 are available in the follwoing forum // thread: http://forum.micasaverde.com/index.php/topic,20078.0.html - -#include #include -#include #include -#include +#include int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point -Sensor gw; -Sleep sleep; +MySensor gw; unsigned long SLEEP_TIME = 900000; // sleep time between reads (seconds * 1000 milliseconds) int oldBatteryPcnt = 0; @@ -54,12 +50,6 @@ void loop() } // delay to allow transmissions to gateway to be completed before sleep - delay(500); - - // Power down the radio. Note that the radio will get powered back up - // on the next write() call - gw.powerDown(); - - sleep.pwrDownMode(); // set sleep mode - sleep.sleepDelay(SLEEP_TIME); // sleep for SLEEP_TIME + delay(300); + gw.sleep(SLEEP_TIME); } diff --git a/libraries/MySensors/examples/BinarySwitchSensor/BinarySwitchSensor.ino b/libraries/MySensors/examples/BinarySwitchSensor/BinarySwitchSensor.ino index 61f4da2..f1a65ca 100644 --- a/libraries/MySensors/examples/BinarySwitchSensor/BinarySwitchSensor.ino +++ b/libraries/MySensors/examples/BinarySwitchSensor/BinarySwitchSensor.ino @@ -2,17 +2,20 @@ // Connect button or door/window reed switch between // digitial I/O pin 3 (BUTTON_PIN below) and GND. -#include +#include #include #include #include #include +#define CHILD_ID 3 #define BUTTON_PIN 3 // Arduino Digital I/O pin for button/reed switch -Sensor gw; +MySensor gw; Bounce debouncer = Bounce(); int oldValue=-1; +// Change to V_LIGHT if you use S_LIGHT in presentation below +MyMessage msg(CHILD_ID,V_TRIPPED); void setup() { @@ -30,7 +33,7 @@ void setup() // Register binary input sensor to gw (they will be created as child devices) // You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage. // If S_LIGHT is used, remember to update variable type you send in below. - gw.sendSensorPresentation(BUTTON_PIN, S_DOOR); + gw.present(CHILD_ID, S_DOOR); } @@ -43,7 +46,7 @@ void loop() if (value != oldValue) { // Send in the new value - gw.sendVariable(BUTTON_PIN, V_TRIPPED, value==HIGH ? "1" : "0"); // Change to V_LIGHT if you use S_LIGHT in presentation above + gw.send(msg.set(value==HIGH ? 1 : 0)); oldValue = value; } } diff --git a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino index b85aeeb..9a0282c 100644 --- a/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino +++ b/libraries/MySensors/examples/DallasTemperatureSensor/DallasTemperatureSensor.ino @@ -1,6 +1,5 @@ // Example sketch showing how to send in OneWire temperature readings #include -#include #include #include #include @@ -12,7 +11,6 @@ unsigned long SLEEP_TIME = 30; // Sleep time between reads (in seconds) OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); MySensor gw; -Sleep sleep; float lastTemperature[MAX_ATTACHED_DS18B20]; int numSensors=0; boolean receivedConfig = false; @@ -64,10 +62,8 @@ void loop() } } // Power down the radio and sleep Arduino to save batteries. - delay(500); - gw.powerDown(); - sleep.pwrDownMode(); //set sleep mode - sleep.sleepDelay(SLEEP_TIME * 1000); //sleep for: sleepTime + delay(300); + gw.sleep(SLEEP_TIME * 1000); } diff --git a/libraries/MySensors/examples/DistanceSensor/DistanceSensor.ino b/libraries/MySensors/examples/DistanceSensor/DistanceSensor.ino index 8c246d0..de1438a 100644 --- a/libraries/MySensors/examples/DistanceSensor/DistanceSensor.ino +++ b/libraries/MySensors/examples/DistanceSensor/DistanceSensor.ino @@ -1,19 +1,18 @@ -#include #include #include #include -#include +#include #include +#define CHILD_ID 1 #define TRIGGER_PIN 6 // Arduino pin tied to trigger pin on the ultrasonic sensor. #define ECHO_PIN 5 // Arduino pin tied to echo pin on the ultrasonic sensor. #define MAX_DISTANCE 300 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm. unsigned long SLEEP_TIME = 5; // Sleep time between reads (in seconds) -Sensor gw; +MySensor gw; NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance. -Sleep sleep; - +MyMessage msg(CHILD_ID, V_DISTANCE); int lastDist; boolean metric = true; @@ -25,8 +24,8 @@ void setup() gw.sendSketchInfo("Distance Sensor", "1.0"); // Register all sensors to gw (they will be created as child devices) - gw.sendSensorPresentation(0, S_DISTANCE); - metric = gw.isMetricSystem(); + gw.present(CHILD_ID, S_DISTANCE); + boolean metric = gw.getConfig().isMetric; } void loop() @@ -39,16 +38,12 @@ void loop() if (dist != lastDist) { - gw.sendVariable(0, V_DISTANCE, dist); + gw.send(msg.set(dist)); lastDist = dist; } - // Power down the radio. Note that the radio will get powered back up - // on the next write() call. - delay(1000); //delay to allow serial to fully print before sleep - gw.powerDown(); - sleep.pwrDownMode(); //set sleep mode - sleep.sleepDelay(SLEEP_TIME * 1000); //sleep for: sleepTime + delay(300); //delay to allow serial to fully print before sleep + gw.sleep(SLEEP_TIME*1000); } diff --git a/libraries/MySensors/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino b/libraries/MySensors/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino index 2fc8cf8..3a65c37 100644 --- a/libraries/MySensors/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino +++ b/libraries/MySensors/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino @@ -7,26 +7,21 @@ // sleepmode. So we cannot make this sensor sleep if we also want // to calculate/report watt-number. -#include #include #include #include -#include +#include #define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your light sensor. (Only 2 and 3 generates interrupt!) #define PULSE_FACTOR 1000 // Nummber of blinks per KWH of your meeter #define SLEEP_MODE false // Watt-value can only be reported when sleep mode is false. #define MAX_WATT 10000 // Max watt value to report. This filetrs outliers. #define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway) -#define CHILD_ID 1 // Id of the sensor child +#define CHILD_ID 1 // Id of the sensor child unsigned long SEND_FREQUENCY = 20; // Minimum time between send (in seconds). We don't wnat to spam the gateway. - -Sensor gw; -Sleep sleep; - -//double kwhPerBlink = 1.0/((double)PULSE_FACTOR); +MySensor gw; double ppwh = ((double)PULSE_FACTOR)/1000; // Pulses per watt hour - +boolean pcReceived = false; volatile unsigned long pulseCount = 0; volatile unsigned long lastBlink = 0; volatile unsigned long watt = 0; @@ -34,21 +29,24 @@ unsigned long oldPulseCount = 0; unsigned long oldWatt = 0; double oldKwh; unsigned long lastSend; +MyMessage wattMsg(CHILD_ID,V_WATT); +MyMessage kwhMsg(CHILD_ID,V_KWH); +MyMessage pcMsg(CHILD_ID,V_VAR1); + void setup() { - gw.begin(); + gw.begin(incomingMessage); // Send the sketch version information to the gateway and Controller gw.sendSketchInfo("Energy Meter", "1.0"); // Register this device as power sensor - gw.sendSensorPresentation(CHILD_ID, S_POWER); + gw.present(CHILD_ID, S_POWER); // Fetch last known pulse count value from gw - pulseCount = oldPulseCount = atol(gw.getStatus(CHILD_ID, V_VAR1)); - Serial.print("Last pulse count from gw:"); - Serial.println(pulseCount); + gw.request(CHILD_ID, V_VAR1); + attachInterrupt(INTERRUPT, onPulse, RISING); lastSend=millis(); } @@ -56,15 +54,17 @@ void setup() void loop() { - unsigned long now = millis(); + gw.process(); + unsigned long now = millis(); // Only send values at a maximum frequency or woken up from sleep - if (SLEEP_MODE || now - lastSend > 1000*SEND_FREQUENCY) { + bool sendTime = now - lastSend > 1000*SEND_FREQUENCY; + if (pcReceived && (SLEEP_MODE || sendTime)) { // New watt value has been calculated if (!SLEEP_MODE && watt != oldWatt) { // Check that we dont get unresonable large watt value. // could hapen when long wraps or false interrupt triggered if (watt<((unsigned long)MAX_WATT)) { - gw.sendVariable(CHILD_ID, V_WATT, watt); // Send watt value to gw + gw.send(wattMsg.set(watt)); // Send watt value to gw } Serial.print("Watt:"); Serial.println(watt); @@ -73,26 +73,32 @@ void loop() // Pulse cout has changed if (pulseCount != oldPulseCount) { - gw.sendVariable(CHILD_ID, V_VAR1, pulseCount); // Send kwh value to gw + gw.send(pcMsg.set(pulseCount)); // Send pulse count value to gw double kwh = ((double)pulseCount/((double)PULSE_FACTOR)); oldPulseCount = pulseCount; - //Serial.print("Pulse count:"); - //Serial.println(pulseCount); if (kwh != oldKwh) { - gw.sendVariable(CHILD_ID, V_KWH, kwh, 4); // Send kwh value to gw - //Serial.print("KWH:"); - //Serial.println(kwh); + gw.send(kwhMsg.set(kwh, 4)); // Send kwh value to gw oldKwh = kwh; } - } + } lastSend = now; + } else if (sendTime && !pcReceived) { + // No count received. Try requesting it again + gw.request(CHILD_ID, V_VAR1); } if (SLEEP_MODE) { delay(300); //delay to allow serial to fully print before sleep - gw.powerDown(); - sleep.pwrDownMode(); //set sleep mode - sleep.sleepDelay(SEND_FREQUENCY * 1000); //sleep for: sleepTime + gw.sleep(SEND_FREQUENCY * 1000); + } +} + +void incomingMessage(MyMessage message) { + if (message.type==V_VAR1) { + pulseCount = oldPulseCount = message.getLong(); + Serial.print("Last pulse count from gw:"); + Serial.println(pulseCount); + pcReceived = true; } } diff --git a/libraries/MySensors/examples/HumiditySensor/HumiditySensor.ino b/libraries/MySensors/examples/HumiditySensor/HumiditySensor.ino index bef4943..3952ce9 100644 --- a/libraries/MySensors/examples/HumiditySensor/HumiditySensor.ino +++ b/libraries/MySensors/examples/HumiditySensor/HumiditySensor.ino @@ -1,8 +1,6 @@ -#include #include -#include #include -#include +#include #include #define CHILD_ID_HUM 0 @@ -10,12 +8,14 @@ #define HUMIDITY_SENSOR_DIGITAL_PIN 3 unsigned long SLEEP_TIME = 30; // Sleep time between reads (in seconds) -Sensor gw; +MySensor gw; DHT dht; -Sleep sleep; float lastTemp; float lastHum; boolean metric = true; +MyMessage msgHum(CHILD_ID_HUM, V_HUM); +MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP); + void setup() { @@ -26,10 +26,10 @@ void setup() gw.sendSketchInfo("Humidity", "1.0"); // Register all sensors to gw (they will be created as child devices) - gw.sendSensorPresentation(CHILD_ID_HUM, S_HUM); - gw.sendSensorPresentation(CHILD_ID_TEMP, S_TEMP); + gw.present(CHILD_ID_HUM, S_HUM); + gw.present(CHILD_ID_TEMP, S_TEMP); - metric = gw.isMetricSystem(); + metric = gw.getConfig().isMetric; } void loop() @@ -44,9 +44,9 @@ void loop() if (!metric) { temperature = dht.toFahrenheit(temperature); } - gw.sendVariable(CHILD_ID_TEMP, V_TEMP, temperature, 1); - Serial.print("T: "); - Serial.println(temperature); + gw.send(msgTemp.set(temperature, 1)); + Serial.print("T: "); + Serial.println(temperature); } float humidity = dht.getHumidity(); @@ -54,17 +54,13 @@ void loop() Serial.println("Failed reading humidity from DHT"); } else if (humidity != lastHum) { lastHum = humidity; - gw.sendVariable(CHILD_ID_HUM, V_HUM, humidity, 1); + gw.send(msgHum.set(humidity, 1)); Serial.print("H: "); Serial.println(humidity); } - // Power down the radio. Note that the radio will get powered back up - // on the next write() call. - delay(1000); //delay to allow serial to fully print before sleep - gw.powerDown(); - sleep.pwrDownMode(); //set sleep mode - sleep.sleepDelay(SLEEP_TIME * 1000); //sleep for: sleepTime + delay(300); //delay to allow serial to fully print before sleep + gw.sleep(SLEEP_TIME * 1000); //sleep a bit } diff --git a/libraries/MySensors/examples/IrSensor/IrSensor.ino b/libraries/MySensors/examples/IrSensor/IrSensor.ino index bb1ea65..a34e024 100644 --- a/libraries/MySensors/examples/IrSensor/IrSensor.ino +++ b/libraries/MySensors/examples/IrSensor/IrSensor.ino @@ -5,7 +5,7 @@ // When binary light on is clicked - sketch will send volume up ir command // When binary light off is clicked - sketch will send volume down ir command -#include +#include #include #include #include @@ -20,39 +20,26 @@ IRrecv irrecv(RECV_PIN); IRdecode decoder; //decode_results results; unsigned int Buffer[RAWBUF]; - -Sensor gw; +MySensor gw; +MyMessage msg(CHILD_1, V_VAR1); void setup() { irrecv.enableIRIn(); // Start the ir receiver decoder.UseExtnBuf(Buffer); - gw.begin(); + gw.begin(incomingMessage); // Send the sketch version information to the gateway and Controller gw.sendSketchInfo("IR Sensor", "1.0"); // Register a sensors to gw. Use binary light for test purposes. - gw.sendSensorPresentation(CHILD_1, S_LIGHT); + gw.present(CHILD_1, S_LIGHT); } void loop() { - if (gw.messageAvailable()) { - message_s message = gw.getMessage(); - - int incomingRelayStatus = atoi(message.data); - if (incomingRelayStatus == 1) { - irsend.send(NEC, 0x1EE17887, 32); // Vol up yamaha ysp-900 - } else { - irsend.send(NEC, 0x1EE1F807, 32); // Vol down yamaha ysp-900 - } - // Start receiving ir again... - irrecv.enableIRIn(); - } - - + gw.process(); if (irrecv.GetResults(&decoder)) { irrecv.resume(); decoder.decode(); @@ -61,11 +48,26 @@ void loop() char buffer[10]; sprintf(buffer, "%08lx", decoder.value); // Send ir result to gw - gw.sendVariable(CHILD_1, V_VAR1, buffer); + gw.send(msg.set(buffer)); } } + +void incomingMessage(MyMessage message) { + // We only expect one type of message from controller. But we better check anyway. + if (message.type==V_LIGHT) { + int incomingRelayStatus = message.getInt(); + if (incomingRelayStatus == 1) { + irsend.send(NEC, 0x1EE17887, 32); // Vol up yamaha ysp-900 + } else { + irsend.send(NEC, 0x1EE1F807, 32); // Vol down yamaha ysp-900 + } + // Start receiving ir again... + irrecv.enableIRIn(); + } +} + // Dumps out the decode_results structure. // Call this after IRrecv::decode() // void * to work around compiler issue diff --git a/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino b/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino index c995316..f834f0c 100644 --- a/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino +++ b/libraries/MySensors/examples/LightLuxSensor/LightLuxSensor.ino @@ -16,12 +16,9 @@ */ - -#include #include #include -#include -#include +#include #include #include @@ -29,9 +26,9 @@ #define LIGHT_SENSOR_ANALOG_PIN 0 unsigned long SLEEP_TIME = 30; // Sleep time between reads (in seconds) -BH1750 lightSensor; -Sensor gw; -Sleep sleep; +BH1750 lightSensor; +MySensor gw; +MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL); int lastlux; void setup() @@ -42,7 +39,7 @@ void setup() gw.sendSketchInfo("Light Lux Sensor", "1.0"); // Register all sensors to gateway (they will be created as child devices) - gw.sendSensorPresentation(CHILD_ID_LIGHT, S_LIGHT_LEVEL); + gw.present(CHILD_ID_LIGHT, S_LIGHT_LEVEL); lightSensor.begin(); } @@ -52,14 +49,10 @@ void loop() uint16_t lux = lightSensor.readLightLevel();// Get Lux value Serial.println(lux); if (lux != lastlux) { - gw.sendVariable(CHILD_ID_LIGHT, V_LIGHT_LEVEL, lux); + gw.send(msg.set(lux)); lastlux = lux; } - // Power down the radio. Note that the radio will get powered back up - // on the next write() call. - delay(1000); //delay to allow serial to fully print before sleep - gw.powerDown(); - sleep.pwrDownMode(); //set sleep mode - sleep.sleepDelay(SLEEP_TIME * 1000); //sleep for: sleepTime + delay(300); //delay to allow serial to fully print before sleep + gw.sleep(SLEEP_TIME * 1000); } diff --git a/libraries/MySensors/examples/LightSensor/LightSensor.ino b/libraries/MySensors/examples/LightSensor/LightSensor.ino index 0b5de6f..df31c89 100644 --- a/libraries/MySensors/examples/LightSensor/LightSensor.ino +++ b/libraries/MySensors/examples/LightSensor/LightSensor.ino @@ -1,17 +1,15 @@ -#include #include #include -#include -#include +#include #define CHILD_ID_LIGHT 0 #define LIGHT_SENSOR_ANALOG_PIN 0 unsigned long SLEEP_TIME = 30; // Sleep time between reads (in seconds) -Sensor gw; +MySensor gw; +MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL); int lastLightLevel; -Sleep sleep; void setup() { @@ -21,7 +19,7 @@ void setup() gw.sendSketchInfo("Light Sensor", "1.0"); // Register all sensors to gateway (they will be created as child devices) - gw.sendSensorPresentation(CHILD_ID_LIGHT, S_LIGHT_LEVEL); + gw.present(CHILD_ID_LIGHT, S_LIGHT_LEVEL); } void loop() @@ -29,16 +27,12 @@ void loop() int lightLevel = (1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23; Serial.println(lightLevel); if (lightLevel != lastLightLevel) { - gw.sendVariable(CHILD_ID_LIGHT, V_LIGHT_LEVEL, lightLevel); + gw.send(msg.set(lightLevel)); lastLightLevel = lightLevel; } - // Power down the radio. Note that the radio will get powered back up - // on the next write() call. - delay(1000); //delay to allow serial to fully print before sleep - gw.powerDown(); - sleep.pwrDownMode(); //set sleep mode - sleep.sleepDelay(SLEEP_TIME * 1000); //sleep for: sleepTime + delay(300); //delay to allow serial to fully print before sleep + gw.sleep(SLEEP_TIME * 1000); } diff --git a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino index 3bb8777..6799854 100644 --- a/libraries/MySensors/examples/MotionSensor/MotionSensor.ino +++ b/libraries/MySensors/examples/MotionSensor/MotionSensor.ino @@ -1,5 +1,4 @@ #include -#include #include #include @@ -8,15 +7,11 @@ #define CHILD_ID 1 // Id of the sensor child MySensor gw; -Sleep sleep; // Initialize motion message MyMessage msg(CHILD_ID, V_TRIPPED); void setup() { - //eeprom_write_byte((uint8_t*)EEPROM_PARENT_NODE_ID_ADDRESS, 1); - //eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, 255); - //delay(2000); gw.begin(); // Send the sketch version information to the gateway and Controller @@ -24,9 +19,7 @@ void setup() pinMode(DIGITAL_INPUT_SENSOR, INPUT); // sets the motion sensor digital pin as input // Register all sensors to gw (they will be created as child devices) - delay(500); gw.present(CHILD_ID, S_MOTION); - delay(1000); } @@ -38,12 +31,8 @@ void loop() Serial.println(tripped); gw.send(msg.set(tripped?"1":"0")); // Send tripped value to gw - // Power down the radio. Note that the radio will get powered back up - // on the next write() call. - delay(200); //delay to allow serial to fully print before sleep - gw.powerDown(); - sleep.pwrDownMode(); //set sleep mode - sleep.sleepInterrupt(INTERRUPT,CHANGE); + // Sleep until interrupt comes in on motion sensor. Send update every two minute. + gw.sleep(INTERRUPT,CHANGE, 120000); } diff --git a/libraries/MySensors/examples/PressureSensor/PressureSensor.ino b/libraries/MySensors/examples/PressureSensor/PressureSensor.ino index 603f402..636e79f 100644 --- a/libraries/MySensors/examples/PressureSensor/PressureSensor.ino +++ b/libraries/MySensors/examples/PressureSensor/PressureSensor.ino @@ -1,21 +1,21 @@ -#include #include -#include #include -#include +#include #include #include +#define BARO_CHILD 0 +#define TEMP_CHILD 1 + #define LIGHT_SENSOR_ANALOG_PIN 0 unsigned long SLEEP_TIME = 60; // Sleep time between reads (in seconds) Adafruit_BMP085 bmp = Adafruit_BMP085(); // Digital Pressure Sensor -Sensor gw; +MySensor gw; float lastPressure = -1; float lastTemp = -1; int lastForecast = -1; -Sleep sleep; char *weather[] = {"stable","sunny","cloudy","unstable","thunderstorm","unknown"}; int minutes; float pressureSamples[180]; @@ -24,6 +24,11 @@ bool firstRound = true; float pressureAvg[7]; float dP_dt; boolean metric; +MyMessage tempMsg(TEMP_CHILD, V_TEMP); +MyMessage pressureMsg(BARO_CHILD, V_PRESSURE); +MyMessage forecastMsg(BARO_CHILD, V_FORECAST); + + void setup() { gw.begin(); @@ -37,9 +42,9 @@ void setup() { } // Register sensors to gw (they will be created as child devices) - gw.sendSensorPresentation(0, S_BARO); - gw.sendSensorPresentation(1, S_TEMP); - metric = gw.isMetricSystem(); + gw.present(BARO_CHILD, S_BARO); + gw.present(TEMP_CHILD, S_TEMP); + metric = gw.getConfig().isMetric; } @@ -64,17 +69,17 @@ void loop() { if (temperature != lastTemp) { - gw.sendVariable(1, V_TEMP, temperature,1); + gw.send(tempMsg.set(temperature,1)); lastTemp = temperature; } if (pressure != lastPressure) { - gw.sendVariable(0, V_PRESSURE, pressure, 0); + gw.send(pressureMsg.set(pressure, 0)); lastPressure = pressure; } if (forecast != lastForecast) { - gw.sendVariable(0, V_FORECAST, weather[forecast]); + gw.send(forecastMsg.set(weather[forecast])); lastForecast = forecast; } @@ -89,12 +94,8 @@ void loop() { 5 = "Unknown (More Time needed) */ - // Power down the radio. Note that the radio will get powered back up - // on the next write() call. - delay(1000); //delay to allow serial to fully print before sleep - gw.powerDown(); - sleep.pwrDownMode(); //set sleep mode - sleep.sleepDelay(SLEEP_TIME * 1000); // sleep to conserve power + delay(300); //delay to allow serial to fully print before sleep + gw.sleep(SLEEP_TIME * 1000); } int sample(float pressure) { diff --git a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino index f04b602..a850cce 100644 --- a/libraries/MySensors/examples/RelayActuator/RelayActuator.ino +++ b/libraries/MySensors/examples/RelayActuator/RelayActuator.ino @@ -39,6 +39,7 @@ void loop() } void incomingMessage(MyMessage message) { + Serial.println(gw.getInternalTemp()); // We only expect one type of message from controller. But we better check anyway. if (message.type==V_LIGHT) { // Change relay state diff --git a/libraries/MySensors/examples/RelayWithButtonActuator/RelayWithButtonActuator.ino b/libraries/MySensors/examples/RelayWithButtonActuator/RelayWithButtonActuator.ino index 427f9fd..9aed1b4 100644 --- a/libraries/MySensors/examples/RelayWithButtonActuator/RelayWithButtonActuator.ino +++ b/libraries/MySensors/examples/RelayWithButtonActuator/RelayWithButtonActuator.ino @@ -1,11 +1,12 @@ // Example sketch för a "light switch" where you can control light or something // else from both vera and a local physical button (connected between digital // pin 3 and +5V). +// This node also works as a repeader for other nodes -#include +#include #include -#include #include +#include #define RELAY_PIN 4 // Arduino Digital I/O pin number for relay #define BUTTON_PIN 3 // Arduino Digital I/O pin number for button (with 10k pulldown) @@ -13,37 +14,40 @@ #define RELAY_ON 0 #define RELAY_OFF 1 -int buttVal; -int previousVal; -int state; -int switched = 0; -long pressTime = 0; // the last time the button pin was pressed -long debounce = 200; // the debounce time, increase if the output flickers - -Relay gw; +Bounce debouncer = Bounce(); +int oldValue=-1; +bool state; +MySensor gw; +MyMessage msg(CHILD_ID,V_LIGHT); void setup() { - gw.begin(); + gw.begin(incomingMessage, AUTO, true); // Send the sketch version information to the gateway and Controller gw.sendSketchInfo("Relay & Button", "1.0"); - // Set buttonPin as Input - pinMode(BUTTON_PIN, INPUT); - buttVal = digitalRead(BUTTON_PIN); //read initial state + // Setup the button + pinMode(BUTTON_PIN,INPUT); + // Activate internal pull-up + digitalWrite(BUTTON_PIN,HIGH); + + // After setting up the button, setup debouncer + debouncer.attach(BUTTON_PIN); + debouncer.interval(5); + // Register all sensors to gw (they will be created as child devices) - gw.sendSensorPresentation(CHILD_ID, S_LIGHT); + gw.present(CHILD_ID, S_LIGHT); // Make sure relays are off when starting up digitalWrite(RELAY_PIN, RELAY_OFF); // Then set relay pins in output mode pinMode(RELAY_PIN, OUTPUT); - // Request/wait for relay status - gw.getStatus(CHILD_ID, V_LIGHT); - setRelayStatus(gw.getMessage()); // Wait here until status message arrive from gw + // Set relay to last known state (using eeprom storage) + digitalWrite(RELAY_PIN, gw.loadState(CHILD_ID)); + } @@ -53,40 +57,35 @@ void setup() */ void loop() { - if (gw.messageAvailable()) { - // ot new messsage from gw - message_s message = gw.getMessage(); - setRelayStatus(message); - } + gw.process(); + debouncer.update(); + // Get the update value + int value = debouncer.read(); - buttVal = digitalRead(BUTTON_PIN); // read input value and store it in val - - if (buttVal == HIGH && previousVal == LOW) { - // Start counter from when button was pressed - pressTime = millis(); - switched = 0; - } - - if (buttVal == HIGH && switched == 0 && millis() - pressTime > debounce) { - // Switch state if button pressed more than 200 msec - state = state==1?0:1; - gw.sendVariable(CHILD_ID, V_LIGHT, state); // We will receive an ack message - switched = 1; // No more switches until button is released + if (value != oldValue && value!=0) { + gw.saveState(CHILD_ID, state); + gw.send(msg.set(state==1?0:1), true); // Send and request ack + oldValue = value; } - previousVal = buttVal; } - -void setRelayStatus(message_s message) { - if (message.header.type==V_LIGHT) { // This could be M_ACK_VARIABLE or M_SET_VARIABLE - state = atoi(message.data); +void incomingMessage(MyMessage message) { + Serial.println(gw.getInternalTemp()); + // We only expect one type of message from controller. But we better check anyway. + if (message.type==V_LIGHT) { // Change relay state - digitalWrite(RELAY_PIN, state==1?RELAY_ON:RELAY_OFF); + state = message.getBool(); + digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF); + // Store state in eeprom + gw.saveState(CHILD_ID, state); + // Write some debug info - Serial.print(message.header.messageType == M_ACK_VARIABLE ? "Button":"Gateway"); - Serial.print(" change. New state: "); - Serial.println(state == 1 ?"on":"off" ); - } + Serial.print("Incoming change for sensor:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getBool()); + } } + diff --git a/libraries/MySensors/examples/RelayingNode/RelayingNode.ino b/libraries/MySensors/examples/RelayingNode/RelayingNode.ino index 40864f7..95975b6 100644 --- a/libraries/MySensors/examples/RelayingNode/RelayingNode.ino +++ b/libraries/MySensors/examples/RelayingNode/RelayingNode.ino @@ -4,16 +4,16 @@ // gw.messageAvailable() frequently. This sketch should not // sleep. -#include +#include #include -#include #include -Relay gw; +MySensor gw; void setup() { - gw.begin(); + // The third argument enables relaying mode. + gw.begin(NULL, AUTO, true); //Send the sensor node sketch version information to the gateway gw.sendSketchInfo("Relaying Node", "1.0"); @@ -21,10 +21,7 @@ void setup() void loop() { - // By calling this regularely you route messages in the background - if (gw.messageAvailable()) { - - // Handleincoming message for this node here... - } + // By calling process() you route messages in the background + gw.process(); } diff --git a/libraries/MySensors/examples/ServoActuator/ServoActuator.ino b/libraries/MySensors/examples/ServoActuator/ServoActuator.ino index 729694f..3fd555b 100644 --- a/libraries/MySensors/examples/ServoActuator/ServoActuator.ino +++ b/libraries/MySensors/examples/ServoActuator/ServoActuator.ino @@ -6,9 +6,8 @@ // Contribution by: Derek Macias -#include +#include #include -#include #include #include @@ -18,7 +17,7 @@ #define DETACH_DELAY 900 // Tune this to let your movement finish before detaching the servo #define CHILD_ID 10 // Id of the sensor child -Sensor gw; +MySensor gw; Servo myservo; // create servo object to control a servo // a maximum of eight servo objects can be created Sensor gw(9,10); unsigned long timeOfLastChange = 0; @@ -33,7 +32,7 @@ void setup() gw.sendSketchInfo("Servo", "1.0"); // Register all sensors to gw (they will be created as child devices) - gw.sendSensorPresentation(CHILD_ID, S_COVER); + gw.present(CHILD_ID, S_COVER); // Fetch servo state at startup gw.getStatus(CHILD_ID, V_DIMMER);