From bfb8eff8262748d8497d7088a6e34d59b251b2fc Mon Sep 17 00:00:00 2001 From: Daniel Wiegert Date: Thu, 28 Aug 2014 14:30:42 +0200 Subject: [PATCH 1/5] Include more debug text in MINIMAL definition, and enable MINIMAL as default, saves 432bytes --- libraries/MySensors/utility/RF24.cpp | 3 ++- libraries/MySensors/utility/RF24.h | 4 ++-- libraries/MySensors/utility/RF24_config.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) mode change 100644 => 100755 libraries/MySensors/utility/RF24.cpp mode change 100644 => 100755 libraries/MySensors/utility/RF24.h mode change 100644 => 100755 libraries/MySensors/utility/RF24_config.h diff --git a/libraries/MySensors/utility/RF24.cpp b/libraries/MySensors/utility/RF24.cpp old mode 100644 new mode 100755 index 2efb7bb..38053ab --- a/libraries/MySensors/utility/RF24.cpp +++ b/libraries/MySensors/utility/RF24.cpp @@ -270,6 +270,7 @@ uint8_t RF24::get_status(void) } /****************************************************************************/ +#if !defined (MINIMAL) void RF24::print_status(uint8_t status) { @@ -325,7 +326,7 @@ void RF24::print_address_register(const char* name, uint8_t reg, uint8_t qty) printf_P(PSTR("\r\n")); } - +#endif /****************************************************************************/ RF24::RF24(uint8_t _cepin, uint8_t _cspin): diff --git a/libraries/MySensors/utility/RF24.h b/libraries/MySensors/utility/RF24.h old mode 100644 new mode 100755 index 55253bb..89ed231 --- a/libraries/MySensors/utility/RF24.h +++ b/libraries/MySensors/utility/RF24.h @@ -863,7 +863,7 @@ private: * @return Current value of status register */ uint8_t get_status(void); - +#if !defined (MINIMAL) /** * Decode and print the given status to stdout * @@ -907,7 +907,7 @@ private: * @param qty How many successive registers to print */ void print_address_register(const char* name, uint8_t reg, uint8_t qty = 1); - +#endif /** * Turn on or off the special features of the chip * diff --git a/libraries/MySensors/utility/RF24_config.h b/libraries/MySensors/utility/RF24_config.h old mode 100644 new mode 100755 index b7154a5..55962f1 --- a/libraries/MySensors/utility/RF24_config.h +++ b/libraries/MySensors/utility/RF24_config.h @@ -21,7 +21,7 @@ #include //TMRh20: - //#define MINIMAL + #define MINIMAL // saves 432 bytes! // Define _BV for non-Arduino platforms and for Arduino DUE #if defined (ARDUINO) From 4ffb53b091cd796e0d5cb2d5e8f26d448e0d6c0c Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Wed, 3 Sep 2014 23:59:36 +0200 Subject: [PATCH 2/5] Implementation of interrupt driven binary switch The difference between the interrupt driven binary switch example and the normal binary switch example is the following: * Interrupt example does not use debouncer because it rely on loop() iterating over time (but it sleeps between iterations) * Interrupt example is more power conservative because it sleeps as soon as it has sent updated data and no activity happens on the pin * Interrupt example is limited to only two IO pins for the sensor, due to limitations in the Arduino HW. The example uses the preprocessor to ensure that this is not misconfigured or sleep function can not be expected to behave as intended. --- .../BinarySwitchSensorInt.ino | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 libraries/MySensors/examples/BinarySwitchSensorInt/BinarySwitchSensorInt.ino diff --git a/libraries/MySensors/examples/BinarySwitchSensorInt/BinarySwitchSensorInt.ino b/libraries/MySensors/examples/BinarySwitchSensorInt/BinarySwitchSensorInt.ino new file mode 100644 index 0000000..033b2f0 --- /dev/null +++ b/libraries/MySensors/examples/BinarySwitchSensorInt/BinarySwitchSensorInt.ino @@ -0,0 +1,60 @@ +// Interrupt driven binary switch example +// Author: Patrick 'Anticimex' Fallberg +// Connect button or door/window reed switch between +// digitial I/O pin 3 (BUTTON_PIN below) and GND. +// This example is designed to fit Arduino Nano/Pro Mini + +#include +#include + +#define CHILD_ID 3 +#define BUTTON_PIN 3 // Arduino Digital I/O pin for button/reed switch + +#if (BUTTON_PIN < 2 || BUTTON_PIN > 3) +#error BUTTON_PIN must be either 2 or 3 for interrupts to work +#endif + +MySensor gw; + +// Change to V_LIGHT if you use S_LIGHT in presentation below +MyMessage msg(CHILD_ID,V_TRIPPED); + +void setup() +{ + gw.begin(); + + // Setup the button + pinMode(BUTTON_PIN,INPUT); + // Activate internal pull-up + digitalWrite(BUTTON_PIN,HIGH); + + // Send the sketch version information to the gateway and Controller + gw.sendSketchInfo("Binary Sensor", "1.0"); + + // 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. See "msg" above. + gw.present(CHILD_ID, S_DOOR); +} + +// Loop will iterate on changes on the BUTTON_PIN +void loop() +{ + uint8_t value; + static uint8_t sentValue=2; + + // Short delay to allow button to properly settle + gw.sleep(5); + + value = digitalRead(BUTTON_PIN); + + if (value != sentValue) { + // Value has changed from last transmission, send the updated value + gw.send(msg.set(value==HIGH ? 1 : 0)); + sentValue = value; + } + + // Sleep until something happens with the sensor + gw.sleep(BUTTON_PIN-2, CHANGE, 0); +} + From ae35b9a05885fa9712b0ac868b9c0fb8e2734f96 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 7 Sep 2014 15:22:58 +0200 Subject: [PATCH 3/5] Minor refactoring of delay variables This is a preparation for handling multiple interrupts in delay(). It also reduces the size of the interrupt-related variables and arguments to int8_t as that should be ample enough for any Arduino implementation. --- libraries/MySensors/MySensor.cpp | 36 +++++++++++++++++--------------- libraries/MySensors/MySensor.h | 2 +- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index 55b15ee..ae4e519 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -465,43 +465,45 @@ int MySensor::getInternalTemp(void) return result/10000; } -int continueTimer = true; +int8_t pinIntTrigger = 0; void wakeUp() //place to send the interrupts { - continueTimer = false; + pinIntTrigger = 1; } void MySensor::internalSleep(unsigned long 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; } + while (!pinIntTrigger && ms >= 8000) { LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); ms -= 8000; } + if (!pinIntTrigger && ms >= 4000) { LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF); ms -= 4000; } + if (!pinIntTrigger && ms >= 2000) { LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF); ms -= 2000; } + if (!pinIntTrigger && ms >= 1000) { LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF); ms -= 1000; } + if (!pinIntTrigger && ms >= 500) { LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF); ms -= 500; } + if (!pinIntTrigger && ms >= 250) { LowPower.powerDown(SLEEP_250MS, ADC_OFF, BOD_OFF); ms -= 250; } + if (!pinIntTrigger && ms >= 125) { LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_OFF); ms -= 120; } + if (!pinIntTrigger && ms >= 64) { LowPower.powerDown(SLEEP_60MS, ADC_OFF, BOD_OFF); ms -= 60; } + if (!pinIntTrigger && ms >= 32) { LowPower.powerDown(SLEEP_30MS, ADC_OFF, BOD_OFF); ms -= 30; } + if (!pinIntTrigger && ms >= 16) { LowPower.powerDown(SLEEP_15Ms, ADC_OFF, BOD_OFF); ms -= 15; } } void MySensor::sleep(unsigned long ms) { // Let serial prints finish (debug, log etc) Serial.flush(); RF24::powerDown(); - continueTimer = true; + pinIntTrigger = 0; internalSleep(ms); } -bool MySensor::sleep(int interrupt, int mode, unsigned long ms) { +bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { // Let serial prints finish (debug, log etc) bool pinTriggeredWakeup = true; Serial.flush(); RF24::powerDown(); - attachInterrupt(interrupt, wakeUp, mode); //Interrupt on pin 3 for any change in solar power + attachInterrupt(interrupt, wakeUp, mode); if (ms>0) { - continueTimer = true; + pinIntTrigger = 0; sleep(ms); - pinTriggeredWakeup = !continueTimer; + if (0 == pinIntTrigger) { + pinTriggeredWakeup = false; + } } else { Serial.flush(); LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index f6dbba1..d8f0adf 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -219,7 +219,7 @@ class MySensor : public RF24 * @param ms Number of milliseconds to sleep or 0 to sleep forever * @return true if wake up was triggered by pin change and false means timer woke it up. */ - bool sleep(int interrupt, int mode, unsigned long ms=0); + bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); /** * getInternalTemp From 35788d6d94b3184343e7995da6ca1162625ad328 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 7 Sep 2014 15:53:57 +0200 Subject: [PATCH 4/5] Added constructor to sleep() for monitoring two interrupts The new constructor allows two separate interrupts with two separate trigger policies to wake up device. --- libraries/MySensors/MySensor.cpp | 29 +++++++++++++++++++++++++++++ libraries/MySensors/MySensor.h | 13 +++++++++++++ 2 files changed, 42 insertions(+) diff --git a/libraries/MySensors/MySensor.cpp b/libraries/MySensors/MySensor.cpp index ae4e519..e7002d5 100755 --- a/libraries/MySensors/MySensor.cpp +++ b/libraries/MySensors/MySensor.cpp @@ -470,6 +470,10 @@ void wakeUp() //place to send the interrupts { pinIntTrigger = 1; } +void wakeUp2() //place to send the second interrupts +{ + pinIntTrigger = 2; +} void MySensor::internalSleep(unsigned long ms) { while (!pinIntTrigger && ms >= 8000) { LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); ms -= 8000; } @@ -512,7 +516,32 @@ bool MySensor::sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { return pinTriggeredWakeup; } +int8_t MySensor::sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { + int8_t retVal = 1; + Serial.flush(); // Let serial prints finish (debug, log etc) + RF24::powerDown(); + attachInterrupt(interrupt1, wakeUp, mode1); + attachInterrupt(interrupt2, wakeUp2, mode2); + if (ms>0) { + pinIntTrigger = 0; + sleep(ms); + if (0 == pinIntTrigger) { + retVal = -1; + } + } else { + Serial.flush(); + LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); + } + detachInterrupt(interrupt1); + detachInterrupt(interrupt2); + if (1 == pinIntTrigger) { + retVal = (int8_t)interrupt1; + } else if (2 == pinIntTrigger) { + retVal = (int8_t)interrupt2; + } + return retVal; +} #ifdef DEBUG void MySensor::debugPrint(const char *fmt, ... ) { diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index d8f0adf..a69e48c 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -221,6 +221,19 @@ class MySensor : public RF24 */ bool sleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); + /** + * Sleep (PowerDownMode) the Arduino and radio. Wake up on timer or pin change for two separate interrupts. + * 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 interrupt1 First interrupt that should trigger the wakeup + * @param mode1 Mode for first interrupt (RISING, FALLING, CHANGE) + * @param interrupt2 Second interrupt that should trigger the wakeup + * @param mode2 Mode for second interrupt (RISING, FALLING, CHANGE) + * @param ms Number of milliseconds to sleep or 0 to sleep forever + * @return Interrupt number wake up was triggered by pin change and negative if timer woke it up. + */ + int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); + /** * getInternalTemp * From c13425d15eb13232c9cd6eac520ec4e6f5aafcdf Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 7 Sep 2014 17:43:51 +0200 Subject: [PATCH 5/5] Updated BinarySwitchSensorInt to handle two sensors The new sleep() constructor allows for two interrupt sources to wake device from sleep. This example is now updated to illustrate this. --- .../BinarySwitchSensorInt.ino | 82 +++++++++++++------ 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/libraries/MySensors/examples/BinarySwitchSensorInt/BinarySwitchSensorInt.ino b/libraries/MySensors/examples/BinarySwitchSensorInt/BinarySwitchSensorInt.ino index 033b2f0..ff8637a 100644 --- a/libraries/MySensors/examples/BinarySwitchSensorInt/BinarySwitchSensorInt.ino +++ b/libraries/MySensors/examples/BinarySwitchSensorInt/BinarySwitchSensorInt.ino @@ -1,60 +1,90 @@ -// Interrupt driven binary switch example +// Interrupt driven binary switch example with dual interrupts // Author: Patrick 'Anticimex' Fallberg -// Connect button or door/window reed switch between -// digitial I/O pin 3 (BUTTON_PIN below) and GND. +// Connect one button or door/window reed switch between +// digitial I/O pin 3 (BUTTON_PIN below) and GND and the other +// one in similar fashion on digital I/O pin 2. // This example is designed to fit Arduino Nano/Pro Mini #include #include -#define CHILD_ID 3 -#define BUTTON_PIN 3 // Arduino Digital I/O pin for button/reed switch +#define SKETCH_NAME "Binary Sensor" +#define SKETCH_MAJOR_VER "1" +#define SKETCH_MINOR_VER "0" -#if (BUTTON_PIN < 2 || BUTTON_PIN > 3) -#error BUTTON_PIN must be either 2 or 3 for interrupts to work +#define PRIMARY_CHILD_ID 3 +#define SECONDARY_CHILD_ID 4 + +#define PRIMARY_BUTTON_PIN 2 // Arduino Digital I/O pin for button/reed switch +#define SECONDARY_BUTTON_PIN 3 // Arduino Digital I/O pin for button/reed switch + +#if (PRIMARY_BUTTON_PIN < 2 || PRIMARY_BUTTON_PIN > 3) +#error PRIMARY_BUTTON_PIN must be either 2 or 3 for interrupts to work #endif - -MySensor gw; +#if (SECONDARY_BUTTON_PIN < 2 || SECONDARY_BUTTON_PIN > 3) +#error SECONDARY_BUTTON_PIN must be either 2 or 3 for interrupts to work +#endif +#if (PRIMARY_BUTTON_PIN == SECONDARY_BUTTON_PIN) +#error PRIMARY_BUTTON_PIN and BUTTON_PIN2 cannot be the same +#endif +#if (PRIMARY_CHILD_ID == SECONDARY_CHILD_ID) +#error PRIMARY_CHILD_ID and SECONDARY_CHILD_ID cannot be the same +#endif + +MySensor sensor_node; // Change to V_LIGHT if you use S_LIGHT in presentation below -MyMessage msg(CHILD_ID,V_TRIPPED); +MyMessage msg(PRIMARY_CHILD_ID, V_TRIPPED); +MyMessage msg2(SECONDARY_CHILD_ID, V_TRIPPED); void setup() { - gw.begin(); + sensor_node.begin(); - // Setup the button - pinMode(BUTTON_PIN,INPUT); - // Activate internal pull-up - digitalWrite(BUTTON_PIN,HIGH); + // Setup the buttons + pinMode(PRIMARY_BUTTON_PIN, INPUT); + pinMode(SECONDARY_BUTTON_PIN, INPUT); + + // Activate internal pull-ups + digitalWrite(PRIMARY_BUTTON_PIN, HIGH); + digitalWrite(SECONDARY_BUTTON_PIN, HIGH); // Send the sketch version information to the gateway and Controller - gw.sendSketchInfo("Binary Sensor", "1.0"); + sensor_node.sendSketchInfo(SKETCH_NAME, SKETCH_MAJOR_VER"."SKETCH_MINOR_VER); - // Register binary input sensor to gw (they will be created as child devices) + // Register binary input sensor to sensor_node (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. See "msg" above. - gw.present(CHILD_ID, S_DOOR); + sensor_node.present(PRIMARY_CHILD_ID, S_DOOR); + sensor_node.present(SECONDARY_CHILD_ID, S_DOOR); } -// Loop will iterate on changes on the BUTTON_PIN +// Loop will iterate on changes on the BUTTON_PINs void loop() { uint8_t value; static uint8_t sentValue=2; + static uint8_t sentValue2=2; - // Short delay to allow button to properly settle - gw.sleep(5); + // Short delay to allow buttons to properly settle + sensor_node.sleep(5); - value = digitalRead(BUTTON_PIN); + value = digitalRead(PRIMARY_BUTTON_PIN); if (value != sentValue) { // Value has changed from last transmission, send the updated value - gw.send(msg.set(value==HIGH ? 1 : 0)); + sensor_node.send(msg.set(value==HIGH ? 1 : 0)); sentValue = value; } - // Sleep until something happens with the sensor - gw.sleep(BUTTON_PIN-2, CHANGE, 0); -} + value = digitalRead(SECONDARY_BUTTON_PIN); + + if (value != sentValue2) { + // Value has changed from last transmission, send the updated value + sensor_node.send(msg2.set(value==HIGH ? 1 : 0)); + sentValue2 = value; + } + // Sleep until something happens with the sensor + sensor_node.sleep(PRIMARY_BUTTON_PIN-2, CHANGE, SECONDARY_BUTTON_PIN-2, CHANGE, 0); +}