Windows Arduino 1.0.X does not like to import zip files. Unzipped to make installation easier.
This commit is contained in:
357
synchronizer/libraries/TimeAlarms/TimeAlarms.cpp
Normal file
357
synchronizer/libraries/TimeAlarms/TimeAlarms.cpp
Normal file
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
TimeAlarms.cpp - Arduino Time alarms for use with Time library
|
||||
Copyright (c) 208-2011 Michael Margolis.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
/*
|
||||
2 July 2011 - replaced alarm types implied from alarm value with enums to make trigger logic more robust
|
||||
- this fixes bug in repeating weekly alarms - thanks to Vincent Valdy and draythomp for testing
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include <string.h> // for memset
|
||||
}
|
||||
|
||||
#if ARDUINO > 22
|
||||
#include <Arduino.h>
|
||||
#else
|
||||
#include <WProgram.h>
|
||||
#endif
|
||||
|
||||
#include "TimeAlarms.h"
|
||||
#include "Time.h"
|
||||
|
||||
#define IS_ONESHOT true // constants used in arguments to create method
|
||||
#define IS_REPEAT false
|
||||
|
||||
|
||||
//**************************************************************
|
||||
//* Alarm Class Constructor
|
||||
|
||||
AlarmClass::AlarmClass()
|
||||
{
|
||||
Mode.isEnabled = Mode.isOneShot = 0;
|
||||
Mode.alarmType = dtNotAllocated;
|
||||
value = nextTrigger = 0;
|
||||
onTickHandler = NULL; // prevent a callback until this pointer is explicitly set
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
//* Private Methods
|
||||
|
||||
|
||||
void AlarmClass::updateNextTrigger()
|
||||
{
|
||||
if( (value != 0) && Mode.isEnabled )
|
||||
{
|
||||
time_t time = now();
|
||||
if( dtIsAlarm(Mode.alarmType) && nextTrigger <= time ) // update alarm if next trigger is not yet in the future
|
||||
{
|
||||
if(Mode.alarmType == dtExplicitAlarm ) // is the value a specific date and time in the future
|
||||
{
|
||||
nextTrigger = value; // yes, trigger on this value
|
||||
}
|
||||
else if(Mode.alarmType == dtDailyAlarm) //if this is a daily alarm
|
||||
{
|
||||
if( value + previousMidnight(now()) <= time)
|
||||
{
|
||||
nextTrigger = value + nextMidnight(time); // if time has passed then set for tomorrow
|
||||
}
|
||||
else
|
||||
{
|
||||
nextTrigger = value + previousMidnight(time); // set the date to today and add the time given in value
|
||||
}
|
||||
}
|
||||
else if(Mode.alarmType == dtWeeklyAlarm) // if this is a weekly alarm
|
||||
{
|
||||
if( (value + previousSunday(now())) <= time)
|
||||
{
|
||||
nextTrigger = value + nextSunday(time); // if day has passed then set for the next week.
|
||||
}
|
||||
else
|
||||
{
|
||||
nextTrigger = value + previousSunday(time); // set the date to this week today and add the time given in value
|
||||
}
|
||||
}
|
||||
else // its not a recognized alarm type - this should not happen
|
||||
{
|
||||
Mode.isEnabled = 0; // Disable the alarm
|
||||
}
|
||||
}
|
||||
if( Mode.alarmType == dtTimer)
|
||||
{
|
||||
// its a timer
|
||||
nextTrigger = time + value; // add the value to previous time (this ensures delay always at least Value seconds)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Mode.isEnabled = 0; // Disable if the value is 0
|
||||
}
|
||||
}
|
||||
|
||||
//**************************************************************
|
||||
//* Time Alarms Public Methods
|
||||
|
||||
TimeAlarmsClass::TimeAlarmsClass()
|
||||
{
|
||||
isServicing = false;
|
||||
for(uint8_t id = 0; id < dtNBR_ALARMS; id++)
|
||||
free(id); // ensure all Alarms are cleared and available for allocation
|
||||
}
|
||||
|
||||
// this method creates a trigger at the given absolute time_t
|
||||
// it replaces the call to alarmOnce with values greater than a week
|
||||
AlarmID_t TimeAlarmsClass::triggerOnce(time_t value, OnTick_t onTickHandler){ // trigger once at the given time_t
|
||||
if( value > 0)
|
||||
return create( value, onTickHandler, IS_ONESHOT, dtExplicitAlarm );
|
||||
else
|
||||
return dtINVALID_ALARM_ID; // dont't allocate if the time is greater than one day
|
||||
}
|
||||
|
||||
// this method will now return an error if the value is greater than one day - use DOW methods for weekly alarms
|
||||
AlarmID_t TimeAlarmsClass::alarmOnce(time_t value, OnTick_t onTickHandler){ // trigger once at the given time of day
|
||||
if( value <= SECS_PER_DAY)
|
||||
return create( value, onTickHandler, IS_ONESHOT, dtDailyAlarm );
|
||||
else
|
||||
return dtINVALID_ALARM_ID; // dont't allocate if the time is greater than one day
|
||||
}
|
||||
|
||||
AlarmID_t TimeAlarmsClass::alarmOnce(const int H, const int M, const int S,OnTick_t onTickHandler){ // as above with HMS arguments
|
||||
return create( AlarmHMS(H,M,S), onTickHandler, IS_ONESHOT, dtDailyAlarm );
|
||||
}
|
||||
|
||||
AlarmID_t TimeAlarmsClass::alarmOnce(const timeDayOfWeek_t DOW, const int H, const int M, const int S, OnTick_t onTickHandler){ // as above, with day of week
|
||||
return create( (DOW-1) * SECS_PER_DAY + AlarmHMS(H,M,S), onTickHandler, IS_ONESHOT, dtWeeklyAlarm );
|
||||
}
|
||||
|
||||
// this method will now return an error if the value is greater than one day - use DOW methods for weekly alarms
|
||||
AlarmID_t TimeAlarmsClass::alarmRepeat(time_t value, OnTick_t onTickHandler){ // trigger daily at the given time
|
||||
if( value <= SECS_PER_DAY)
|
||||
return create( value, onTickHandler, IS_REPEAT, dtDailyAlarm );
|
||||
else
|
||||
return dtINVALID_ALARM_ID; // dont't allocate if the time is greater than one day
|
||||
}
|
||||
|
||||
AlarmID_t TimeAlarmsClass::alarmRepeat(const int H, const int M, const int S, OnTick_t onTickHandler){ // as above with HMS arguments
|
||||
return create( AlarmHMS(H,M,S), onTickHandler, IS_REPEAT, dtDailyAlarm );
|
||||
}
|
||||
|
||||
AlarmID_t TimeAlarmsClass::alarmRepeat(const timeDayOfWeek_t DOW, const int H, const int M, const int S, OnTick_t onTickHandler){ // as above, with day of week
|
||||
return create( (DOW-1) * SECS_PER_DAY + AlarmHMS(H,M,S), onTickHandler, IS_REPEAT, dtWeeklyAlarm );
|
||||
}
|
||||
|
||||
AlarmID_t TimeAlarmsClass::timerOnce(time_t value, OnTick_t onTickHandler){ // trigger once after the given number of seconds
|
||||
return create( value, onTickHandler, IS_ONESHOT, dtTimer );
|
||||
}
|
||||
|
||||
AlarmID_t TimeAlarmsClass::timerOnce(const int H, const int M, const int S, OnTick_t onTickHandler){ // As above with HMS arguments
|
||||
return create( AlarmHMS(H,M,S), onTickHandler, IS_ONESHOT, dtTimer );
|
||||
}
|
||||
|
||||
AlarmID_t TimeAlarmsClass::timerRepeat(time_t value, OnTick_t onTickHandler){ // trigger after the given number of seconds continuously
|
||||
return create( value, onTickHandler, IS_REPEAT, dtTimer);
|
||||
}
|
||||
|
||||
AlarmID_t TimeAlarmsClass::timerRepeat(const int H, const int M, const int S, OnTick_t onTickHandler){ // trigger after the given number of seconds continuously
|
||||
return create( AlarmHMS(H,M,S), onTickHandler, IS_REPEAT, dtTimer);
|
||||
}
|
||||
|
||||
void TimeAlarmsClass::enable(AlarmID_t ID)
|
||||
{
|
||||
if(isAllocated(ID)) {
|
||||
Alarm[ID].Mode.isEnabled = (Alarm[ID].value != 0) && (Alarm[ID].onTickHandler != 0) ; // only enable if value is non zero and a tick handler has been set
|
||||
Alarm[ID].updateNextTrigger(); // trigger is updated whenever this is called, even if already enabled
|
||||
}
|
||||
}
|
||||
|
||||
void TimeAlarmsClass::disable(AlarmID_t ID)
|
||||
{
|
||||
if(isAllocated(ID))
|
||||
Alarm[ID].Mode.isEnabled = false;
|
||||
}
|
||||
|
||||
// write the given value to the given alarm
|
||||
void TimeAlarmsClass::write(AlarmID_t ID, time_t value)
|
||||
{
|
||||
if(isAllocated(ID))
|
||||
{
|
||||
Alarm[ID].value = value;
|
||||
enable(ID); // update trigger time
|
||||
}
|
||||
}
|
||||
|
||||
// return the value for the given alarm ID
|
||||
time_t TimeAlarmsClass::read(AlarmID_t ID)
|
||||
{
|
||||
if(isAllocated(ID))
|
||||
return Alarm[ID].value ;
|
||||
else
|
||||
return dtINVALID_TIME;
|
||||
}
|
||||
|
||||
// return the alarm type for the given alarm ID
|
||||
dtAlarmPeriod_t TimeAlarmsClass::readType(AlarmID_t ID)
|
||||
{
|
||||
if(isAllocated(ID))
|
||||
return (dtAlarmPeriod_t)Alarm[ID].Mode.alarmType ;
|
||||
else
|
||||
return dtNotAllocated;
|
||||
}
|
||||
|
||||
void TimeAlarmsClass::free(AlarmID_t ID)
|
||||
{
|
||||
if(isAllocated(ID))
|
||||
{
|
||||
Alarm[ID].Mode.isEnabled = false;
|
||||
Alarm[ID].Mode.alarmType = dtNotAllocated;
|
||||
Alarm[ID].onTickHandler = 0;
|
||||
Alarm[ID].value = 0;
|
||||
Alarm[ID].nextTrigger = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// returns the number of allocated timers
|
||||
uint8_t TimeAlarmsClass::count()
|
||||
{
|
||||
uint8_t c = 0;
|
||||
for(uint8_t id = 0; id < dtNBR_ALARMS; id++)
|
||||
{
|
||||
if(isAllocated(id))
|
||||
c++;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
// returns true only if id is allocated and the type is a time based alarm, returns false if not allocated or if its a timer
|
||||
bool TimeAlarmsClass::isAlarm(AlarmID_t ID)
|
||||
{
|
||||
return( isAllocated(ID) && dtIsAlarm(Alarm[ID].Mode.alarmType) );
|
||||
}
|
||||
|
||||
// returns true if this id is allocated
|
||||
bool TimeAlarmsClass::isAllocated(AlarmID_t ID)
|
||||
{
|
||||
return( ID < dtNBR_ALARMS && Alarm[ID].Mode.alarmType != dtNotAllocated );
|
||||
}
|
||||
|
||||
|
||||
AlarmID_t TimeAlarmsClass::getTriggeredAlarmId() //returns the currently triggered alarm id
|
||||
// returns dtINVALID_ALARM_ID if not invoked from within an alarm handler
|
||||
{
|
||||
if(isServicing)
|
||||
return servicedAlarmId; // new private data member used instead of local loop variable i in serviceAlarms();
|
||||
else
|
||||
return dtINVALID_ALARM_ID; // valid ids only available when servicing a callback
|
||||
}
|
||||
|
||||
// following functions are not Alarm ID specific.
|
||||
void TimeAlarmsClass::delay(unsigned long ms)
|
||||
{
|
||||
unsigned long start = millis();
|
||||
while( millis() - start <= ms)
|
||||
serviceAlarms();
|
||||
}
|
||||
|
||||
void TimeAlarmsClass::waitForDigits( uint8_t Digits, dtUnits_t Units)
|
||||
{
|
||||
while(Digits != getDigitsNow(Units) )
|
||||
{
|
||||
serviceAlarms();
|
||||
}
|
||||
}
|
||||
|
||||
void TimeAlarmsClass::waitForRollover( dtUnits_t Units)
|
||||
{
|
||||
while(getDigitsNow(Units) == 0 ) // if its just rolled over than wait for another rollover
|
||||
serviceAlarms();
|
||||
waitForDigits(0, Units);
|
||||
}
|
||||
|
||||
uint8_t TimeAlarmsClass::getDigitsNow( dtUnits_t Units)
|
||||
{
|
||||
time_t time = now();
|
||||
if(Units == dtSecond) return numberOfSeconds(time);
|
||||
if(Units == dtMinute) return numberOfMinutes(time);
|
||||
if(Units == dtHour) return numberOfHours(time);
|
||||
if(Units == dtDay) return dayOfWeek(time);
|
||||
return 255; // This should never happen
|
||||
}
|
||||
|
||||
//***********************************************************
|
||||
//* Private Methods
|
||||
|
||||
void TimeAlarmsClass::serviceAlarms()
|
||||
{
|
||||
if(! isServicing)
|
||||
{
|
||||
isServicing = true;
|
||||
for( servicedAlarmId = 0; servicedAlarmId < dtNBR_ALARMS; servicedAlarmId++)
|
||||
{
|
||||
if( Alarm[servicedAlarmId].Mode.isEnabled && (now() >= Alarm[servicedAlarmId].nextTrigger) )
|
||||
{
|
||||
OnTick_t TickHandler = Alarm[servicedAlarmId].onTickHandler;
|
||||
if(Alarm[servicedAlarmId].Mode.isOneShot)
|
||||
free(servicedAlarmId); // free the ID if mode is OnShot
|
||||
else
|
||||
Alarm[servicedAlarmId].updateNextTrigger();
|
||||
if( TickHandler != NULL) {
|
||||
(*TickHandler)(); // call the handler
|
||||
}
|
||||
}
|
||||
}
|
||||
isServicing = false;
|
||||
}
|
||||
}
|
||||
|
||||
// returns the absolute time of the next scheduled alarm, or 0 if none
|
||||
time_t TimeAlarmsClass::getNextTrigger()
|
||||
{
|
||||
time_t nextTrigger = 0xffffffff; // the max time value
|
||||
|
||||
for(uint8_t id = 0; id < dtNBR_ALARMS; id++)
|
||||
{
|
||||
if(isAllocated(id) )
|
||||
{
|
||||
if(Alarm[id].nextTrigger < nextTrigger)
|
||||
nextTrigger = Alarm[id].nextTrigger;
|
||||
}
|
||||
}
|
||||
return nextTrigger == 0xffffffff ? 0 : nextTrigger;
|
||||
}
|
||||
|
||||
// attempt to create an alarm and return true if successful
|
||||
AlarmID_t TimeAlarmsClass::create( time_t value, OnTick_t onTickHandler, uint8_t isOneShot, dtAlarmPeriod_t alarmType, uint8_t isEnabled)
|
||||
{
|
||||
if( ! (dtIsAlarm(alarmType) && now() < SECS_PER_YEAR)) // only create alarm ids if the time is at least Jan 1 1971
|
||||
{
|
||||
for(uint8_t id = 0; id < dtNBR_ALARMS; id++)
|
||||
{
|
||||
if( Alarm[id].Mode.alarmType == dtNotAllocated )
|
||||
{
|
||||
// here if there is an Alarm id that is not allocated
|
||||
Alarm[id].onTickHandler = onTickHandler;
|
||||
Alarm[id].Mode.isOneShot = isOneShot;
|
||||
Alarm[id].Mode.alarmType = alarmType;
|
||||
Alarm[id].value = value;
|
||||
isEnabled ? enable(id) : disable(id);
|
||||
return id; // alarm created ok
|
||||
}
|
||||
}
|
||||
}
|
||||
return dtINVALID_ALARM_ID; // no IDs available or time is invalid
|
||||
}
|
||||
|
||||
// make one instance for the user to use
|
||||
TimeAlarmsClass Alarm = TimeAlarmsClass() ;
|
||||
|
||||
127
synchronizer/libraries/TimeAlarms/TimeAlarms.h
Normal file
127
synchronizer/libraries/TimeAlarms/TimeAlarms.h
Normal file
@@ -0,0 +1,127 @@
|
||||
// TimeAlarms.h - Arduino Time alarms header for use with Time library
|
||||
|
||||
#ifndef TimeAlarms_h
|
||||
#define TimeAlarms_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Time.h"
|
||||
|
||||
#define dtNBR_ALARMS 6 // max is 255
|
||||
|
||||
#define USE_SPECIALIST_METHODS // define this for testing
|
||||
|
||||
typedef enum { dtMillisecond, dtSecond, dtMinute, dtHour, dtDay } dtUnits_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t alarmType :4 ; // enumeration of daily/weekly (in future: biweekly/semimonthly/monthly/annual)
|
||||
// note that the current API only supports daily or weekly alarm periods
|
||||
uint8_t isEnabled :1 ; // the timer is only actioned if isEnabled is true
|
||||
uint8_t isOneShot :1 ; // the timer will be de-allocated after trigger is processed
|
||||
}
|
||||
AlarmMode_t ;
|
||||
|
||||
// new time based alarms should be added just before dtLastAlarmType
|
||||
typedef enum {dtNotAllocated, dtTimer, dtExplicitAlarm, dtDailyAlarm, dtWeeklyAlarm, dtLastAlarmType } dtAlarmPeriod_t ; // in future: dtBiweekly, dtMonthly, dtAnnual
|
||||
|
||||
// macro to return true if the given type is a time based alarm, false if timer or not allocated
|
||||
#define dtIsAlarm(_type_) (_type_ >= dtExplicitAlarm && _type_ < dtLastAlarmType)
|
||||
|
||||
typedef uint8_t AlarmID_t;
|
||||
typedef AlarmID_t AlarmId; // Arduino friendly name
|
||||
|
||||
#define dtINVALID_ALARM_ID 255
|
||||
#define dtINVALID_TIME 0L
|
||||
|
||||
class AlarmClass; // forward reference
|
||||
typedef void (*OnTick_t)(); // alarm callback function typedef
|
||||
|
||||
// class defining an alarm instance, only used by dtAlarmsClass
|
||||
class AlarmClass
|
||||
{
|
||||
private:
|
||||
|
||||
public:
|
||||
AlarmClass();
|
||||
OnTick_t onTickHandler;
|
||||
void updateNextTrigger();
|
||||
time_t value;
|
||||
time_t nextTrigger;
|
||||
AlarmMode_t Mode;
|
||||
};
|
||||
|
||||
// class containing the collection of alarms
|
||||
class TimeAlarmsClass
|
||||
{
|
||||
private:
|
||||
AlarmClass Alarm[dtNBR_ALARMS];
|
||||
void serviceAlarms();
|
||||
uint8_t isServicing;
|
||||
uint8_t servicedAlarmId; // the alarm currently being serviced
|
||||
AlarmID_t create( time_t value, OnTick_t onTickHandler, uint8_t isOneShot, dtAlarmPeriod_t alarmType, uint8_t isEnabled=true);
|
||||
|
||||
public:
|
||||
TimeAlarmsClass();
|
||||
// functions to create alarms and timers
|
||||
|
||||
AlarmID_t triggerOnce(time_t value, OnTick_t onTickHandler); // trigger once at the given time_t
|
||||
|
||||
AlarmID_t alarmRepeat(time_t value, OnTick_t onTickHandler); // trigger daily at given time of day
|
||||
AlarmID_t alarmRepeat(const int H, const int M, const int S, OnTick_t onTickHandler); // as above, with hms arguments
|
||||
AlarmID_t alarmRepeat(const timeDayOfWeek_t DOW, const int H, const int M, const int S, OnTick_t onTickHandler); // as above, with day of week
|
||||
|
||||
AlarmID_t alarmOnce(time_t value, OnTick_t onTickHandler); // trigger once at given time of day
|
||||
AlarmID_t alarmOnce( const int H, const int M, const int S, OnTick_t onTickHandler); // as above, with hms arguments
|
||||
AlarmID_t alarmOnce(const timeDayOfWeek_t DOW, const int H, const int M, const int S, OnTick_t onTickHandler); // as above, with day of week
|
||||
|
||||
AlarmID_t timerOnce(time_t value, OnTick_t onTickHandler); // trigger once after the given number of seconds
|
||||
AlarmID_t timerOnce(const int H, const int M, const int S, OnTick_t onTickHandler); // As above with HMS arguments
|
||||
|
||||
AlarmID_t timerRepeat(time_t value, OnTick_t onTickHandler); // trigger after the given number of seconds continuously
|
||||
AlarmID_t timerRepeat(const int H, const int M, const int S, OnTick_t onTickHandler); // As above with HMS arguments
|
||||
|
||||
void delay(unsigned long ms);
|
||||
|
||||
// utility methods
|
||||
uint8_t getDigitsNow( dtUnits_t Units); // returns the current digit value for the given time unit
|
||||
void waitForDigits( uint8_t Digits, dtUnits_t Units);
|
||||
void waitForRollover(dtUnits_t Units);
|
||||
|
||||
// low level methods
|
||||
void enable(AlarmID_t ID); // enable the alarm to trigger
|
||||
void disable(AlarmID_t ID); // prevent the alarm from triggering
|
||||
AlarmID_t getTriggeredAlarmId(); // returns the currently triggered alarm id
|
||||
void write(AlarmID_t ID, time_t value); // write the value (and enable) the alarm with the given ID
|
||||
time_t read(AlarmID_t ID); // return the value for the given timer
|
||||
dtAlarmPeriod_t readType(AlarmID_t ID); // return the alarm type for the given alarm ID
|
||||
|
||||
#ifndef USE_SPECIALIST_METHODS
|
||||
private: // the following methods are for testing and are not documented as part of the standard library
|
||||
#endif
|
||||
void free(AlarmID_t ID); // free the id to allow its reuse
|
||||
uint8_t count(); // returns the number of allocated timers
|
||||
time_t getNextTrigger(); // returns the time of the next scheduled alarm
|
||||
bool isAllocated(AlarmID_t ID); // returns true if this id is allocated
|
||||
bool isAlarm(AlarmID_t ID); // returns true if id is for a time based alarm, false if its a timer or not allocated
|
||||
};
|
||||
|
||||
extern TimeAlarmsClass Alarm; // make an instance for the user
|
||||
|
||||
/*==============================================================================
|
||||
* MACROS
|
||||
*============================================================================*/
|
||||
|
||||
/* public */
|
||||
#define waitUntilThisSecond(_val_) waitForDigits( _val_, dtSecond)
|
||||
#define waitUntilThisMinute(_val_) waitForDigits( _val_, dtMinute)
|
||||
#define waitUntilThisHour(_val_) waitForDigits( _val_, dtHour)
|
||||
#define waitUntilThisDay(_val_) waitForDigits( _val_, dtDay)
|
||||
#define waitMinuteRollover() waitForRollover(dtSecond)
|
||||
#define waitHourRollover() waitForRollover(dtMinute)
|
||||
#define waitDayRollover() waitForRollover(dtHour)
|
||||
|
||||
#define AlarmHMS(_hr_, _min_, _sec_) (_hr_ * SECS_PER_HOUR + _min_ * SECS_PER_MIN + _sec_)
|
||||
|
||||
|
||||
#endif /* TimeAlarms_h */
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* TimeAlarmExample.pde
|
||||
*
|
||||
* This example calls alarm functions at 8:30 am and at 5:45 pm (17:45)
|
||||
* and simulates turning lights on at night and off in the morning
|
||||
* A weekly timer is set for Saturdays at 8:30:30
|
||||
*
|
||||
* A timer is called every 15 seconds
|
||||
* Another timer is called once only after 10 seconds
|
||||
*
|
||||
* At startup the time is set to Jan 1 2011 8:29 am
|
||||
*/
|
||||
|
||||
#include <Time.h>
|
||||
#include <TimeAlarms.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
setTime(8,29,0,1,1,11); // set time to Saturday 8:29:00am Jan 1 2011
|
||||
// create the alarms
|
||||
Alarm.alarmRepeat(8,30,0, MorningAlarm); // 8:30am every day
|
||||
Alarm.alarmRepeat(17,45,0,EveningAlarm); // 5:45pm every day
|
||||
Alarm.alarmRepeat(dowSaturday,8,30,30,WeeklyAlarm); // 8:30:30 every Saturday
|
||||
|
||||
|
||||
Alarm.timerRepeat(15, Repeats); // timer for every 15 seconds
|
||||
Alarm.timerOnce(10, OnceOnly); // called once after 10 seconds
|
||||
}
|
||||
|
||||
void loop(){
|
||||
digitalClockDisplay();
|
||||
Alarm.delay(1000); // wait one second between clock display
|
||||
}
|
||||
|
||||
// functions to be called when an alarm triggers:
|
||||
void MorningAlarm(){
|
||||
Serial.println("Alarm: - turn lights off");
|
||||
}
|
||||
|
||||
void EveningAlarm(){
|
||||
Serial.println("Alarm: - turn lights on");
|
||||
}
|
||||
|
||||
void WeeklyAlarm(){
|
||||
Serial.println("Alarm: - its Monday Morning");
|
||||
}
|
||||
|
||||
void ExplicitAlarm(){
|
||||
Serial.println("Alarm: - this triggers only at the given date and time");
|
||||
}
|
||||
|
||||
void Repeats(){
|
||||
Serial.println("15 second timer");
|
||||
}
|
||||
|
||||
void OnceOnly(){
|
||||
Serial.println("This timer only triggers once");
|
||||
}
|
||||
|
||||
void digitalClockDisplay()
|
||||
{
|
||||
// digital clock display of the time
|
||||
Serial.print(hour());
|
||||
printDigits(minute());
|
||||
printDigits(second());
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void printDigits(int digits)
|
||||
{
|
||||
Serial.print(":");
|
||||
if(digits < 10)
|
||||
Serial.print('0');
|
||||
Serial.print(digits);
|
||||
}
|
||||
|
||||
25
synchronizer/libraries/TimeAlarms/keywords.txt
Normal file
25
synchronizer/libraries/TimeAlarms/keywords.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For TimeAlarms
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
alarmRepeat KEYWORD2
|
||||
alarmOnce KEYWORD2
|
||||
timerRepeat KEYWORD2
|
||||
timerOnce KEYWORD2
|
||||
delay KEYWORD2
|
||||
#######################################
|
||||
# Instances (KEYWORD2)
|
||||
#######################################
|
||||
Alarm KEYWORD2
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
dtINVALID_ALARM_ID LITERAL1
|
||||
dtINVALID_TIME LITERAL1
|
||||
220
synchronizer/libraries/TimeAlarms/readme.txt
Normal file
220
synchronizer/libraries/TimeAlarms/readme.txt
Normal file
@@ -0,0 +1,220 @@
|
||||
Alarms
|
||||
|
||||
The Alarm library is a companion to the Time library that makes it easy to
|
||||
perform tasks at specific times or after specific intervals.
|
||||
|
||||
Tasks scheduled at a particular time of day are called Alarms,
|
||||
tasks scheduled after an interval of time has elapsed are called Timers.
|
||||
These tasks can be created to continuously repeat or to occur once only.
|
||||
|
||||
Here is how you create an alarm to trigger a task repeatedly at a particular time of day:
|
||||
Alarm.alarmRepeat(8,30,0, MorningAlarm);
|
||||
This would call the function MorningAlarm() at 8:30 am every day.
|
||||
|
||||
If you want the alarm to trigger only once you can use the alarmOnce method:
|
||||
Alarm.alarmOnce(8,30,0, MorningAlarm);
|
||||
This calls a MorningAlarm() function in a sketch once only (when the time is next 8:30am)
|
||||
|
||||
Alarms can be specified to trigger a task repeatedly at a particular day of week and time of day:
|
||||
Alarm.alarmRepeat(dowMonday, 9,15,0, MondayMorningAlarm);
|
||||
This would call the function WeeklyAlarm() at 9:15am every Monday.
|
||||
|
||||
If you want the alarm to trigger once only on a particular day and time you can do this:
|
||||
Alarm.alarmOnce(dowMonday, 9,15,0, MondayMorningAlarm);
|
||||
This would call the function MondayMorning() Alarm on the next Monday at 9:15am.
|
||||
|
||||
Timers trigger tasks that occur after a specified interval of time has passed.
|
||||
The timer interval can be specified in seconds, or in hour, minutes and seconds.
|
||||
Alarm.timerRepeat(15, Repeats); // timer task every 15 seconds
|
||||
This calls the Repeats() function in your sketch every 15 seconds.
|
||||
|
||||
If you want a timer to trigger once only, you can use the timerOnce method:
|
||||
Alarm.timerOnce(10, OnceOnly); // called once after 10 seconds
|
||||
This calls the onceOnly() function in a sketch 10 seconds after the timer is created.
|
||||
|
||||
If you want to trigger once at a specified date and time you can use the trigger Once() method:
|
||||
Alarm. triggerOnce(time_t value, explicitAlarm); // value specifies a date and time
|
||||
(See the makeTime() method in the Time library to convert dates and times into time_t)
|
||||
|
||||
Your sketch should call the Alarm.delay() function instead of the Arduino delay() function when
|
||||
using the Alarms library. The timeliness of triggers depends on sketch delays using this function.
|
||||
Alarm.delay( period); // Similar to Arduino delay - pauses the program for the period (in milliseconds).
|
||||
|
||||
|
||||
|
||||
Here is an example sketch:
|
||||
|
||||
This sketch triggers daily alarms at 8:30 am and 17:45 pm.
|
||||
A Timer is triggered every 15 seconds, another timer triggers once only after 10 seconds.
|
||||
A weekly alarm is triggered every Sunday at 8:30:30
|
||||
|
||||
#include <Time.h>
|
||||
#include <TimeAlarms.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
setTime(8,29,0,1,1,11); // set time to Saturday 8:29:00am Jan 1 2011
|
||||
// create the alarms
|
||||
Alarm.alarmRepeat(8,30,0, MorningAlarm); // 8:30am every day
|
||||
Alarm.alarmRepeat(17,45,0,EveningAlarm); // 5:45pm every day
|
||||
Alarm.alarmRepeat(dowSaturday,8,30,30,WeeklyAlarm); // 8:30:30 every Saturday
|
||||
|
||||
|
||||
Alarm.timerRepeat(15, Repeats); // timer for every 15 seconds
|
||||
Alarm.timerOnce(10, OnceOnly); // called once after 10 seconds
|
||||
}
|
||||
|
||||
void loop(){
|
||||
digitalClockDisplay();
|
||||
Alarm.delay(1000); // wait one second between clock display
|
||||
}
|
||||
|
||||
// functions to be called when an alarm triggers:
|
||||
void MorningAlarm(){
|
||||
Serial.println("Alarm: - turn lights off");
|
||||
}
|
||||
|
||||
void EveningAlarm(){
|
||||
Serial.println("Alarm: - turn lights on");
|
||||
}
|
||||
|
||||
void WeeklyAlarm(){
|
||||
Serial.println("Alarm: - its Monday Morning");
|
||||
}
|
||||
|
||||
void ExplicitAlarm(){
|
||||
Serial.println("Alarm: - this triggers only at the given date and time");
|
||||
}
|
||||
|
||||
void Repeats(){
|
||||
Serial.println("15 second timer");
|
||||
}
|
||||
|
||||
void OnceOnly(){
|
||||
Serial.println("This timer only triggers once");
|
||||
}
|
||||
|
||||
void digitalClockDisplay()
|
||||
{
|
||||
// digital clock display of the time
|
||||
Serial.print(hour());
|
||||
printDigits(minute());
|
||||
printDigits(second());
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void printDigits(int digits)
|
||||
{
|
||||
Serial.print(":");
|
||||
if(digits < 10)
|
||||
Serial.print('0');
|
||||
Serial.print(digits);
|
||||
}
|
||||
Note that the loop code calls Alarm.delay(1000) - Alarm.delay must be used
|
||||
instead of the usual arduino delay function because the alarms are serviced in the Alarm.delay method.
|
||||
Failing to regularly call Alarm.delay will result in the alarms not being triggered
|
||||
so always use Alarm.delay instead of delay in sketches that use the Alarms library.
|
||||
|
||||
Functional reference:
|
||||
|
||||
// functions to create alarms and timers
|
||||
|
||||
Alarm.triggerOnce(value, AlarmFunction);
|
||||
Description: Call user provided AlarmFunction once at the date and time of the given value
|
||||
See the Ttime library for more on time_t values
|
||||
|
||||
Alarm.alarmRepeat(Hour, Minute, Second, AlarmFunction);
|
||||
Description: Calls user provided AlarmFunction every day at the given Hour, Minute and Second.
|
||||
|
||||
Alarm.alarmRepeat(value, AlarmFunction);
|
||||
Description: Calls user provided AlarmFunction every day at the time indicated by the given value
|
||||
|
||||
Alarm.alarmRepeat(DayOfWeek, Hour, Minute, Second, AlarmFunction);
|
||||
Description: Calls user provided AlarmFunction every week on the given DayOfWeek, Hour, Minute and Second.
|
||||
|
||||
Alarm.alarmOnce(Hour, Minute, Second, AlarmFunction);
|
||||
Description: Calls user provided AlarmFunction once when the Arduino time next reaches the given Hour, Minute and Second.
|
||||
|
||||
Alarm.alarmOnce(value, AlarmFunction);
|
||||
Description: Calls user provided AlarmFunction once at the next time indicated by the given value
|
||||
|
||||
Alarm.alarmOnce(DayOfWeek, Hour, Minute, Second, AlarmFunction);
|
||||
Description: Calls user provided AlarmFunction once only on the next DayOfWeek, Hour, Minute and Second.
|
||||
|
||||
Alarm.timerRepeat(Period, TimerFunction);
|
||||
Description: Continuously calls user provided TimerFunction after the given period in seconds has elapsed.
|
||||
|
||||
Alarm.timerRepeat(Hour, Minute, Second, TimerFunction);
|
||||
Description: As timerRepeat above, but period is the number of seconds in the given Hour, Minute and Second parameters
|
||||
|
||||
Alarm.timerOnce(Period, TimerFunction);
|
||||
Description: Calls user provided TimerFunction once only after the given period in seconds has elapsed.
|
||||
|
||||
Alarm.timerOnce(Hour, Minute, Second, TimerFunction);
|
||||
Description: As timerOnce above, but period is the number of seconds in the given Hour, Minute and Second parameters
|
||||
|
||||
Alarm.delay( period)
|
||||
Description: Similar to Arduino delay - pauses the program for the period (in miliseconds) specified.
|
||||
Call this function rather than the Arduino delay function when using the Alarms library.
|
||||
The timeliness of the triggers depends on sketch delays using this function.
|
||||
|
||||
Low level functions not usually required for typical applications:
|
||||
disable( ID); - prevent the alarm associated with the given ID from triggering
|
||||
enable(ID); - enable the alarm
|
||||
write(ID, value); - write the value (and enable) the alarm for the given ID
|
||||
read(ID); - return the value for the given ID
|
||||
readType(ID); - return the alarm type for the given alarm ID
|
||||
getTriggeredAlarmId(); - returns the currently triggered alarm id, only valid in an alarm callback
|
||||
|
||||
FAQ
|
||||
|
||||
Q: What hardware and software is needed to use this library?
|
||||
A: This library requires the Time library. No internal or external hardware is used by the Alarm library.
|
||||
|
||||
Q: Why must I use Alarm.delay() instead of delay()?
|
||||
A: Task scheduling is handled in the Alarm.delay function.
|
||||
Tasks are monitored and triggered from within the Alarm.delay call so Alarm.delay should be called
|
||||
whenever a delay is required in your sketch.
|
||||
If your sketch waits on an external event (for example, a sensor change),
|
||||
make sure you repeatedly call Alarm.delay while checking the sensor.
|
||||
You can call Alarm.delay(0) if you need to service the scheduler without a delay.
|
||||
|
||||
Q: Are there any restrictions on the code in a task handler function?
|
||||
A: No. The scheduler does not use interrupts so your task handling function is no
|
||||
different from other functions you create in your sketch.
|
||||
|
||||
Q: What are the shortest and longest intervals that can be scheduled?
|
||||
A: Time intervals can range from 1 second to years.
|
||||
(If you need timer intervals shorter than 1 second then the TimedAction library
|
||||
by Alexander Brevig may be more suitable, see: http://www.arduino.cc/playground/Code/TimedAction)
|
||||
|
||||
Q: How are scheduled tasks affected if the system time is changed?
|
||||
A: Tasks are scheduled for specific times designated by the system clock.
|
||||
If the system time is reset to a later time (for example one hour ahead) then all
|
||||
alarms and timers will occur one hour later.
|
||||
If the system time is set backwards (for example one hour back) then the alarms and timers will occur an hour earlier.
|
||||
If the time is reset before the time a task was scheduled, then the task will be triggered on the next service (the next call to Alarm.delay).
|
||||
This is the expected behaviour for Alarms <20> tasks scheduled for a specific time of day will trigger at that time, but the affect on timers may not be intuitive. If a timer is scheduled to trigger in 5 minutes time and the clock is set ahead by one hour, that timer will not trigger until one hour and 5 minutes has elapsed.
|
||||
|
||||
Q: What is the valid range of times supported by these libraries?
|
||||
A: The time library is intended to handle times from Jan 1 1970 through Jan 19 2038.
|
||||
The Alarms library expects dates to be on or after Jan1 1971 so clocks should no be set earlier than this if using Alarms.
|
||||
(The functions to create alarms will return an error if an earlier date is given).
|
||||
|
||||
Q: How many alarms can be created?
|
||||
A: Up to six alarms can be scheduled.
|
||||
The number of alarms can be changed in the TimeAlarms header file (set by the constant dtNBR_ALARMS,
|
||||
note that the RAM used equals dtNBR_ALARMS * 11)
|
||||
|
||||
onceOnly Alarms and Timers are freed when they are triggered so another onceOnly alarm can be set to trigger again.
|
||||
There is no limit to the number of times a onceOnly alarm can be reset.
|
||||
|
||||
The following fragment gives one example of how a timerOnce task can be rescheduled:
|
||||
Alarm.timerOnce(random(10), randomTimer); // trigger after random number of seconds
|
||||
|
||||
void randomTimer(){
|
||||
int period = random(2,10); // get a new random period
|
||||
Alarm.timerOnce(period, randomTimer); // trigger for another random period
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user