diff options
author | Mike Beattie <mike@ethernal.org> | 2012-03-20 23:25:17 +1300 |
---|---|---|
committer | Mike Beattie <mike@ethernal.org> | 2012-03-20 23:25:17 +1300 |
commit | cb7bd533cb2b505441ca9a35c9897db358a30b47 (patch) | |
tree | fd20d304a519730798433e9835ce3e8e12f703fc |
Add Time library
Signed-off-by: Mike Beattie <mike@ethernal.org>
23 files changed, 2138 insertions, 0 deletions
diff --git a/DS1307RTC/DS1307RTC.cpp b/DS1307RTC/DS1307RTC.cpp new file mode 100644 index 0000000..bf0b46e --- /dev/null +++ b/DS1307RTC/DS1307RTC.cpp @@ -0,0 +1,124 @@ +/*
+ * DS1307RTC.h - library for DS1307 RTC
+
+ Copyright (c) Michael Margolis 2009
+ This library is intended to be uses with Arduino Time.h library functions
+
+ The 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.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ 30 Dec 2009 - Initial release
+ 5 Sep 2011 updated for Arduino 1.0
+ */
+
+#include <Wire.h>
+#include "DS1307RTC.h"
+
+#define DS1307_CTRL_ID 0x68
+
+DS1307RTC::DS1307RTC()
+{
+ Wire.begin();
+}
+
+// PUBLIC FUNCTIONS
+time_t DS1307RTC::get() // Aquire data from buffer and convert to time_t
+{
+ tmElements_t tm;
+ read(tm);
+ return(makeTime(tm));
+}
+
+void DS1307RTC::set(time_t t)
+{
+ tmElements_t tm;
+ breakTime(t, tm);
+ tm.Second |= 0x80; // stop the clock
+ write(tm);
+ tm.Second &= 0x7f; // start the clock
+ write(tm);
+}
+
+// Aquire data from the RTC chip in BCD format
+void DS1307RTC::read( tmElements_t &tm)
+{
+ Wire.beginTransmission(DS1307_CTRL_ID);
+#if ARDUINO >= 100
+ Wire.write((uint8_t)0x00);
+#else
+ Wire.send(0x00);
+#endif
+ Wire.endTransmission();
+
+ // request the 7 data fields (secs, min, hr, dow, date, mth, yr)
+ Wire.requestFrom(DS1307_CTRL_ID, tmNbrFields);
+#if ARDUINO >= 100
+ tm.Second = bcd2dec(Wire.read() & 0x7f);
+ tm.Minute = bcd2dec(Wire.read() );
+ tm.Hour = bcd2dec(Wire.read() & 0x3f); // mask assumes 24hr clock
+ tm.Wday = bcd2dec(Wire.read() );
+ tm.Day = bcd2dec(Wire.read() );
+ tm.Month = bcd2dec(Wire.read() );
+ tm.Year = y2kYearToTm((bcd2dec(Wire.read())));
+#else
+ tm.Second = bcd2dec(Wire.receive() & 0x7f);
+ tm.Minute = bcd2dec(Wire.receive() );
+ tm.Hour = bcd2dec(Wire.receive() & 0x3f); // mask assumes 24hr clock
+ tm.Wday = bcd2dec(Wire.receive() );
+ tm.Day = bcd2dec(Wire.receive() );
+ tm.Month = bcd2dec(Wire.receive() );
+ tm.Year = y2kYearToTm((bcd2dec(Wire.receive())));
+#endif
+}
+
+void DS1307RTC::write(tmElements_t &tm)
+{
+ Wire.beginTransmission(DS1307_CTRL_ID);
+#if ARDUINO >= 100
+ Wire.write((uint8_t)0x00); // reset register pointer
+ Wire.write(dec2bcd(tm.Second)) ;
+ Wire.write(dec2bcd(tm.Minute));
+ Wire.write(dec2bcd(tm.Hour)); // sets 24 hour format
+ Wire.write(dec2bcd(tm.Wday));
+ Wire.write(dec2bcd(tm.Day));
+ Wire.write(dec2bcd(tm.Month));
+ Wire.write(dec2bcd(tmYearToY2k(tm.Year)));
+#else
+ Wire.send(0x00); // reset register pointer
+ Wire.send(dec2bcd(tm.Second)) ;
+ Wire.send(dec2bcd(tm.Minute));
+ Wire.send(dec2bcd(tm.Hour)); // sets 24 hour format
+ Wire.send(dec2bcd(tm.Wday));
+ Wire.send(dec2bcd(tm.Day));
+ Wire.send(dec2bcd(tm.Month));
+ Wire.send(dec2bcd(tmYearToY2k(tm.Year)));
+#endif
+ Wire.endTransmission();
+}
+// PRIVATE FUNCTIONS
+
+// Convert Decimal to Binary Coded Decimal (BCD)
+uint8_t DS1307RTC::dec2bcd(uint8_t num)
+{
+ return ((num/10 * 16) + (num % 10));
+}
+
+// Convert Binary Coded Decimal (BCD) to Decimal
+uint8_t DS1307RTC::bcd2dec(uint8_t num)
+{
+ return ((num/16 * 10) + (num % 16));
+}
+
+DS1307RTC RTC = DS1307RTC(); // create an instance for the user
+
diff --git a/DS1307RTC/DS1307RTC.h b/DS1307RTC/DS1307RTC.h new file mode 100644 index 0000000..e3a1bc1 --- /dev/null +++ b/DS1307RTC/DS1307RTC.h @@ -0,0 +1,31 @@ +/*
+ * DS1307RTC.h - library for DS1307 RTC
+ * This library is intended to be uses with Arduino Time.h library functions
+ */
+
+#ifndef DS1307RTC_h
+#define DS1307RTC_h
+
+#include <Time.h>
+
+// library interface description
+class DS1307RTC
+{
+ // user-accessible "public" interface
+ public:
+ DS1307RTC();
+ static time_t get();
+ static void set(time_t t);
+ static void read(tmElements_t &tm);
+ static void write(tmElements_t &tm);
+
+ private:
+ static uint8_t dec2bcd(uint8_t num);
+ static uint8_t bcd2dec(uint8_t num);
+};
+
+extern DS1307RTC RTC;
+
+#endif
+
+
diff --git a/DS1307RTC/keywords.txt b/DS1307RTC/keywords.txt new file mode 100644 index 0000000..be96f1e --- /dev/null +++ b/DS1307RTC/keywords.txt @@ -0,0 +1,22 @@ +####################################### +# Syntax Coloring Map For DS1307RTC +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +get KEYWORD2 +set KEYWORD2 +read KEYWORD2 +write KEYWORD2 +####################################### +# Instances (KEYWORD2) +####################################### +RTC +####################################### +# Constants (LITERAL1) +####################################### diff --git a/DS1307RTC/readme.txt b/DS1307RTC/readme.txt new file mode 100644 index 0000000..5978295 --- /dev/null +++ b/DS1307RTC/readme.txt @@ -0,0 +1,7 @@ +Readme file for DS1307RTC Library + +The DS1307RTC library is provided to demonstrate the Arduino Time library. + +See the TimeRTC example sketches privided with the Time library download for usage + + diff --git a/Time/DateStrings.cpp b/Time/DateStrings.cpp new file mode 100644 index 0000000..7610c8f --- /dev/null +++ b/Time/DateStrings.cpp @@ -0,0 +1,80 @@ +/* DateStrings.cpp
+ * Definitions for date strings for use with the Time library
+ *
+ * No memory is consumed in the sketch if your code does not call any of the string methods
+ * You can change the text of the strings, make sure the short strings are each exactly 3 characters
+ * the long strings can be any length up to the constant dt_MAX_STRING_LEN defined in Time.h
+ *
+ */
+
+#include <avr/pgmspace.h>
+#include "Time.h"
+
+// the short strings for each day or month must be exactly dt_SHORT_STR_LEN
+#define dt_SHORT_STR_LEN 3 // the length of short strings
+
+static char buffer[dt_MAX_STRING_LEN+1]; // must be big enough for longest string and the terminating null
+
+char monthStr1[] PROGMEM = "January";
+char monthStr2[] PROGMEM = "February";
+char monthStr3[] PROGMEM = "March";
+char monthStr4[] PROGMEM = "April";
+char monthStr5[] PROGMEM = "May";
+char monthStr6[] PROGMEM = "June";
+char monthStr7[] PROGMEM = "July";
+char monthStr8[] PROGMEM = "August";
+char monthStr9[] PROGMEM = "September";
+char monthStr10[] PROGMEM = "October";
+char monthStr11[] PROGMEM = "November";
+char monthStr12[] PROGMEM = "December";
+
+PGM_P monthNames_P[] PROGMEM =
+{
+ "",monthStr1,monthStr2,monthStr3,monthStr4,monthStr5,monthStr6,
+ monthStr7,monthStr8,monthStr9,monthStr10,monthStr11,monthStr12
+};
+
+char monthShortNames_P[] PROGMEM = "ErrJanFebMarAprMayJunJulAugSepOctNovDec";
+
+char dayStr0[] PROGMEM = "Err";
+char dayStr1[] PROGMEM = "Sunday";
+char dayStr2[] PROGMEM = "Monday";
+char dayStr3[] PROGMEM = "Tuesday";
+char dayStr4[] PROGMEM = "Wednesday";
+char dayStr5[] PROGMEM = "Thursday";
+char dayStr6[] PROGMEM = "Friday";
+char dayStr7[] PROGMEM = "Saturday";
+
+PGM_P dayNames_P[] PROGMEM = { dayStr0,dayStr1,dayStr2,dayStr3,dayStr4,dayStr5,dayStr6,dayStr7};
+char dayShortNames_P[] PROGMEM = "ErrSunMonTueWedThrFriSat";
+
+/* functions to return date strings */
+
+char* monthStr(uint8_t month)
+{
+ strcpy_P(buffer, (PGM_P)pgm_read_word(&(monthNames_P[month])));
+ return buffer;
+}
+
+char* monthShortStr(uint8_t month)
+{
+ for (int i=0; i < dt_SHORT_STR_LEN; i++)
+ buffer[i] = pgm_read_byte(&(monthShortNames_P[i+ (month*dt_SHORT_STR_LEN)]));
+ buffer[dt_SHORT_STR_LEN] = 0;
+ return buffer;
+}
+
+char* dayStr(uint8_t day)
+{
+ strcpy_P(buffer, (PGM_P)pgm_read_word(&(dayNames_P[day])));
+ return buffer;
+}
+
+char* dayShortStr(uint8_t day)
+{
+ uint8_t index = day*dt_SHORT_STR_LEN;
+ for (int i=0; i < dt_SHORT_STR_LEN; i++)
+ buffer[i] = pgm_read_byte(&(dayShortNames_P[index + i]));
+ buffer[dt_SHORT_STR_LEN] = 0;
+ return buffer;
+}
diff --git a/Time/Examples/Processing/SyncArduinoClock/SyncArduinoClock.pde b/Time/Examples/Processing/SyncArduinoClock/SyncArduinoClock.pde new file mode 100644 index 0000000..4c74d4b --- /dev/null +++ b/Time/Examples/Processing/SyncArduinoClock/SyncArduinoClock.pde @@ -0,0 +1,70 @@ +/** + * SyncArduinoClock. + * + * portIndex must be set to the port connected to the Arduino + * + * The current time is sent in response to request message from Arduino + * or by clicking the display window + * + * The time message is 11 ASCII text characters; a header (the letter 'T') + * followed by the ten digit system time (unix time) + */ + + +import processing.serial.*; + +public static final short portIndex = 1; // select the com port, 0 is the first port +public static final char TIME_HEADER = 'T'; //header byte for arduino serial time message +public static final char TIME_REQUEST = 7; // ASCII bell character +public static final char LF = 10; // ASCII linefeed +public static final char CR = 13; // ASCII linefeed +Serial myPort; // Create object from Serial class + +void setup() { + size(200, 200); + println(Serial.list()); + println(" Connecting to -> " + Serial.list()[portIndex]); + myPort = new Serial(this,Serial.list()[portIndex], 9600); +} + +void draw() +{ + if ( myPort.available() > 0) { // If data is available, + char val = char(myPort.read()); // read it and store it in val + if(val == TIME_REQUEST){ + long t = getTimeNow(); + sendTimeMessage(TIME_HEADER, t); + } + else + { + if(val == LF) + ; //igonore + else if(val == CR) + println(); + else + print(val); // echo everying but time request + } + } +} + +void mousePressed() { + sendTimeMessage( TIME_HEADER, getTimeNow()); +} + + +void sendTimeMessage(char header, long time) { + String timeStr = String.valueOf(time); + myPort.write(header); // send header and time to arduino + myPort.write(timeStr); +} + +long getTimeNow(){ + // java time is in ms, we want secs + GregorianCalendar cal = new GregorianCalendar(); + cal.setTime(new Date()); + int tzo = cal.get(Calendar.ZONE_OFFSET); + int dst = cal.get(Calendar.DST_OFFSET); + long now = (cal.getTimeInMillis() / 1000) ; + now = now + (tzo/1000) + (dst/1000); + return now; +} diff --git a/Time/Examples/Processing/SyncArduinoClock/readme.txt b/Time/Examples/Processing/SyncArduinoClock/readme.txt new file mode 100644 index 0000000..985bd80 --- /dev/null +++ b/Time/Examples/Processing/SyncArduinoClock/readme.txt @@ -0,0 +1,9 @@ +SyncArduinoClock is a Processing sketch that responds to Arduino requests for +time synchronization messages. + +The portIndex must be set the Serial port connected to Arduino. + +Download TimeSerial.pde onto Arduino and you should see the time +message displayed when you run SyncArduinoClock in Processing. +The Arduino time is set from the time on your computer through the +Processing sketch.
\ No newline at end of file diff --git a/Time/Examples/TimeGPS/TimeGPS.pde b/Time/Examples/TimeGPS/TimeGPS.pde new file mode 100644 index 0000000..1c7b25e --- /dev/null +++ b/Time/Examples/TimeGPS/TimeGPS.pde @@ -0,0 +1,82 @@ +/* + * TimeGPS.pde + * example code illustrating time synced from a GPS + * + */ + +#include <Time.h> +#include <TinyGPS.h> //http://arduiniana.org/libraries/TinyGPS/ +#include <NewSoftSerial.h> //http://arduiniana.org/libraries/newsoftserial/ +// GPS and NewSoftSerial libraries are the work of Mikal Hart + +TinyGPS gps; +NewSoftSerial serial_gps = NewSoftSerial(3, 2); // receive on pin 3 + +const int offset = 1; // offset hours from gps time (UTC) +time_t prevDisplay = 0; // when the digital clock was displayed + +void setup() +{ + Serial.begin(9600); + serial_gps.begin(4800); + Serial.println("Waiting for GPS time ... "); + setSyncProvider(gpsTimeSync); +} + +void loop() +{ + while (serial_gps.available()) + { + gps.encode(serial_gps.read()); // process gps messages + } + if(timeStatus()!= timeNotSet) + { + if( now() != prevDisplay) //update the display only if the time has changed + { + prevDisplay = now(); + digitalClockDisplay(); + } + } +} + +void digitalClockDisplay(){ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + Serial.print(month()); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits){ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + +time_t gpsTimeSync(){ + // returns time if avail from gps, else returns 0 + unsigned long fix_age = 0 ; + gps.get_datetime(NULL,NULL, &fix_age); + unsigned long time_since_last_fix; + if(fix_age < 1000) + return gpsTimeToArduinoTime(); // return time only if updated recently by gps + return 0; +} + +time_t gpsTimeToArduinoTime(){ + // returns time_t from gps date and time with the given offset hours + tmElements_t tm; + int year; + gps.crack_datetime(&year, &tm.Month, &tm.Day, &tm.Hour, &tm.Minute, &tm.Second, NULL, NULL); + tm.Year = year - 1970; + time_t time = makeTime(tm); + return time + (offset * SECS_PER_HOUR); +} diff --git a/Time/Examples/TimeNTP/TimeNTP.pde b/Time/Examples/TimeNTP/TimeNTP.pde new file mode 100644 index 0000000..11927c6 --- /dev/null +++ b/Time/Examples/TimeNTP/TimeNTP.pde @@ -0,0 +1,120 @@ +/* + * Time_NTP.pde + * Example showing time sync to NTP time source + * + * This sketch uses the Ethenet library with the user contributed UdpBytewise extension + */ + +#include <Time.h> +#include <Ethernet.h> +#include <UdpBytewise.h> // UDP library from: bjoern@cs.stanford.edu 12/30/2008 +#if UDP_TX_PACKET_MAX_SIZE <64 || UDP_RX_PACKET_MAX_SIZE < 64 +#error : UDP packet size to small - modify UdpBytewise.h to set buffers to 64 bytes +#endif +/* + * + * You may need to modify the UdpBytewise.h library to allow enough space in the buffers for the NTP packets. + * Open up UdpBytewse.h and set the following buffers to 64 bytes: + * #define UDP_TX_PACKET_MAX_SIZE 64 + * #define UDP_RX_PACKET_MAX_SIZE 64 + */ + + +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +byte ip[] = { 192, 168, 1, 44 }; // set the IP address to an unused address on your network + +byte SNTP_server_IP[] = { 192, 43, 244, 18}; // time.nist.gov +//byte SNTP_server_IP[] = { 130,149,17,21}; // ntps1-0.cs.tu-berlin.de +//byte SNTP_server_IP[] = { 192,53,103,108}; // ptbtime1.ptb.de + + +time_t prevDisplay = 0; // when the digital clock was displayed +const long timeZoneOffset = 0L; // set this to the offset in seconds to your local time; + +void setup() +{ + Serial.begin(9600); + Ethernet.begin(mac,ip); + Serial.println("waiting for sync"); + setSyncProvider(getNtpTime); + while(timeStatus()== timeNotSet) + ; // wait until the time is set by the sync provider +} + +void loop() +{ + if( now() != prevDisplay) //update the display only if the time has changed + { + prevDisplay = now(); + digitalClockDisplay(); + } +} + +void digitalClockDisplay(){ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + Serial.print(month()); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits){ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + +/*-------- NTP code ----------*/ + +unsigned long getNtpTime() +{ + sendNTPpacket(SNTP_server_IP); + delay(1000); + if ( UdpBytewise.available() ) { + for(int i=0; i < 40; i++) + UdpBytewise.read(); // ignore every field except the time + const unsigned long seventy_years = 2208988800UL + timeZoneOffset; + return getUlong() - seventy_years; + } + return 0; // return 0 if unable to get the time +} + +unsigned long sendNTPpacket(byte *address) +{ + UdpBytewise.begin(123); + UdpBytewise.beginPacket(address, 123); + UdpBytewise.write(B11100011); // LI, Version, Mode + UdpBytewise.write(0); // Stratum + UdpBytewise.write(6); // Polling Interval + UdpBytewise.write(0xEC); // Peer Clock Precision + write_n(0, 8); // Root Delay & Root Dispersion + UdpBytewise.write(49); + UdpBytewise.write(0x4E); + UdpBytewise.write(49); + UdpBytewise.write(52); + write_n(0, 32); //Reference and time stamps + UdpBytewise.endPacket(); +} + +unsigned long getUlong() +{ + unsigned long ulong = (unsigned long)UdpBytewise.read() << 24; + ulong |= (unsigned long)UdpBytewise.read() << 16; + ulong |= (unsigned long)UdpBytewise.read() << 8; + ulong |= (unsigned long)UdpBytewise.read(); + return ulong; +} + +void write_n(int what, int how_many) +{ + for( int i = 0; i < how_many; i++ ) + UdpBytewise.write(what); +}
diff --git a/Time/Examples/TimeRTC/TimeRTC.pde b/Time/Examples/TimeRTC/TimeRTC.pde new file mode 100644 index 0000000..1a1ed80 --- /dev/null +++ b/Time/Examples/TimeRTC/TimeRTC.pde @@ -0,0 +1,47 @@ +/* + * TimeRTC.pde + * example code illustrating Time library with Real Time Clock. + * + */ + +#include <Time.h> +#include <Wire.h> +#include <DS1307RTC.h> // a basic DS1307 library that returns time as a time_t + +void setup() { + Serial.begin(9600); + setSyncProvider(RTC.get); // the function to get the time from the RTC + if(timeStatus()!= timeSet) + Serial.println("Unable to sync with the RTC"); + else + Serial.println("RTC has set the system time"); +} + +void loop() +{ + digitalClockDisplay(); + delay(1000); +} + +void digitalClockDisplay(){ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + Serial.print(month()); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits){ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} +
diff --git a/Time/Examples/TimeRTCLog/TimeRTCLog.pde b/Time/Examples/TimeRTCLog/TimeRTCLog.pde new file mode 100644 index 0000000..76ed17d --- /dev/null +++ b/Time/Examples/TimeRTCLog/TimeRTCLog.pde @@ -0,0 +1,106 @@ +/* + * TimeRTCLogger.pde + * example code illustrating adding and subtracting Time. + * + * this sketch logs pin state change events + * the time of the event and time since the previous event is calculated and sent to the serial port. + */ + +#include <Time.h> +#include <Wire.h> +#include <DS1307RTC.h> // a basic DS1307 library that returns time as a time_t + +const int nbrInputPins = 6; // monitor 6 digital pins +const int inputPins[nbrInputPins] = {2,3,4,5,6,7}; // pins to monitor +boolean state[nbrInputPins] ; // the state of the monitored pins +time_t prevEventTime[nbrInputPins] ; // the time of the previous event + +void setup() { + Serial.begin(9600); + setSyncProvider(RTC.get); // the function to sync the time from the RTC + for(int i=0; i < nbrInputPins; i++){ + pinMode( inputPins[i], INPUT); + // digitalWrite( inputPins[i], HIGH); // uncomment these lines if + // state[i] = HIGH; // pull-up resistors are wanted + } +} + +void loop() +{ + for(int i=0; i < nbrInputPins; i++) + { + boolean val = digitalRead(inputPins[i]); + if(val != state[i]) + { + time_t duration = 0; // the time since the previous event + state[i] = val; + time_t timeNow = now(); + if(prevEventTime[i] > 0) + // if this was not the first state change, calculate the time from the previous change + duration = duration = timeNow - prevEventTime[i]; + logEvent(inputPins[i], val, timeNow, duration ); // log the event + prevEventTime[i] = timeNow; // store the time for this event + } + } +} + +void logEvent( int pin, boolean state, time_t timeNow, time_t duration) +{ + Serial.print("Pin "); + Serial.print(pin); + if( state == HIGH) + Serial.print(" went High at "); + else + Serial.print(" went Low at "); + showTime(timeNow); + if(duration > 0){ + // only display duration if greater than 0 + Serial.print(", Duration was "); + showDuration(duration); + } + Serial.println(); +} + + +void showTime(time_t t){ + // display the given time + Serial.print(hour(t)); + printDigits(minute(t)); + printDigits(second(t)); + Serial.print(" "); + Serial.print(day(t)); + Serial.print(" "); + Serial.print(month(t)); + Serial.print(" "); + Serial.print(year(t)); +} + +void printDigits(int digits){ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + +void showDuration(time_t duration){ +// prints the duration in days, hours, minutes and seconds + if(duration >= SECS_PER_DAY){ + Serial.print(duration / SECS_PER_DAY); + Serial.print(" day(s) "); + duration = duration % SECS_PER_DAY; + } + if(duration >= SECS_PER_HOUR){ + Serial.print(duration / SECS_PER_HOUR); + Serial.print(" hour(s) "); + duration = duration % SECS_PER_HOUR; + } + if(duration >= SECS_PER_MIN){ + Serial.print(duration / SECS_PER_MIN); + Serial.print(" minute(s) "); + duration = duration % SECS_PER_MIN; + } + Serial.print(duration); + Serial.print(" second(s) "); +} +
diff --git a/Time/Examples/TimeRTCSet/TimeRTCSet.pde b/Time/Examples/TimeRTCSet/TimeRTCSet.pde new file mode 100644 index 0000000..48b696c --- /dev/null +++ b/Time/Examples/TimeRTCSet/TimeRTCSet.pde @@ -0,0 +1,82 @@ +/* + * TimeRTCSet.pde + * example code illustrating Time library with Real Time Clock. + * + * RTC clock is set in response to serial port time message + * A Processing example sketch to set the time is inclided in the download + */ + +#include <Time.h> +#include <Wire.h> +#include <DS1307RTC.h> // a basic DS1307 library that returns time as a time_t + + +void setup() { + Serial.begin(9600); + setSyncProvider(RTC.get); // the function to get the time from the RTC + if(timeStatus()!= timeSet) + Serial.println("Unable to sync with the RTC"); + else + Serial.println("RTC has set the system time"); +} + +void loop() +{ + if(Serial.available()) + { + time_t t = processSyncMessage(); + if(t >0) + { + RTC.set(t); // set the RTC and the system time to the received value + setTime(t); + } + } + digitalClockDisplay(); + delay(1000); +} + +void digitalClockDisplay(){ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + Serial.print(month()); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits){ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + +/* code to process time sync messages from the serial port */ +#define TIME_MSG_LEN 11 // time sync to PC is HEADER followed by unix time_t as ten ascii digits +#define TIME_HEADER 'T' // Header tag for serial time sync message + +time_t processSyncMessage() { + // return the time if a valid sync message is received on the serial port. + while(Serial.available() >= TIME_MSG_LEN ){ // time message consists of a header and ten ascii digits + char c = Serial.read() ; + Serial.print(c); + if( c == TIME_HEADER ) { + time_t pctime = 0; + for(int i=0; i < TIME_MSG_LEN -1; i++){ + c = Serial.read(); + if( c >= '0' && c <= '9'){ + pctime = (10 * pctime) + (c - '0') ; // convert digits to a number + } + } + return pctime; + } + } + return 0; +} +
diff --git a/Time/Examples/TimeSerial/TimeSerial.pde b/Time/Examples/TimeSerial/TimeSerial.pde new file mode 100644 index 0000000..55c67a6 --- /dev/null +++ b/Time/Examples/TimeSerial/TimeSerial.pde @@ -0,0 +1,82 @@ +/* + * TimeSerial.pde + * example code illustrating Time library set through serial port messages. + * + * Messages consist of the letter T followed by ten digit time (as seconds since Jan 1 1970) + * you can send the text on the next line using Serial Monitor to set the clock to noon Jan 1 2010 + T1262347200 + * + * A Processing example sketch to automatically send the messages is inclided in the download + */ + +#include <Time.h> + +#define TIME_MSG_LEN 11 // time sync to PC is HEADER followed by unix time_t as ten ascii digits +#define TIME_HEADER 'T' // Header tag for serial time sync message +#define TIME_REQUEST 7 // ASCII bell character requests a time sync message + +void setup() { + Serial.begin(9600); + setSyncProvider( requestSync); //set function to call when sync required + Serial.println("Waiting for sync message"); +} + +void loop(){ + if(Serial.available() ) + { + processSyncMessage(); + } + if(timeStatus()!= timeNotSet) + { + digitalWrite(13,timeStatus() == timeSet); // on if synced, off if needs refresh + digitalClockDisplay(); + } + delay(1000); +} + +void digitalClockDisplay(){ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + Serial.print(month()); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits){ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + +void processSyncMessage() { + // if time sync available from serial port, update time and return true + while(Serial.available() >= TIME_MSG_LEN ){ // time message consists of a header and ten ascii digits + char c = Serial.read() ; + Serial.print(c); + if( c == TIME_HEADER ) { + time_t pctime = 0; + for(int i=0; i < TIME_MSG_LEN -1; i++){ + c = Serial.read(); + if( c >= '0' && c <= '9'){ + pctime = (10 * pctime) + (c - '0') ; // convert digits to a number + } + } + setTime(pctime); // Sync Arduino clock to the time received on the serial port + } + } +} + +time_t requestSync() +{ + Serial.print(TIME_REQUEST,BYTE); + return 0; // the time will be sent later in response to serial mesg +} +
diff --git a/Time/Examples/TimeSerialDateStrings/TimeSerialDateStrings.pde b/Time/Examples/TimeSerialDateStrings/TimeSerialDateStrings.pde new file mode 100644 index 0000000..dcff97e --- /dev/null +++ b/Time/Examples/TimeSerialDateStrings/TimeSerialDateStrings.pde @@ -0,0 +1,80 @@ +/* + * TimeSerialDateStrings.pde + * example code illustrating Time library date strings + * + * This sketch adds date string functionality to TimeSerial.pde + * + */ + +#include <Time.h> + +#define TIME_MSG_LEN 11 // time sync to PC is HEADER followed by unix time_t as ten ascii digits +#define TIME_HEADER 'T' // Header tag for serial time sync message +#define TIME_REQUEST 7 // ASCII bell character requests a time sync message + +void setup() { + Serial.begin(9600); + setSyncProvider( requestSync); //set function to call when sync required + Serial.println("Waiting for sync message"); +} + +void loop(){ + if(Serial.available() ) + { + processSyncMessage(); + } + if(timeStatus()!= timeNotSet) + { + digitalClockDisplay(); + } + delay(1000); +} + +void digitalClockDisplay(){ + // digital clock display of the time + Serial.print(hour()); + printDigits(minute()); + printDigits(second()); + Serial.print(" "); + Serial.print(dayStr(weekday())); + Serial.print(" "); + Serial.print(day()); + Serial.print(" "); + Serial.print(monthShortStr(month())); + Serial.print(" "); + Serial.print(year()); + Serial.println(); +} + +void printDigits(int digits){ + // utility function for digital clock display: prints preceding colon and leading 0 + Serial.print(":"); + if(digits < 10) + Serial.print('0'); + Serial.print(digits); +} + +void processSyncMessage() { + // if time sync available from serial port, update time and return true + while(Serial.available() >= TIME_MSG_LEN ){ // time message consists of a header and ten ascii digits + char c = Serial.read() ; + Serial.print(c); + if( c == TIME_HEADER ) { + time_t pctime = 0; + for(int i=0; i < TIME_MSG_LEN -1; i++){ + c = Serial.read(); + if( c >= '0' && c <= '9'){ + pctime = (10 * pctime) + (c - '0') ; // convert digits to a number + } + } + setTime(pctime); // Sync Arduino clock to the time received on the serial port + } + } +} + +time_t requestSync() +{ + Serial.print(TIME_REQUEST,BYTE); + return 0; // the time will be sent later in response to serial mesg +} +
diff --git a/Time/Readme.txt b/Time/Readme.txt new file mode 100644 index 0000000..22bc4aa --- /dev/null +++ b/Time/Readme.txt @@ -0,0 +1,131 @@ +Readme file for Arduino Time Library
+
+Time is a library that provides timekeeping functionality for Arduino.
+
+The code is derived from the Playground DateTime library but is updated
+to provide an API that is more flexable and easier to use.
+
+A primary goal was to enable date and time functionality that can be used with
+a variety of external time sources with minimum differences required in sketch logic.
+
+Example sketches illustrate how similar sketch code can be used with: a Real Time Clock,
+internet NTP time service, GPS time data, and Serial time messages from a computer
+for time synchronization.
+
+The functions available in the library include:
+
+hour(); // the hour now (0-23)
+minute(); // the minute now (0-59)
+second(); // the second now (0-59)
+day(); // the day now (1-31)
+weekday(); // day of the week, Sunday is day 0
+month(); // the month now (1-12)
+year(); // the full four digit year: (2009, 2010 etc)
+
+there are also functions to return the hour in 12 hour format
+hourFormat12(); // the hour now in 12 hour format
+isAM(); // returns true if time now is AM
+isPM(); // returns true if time now is PM
+
+now(); // returns the current time as seconds since Jan 1 1970
+
+The time and date functions can take an optional parameter for the time. This prevents
+errors if the time rolls over between elements. For example, if a new minute begins
+between getting the minute and second, the values will be inconsistent. Using the
+following functions eliminates this probglem
+ time_t t = now(); // store the current time in time variable t
+ hour(t); // returns the hour for the given time t
+ minute(t); // returns the minute for the given time t
+ second(t); // returns the second for the given time t
+ day(t); // the day for the given time t
+ weekday(t); // day of the week for the given time t
+ month(t); // the month for the given time t
+ year(t); // the year for the given time t
+
+
+Functions for managing the timer services are:
+setTime(t); // set the system time to the give time t
+setTime(hr,min,sec,day,mnth,yr); // alternative to above, yr is 2 or 4 digit yr (2010 or 10 sets year to 2010)
+adjustTime(adjustment); // adjust system time by adding the adjustment value
+
+timeStatus(); // indicates if time has been set and recently synchronized
+ // returns one of the following enumerations:
+ timeNotSet // the time has never been set, the clock started at Jan 1 1970
+ timeNeedsSync // the time had been set but a sync attempt did not succeed
+ timeSet // the time is set and is synced
+Time and Date values are not valid if the status is timeNotSet. Otherwise values can be used but
+the returned time may have drifted if the status is timeNeedsSync.
+
+setSyncProvider(getTimeFunction); // set the external time provider
+setSyncInterval(interval); // set the number of seconds between re-sync
+
+
+There are many convenience macros in the time.h file for time constants and conversion of time units.
+
+To use the library, copy the download to the Library directory.
+
+The Time directory contains the Time library and some example sketches
+illustrating how the library can be used with various time sources:
+
+- TimeSerial.pde shows Arduino as a clock without external hardware.
+ It is synchronized by time messages sent over the serial port.
+ A companion Processing sketch will automatically provide these messages
+ if it is running and connected to the Arduino serial port.
+
+- TimeSerialDateStrings.pde adds day and month name strings to the sketch above
+ Short (3 character) and long strings are available to print the days of
+ the week and names of the months.
+
+- TimeRTC uses a DS1307 real time clock to provide time synchronization.
+ A basic RTC library named DS1307RTC is included in the download.
+ To run this sketch the DS1307RTC library must be installed.
+
+- TimeRTCSet is similar to the above and adds the ability to set the Real Time Clock
+
+- TimeRTCLog demonstrates how to calculate the difference between times.
+ It is a vary simple logger application that monitors events on digtial pins
+ and prints (to the serial port) the time of an event and the time period since the previous event.
+
+- TimeNTP uses the Arduino Ethernet shield to access time using the internet NTP time service.
+ The NTP protocol uses UDP and the UdpBytewise library is required, see:
+ http://bitbucket.org/bjoern/arduino_osc/src/14667490521f/libraries/Ethernet/
+
+-TimeGPS gets time from a GPS
+ This requires the TinyGPS and NewSoftSerial libraries from Mikal Hart:
+ http://arduiniana.org/libraries/TinyGPS and http://arduiniana.org/libraries/newsoftserial/
+
+Differences between this code and the playground DateTime library
+although the Time library is based on the DateTime codebase, the API has changed.
+Changes in the Time library API:
+- time elements are functions returning int (they are variables in DateTime)
+- Years start from 1970
+- days of the week and months start from 1 (they start from 0 in DateTime)
+- DateStrings do not require a seperate library
+- time elements can be accessed non-atomically (in DateTime they are always atomic)
+- function added to automatically sync time with extrnal source
+- localTime and maketime parameters changed, localTime renamed to breakTime
+
+Technical notes:
+
+Internal system time is based on the standard Unix time_t.
+The value is the number of seconds since Jan 1 1970.
+System time begins at zero when the sketch starts.
+
+The internal time can be automatically synchronized at regular intervals to an external time source.
+This is enabled by calling the setSyncProvider(provider) function - the provider argument is
+the address of a function that returns the current time as a time_t.
+See the sketches in the examples directory for usage.
+
+The default interval for re-syncing the time is 5 minutes but can be changed by calling the
+setSyncInterval( interval) method to set the number of seconds between re-sync attempts.
+
+The Time library defines a structure for holding time elements that is a compact version of the C tm structure.
+All the members of the Arduino tm structure are bytes and the year is offset from 1970.
+Convenience macros provide conversion to and from the Arduino format.
+
+Low level functions to convert between system time and individual time elements are provided:
+ breakTime( time, &tm); // break time_t into elements stored in tm struct
+ makeTime( &tm); // return time_t from elements stored in tm struct
+
+The DS1307RTC library included in the download provides an example of how a time provider
+can use the low level functions to interface with the Time library.
\ No newline at end of file diff --git a/Time/Time.cpp b/Time/Time.cpp new file mode 100644 index 0000000..86bdcd5 --- /dev/null +++ b/Time/Time.cpp @@ -0,0 +1,307 @@ +/* + time.c - low level time and date functions + Copyright (c) Michael Margolis 2009 + + 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. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + 6 Jan 2010 - initial release + 12 Feb 2010 - fixed leap year calculation error + 1 Nov 2010 - fixed setTime bug (thanks to Korman for this) +*/ + +#if ARDUINO >= 100 +#include <Arduino.h> +#else +#include <WProgram.h> +#endif + +#include "Time.h" + +static tmElements_t tm; // a cache of time elements +static time_t cacheTime; // the time the cache was updated +static time_t syncInterval = 300; // time sync will be attempted after this many seconds + +void refreshCache( time_t t){ + if( t != cacheTime) + { + breakTime(t, tm); + cacheTime = t; + } +} + +int hour() { // the hour now + return hour(now()); +} + +int hour(time_t t) { // the hour for the given time + refreshCache(t); + return tm.Hour; +} + +int hourFormat12() { // the hour now in 12 hour format + return hourFormat12(now()); +} + +int hourFormat12(time_t t) { // the hour for the given time in 12 hour format + refreshCache(t); + if( tm.Hour == 0 ) + return 12; // 12 midnight + else if( tm.Hour > 12) + return tm.Hour - 12 ; + else + return tm.Hour ; +} + +uint8_t isAM() { // returns true if time now is AM + return !isPM(now()); +} + +uint8_t isAM(time_t t) { // returns true if given time is AM + return !isPM(t); +} + +uint8_t isPM() { // returns true if PM + return isPM(now()); +} + +uint8_t isPM(time_t t) { // returns true if PM + return (hour(t) >= 12); +} + +int minute() { + return minute(now()); +} + +int minute(time_t t) { // the minute for the given time + refreshCache(t); + return tm.Minute; +} + +int second() { + return second(now()); +} + +int second(time_t t) { // the second for the given time + refreshCache(t); + return tm.Second; +} + +int day(){ + return(day(now())); +} + +int day(time_t t) { // the day for the given time (0-6) + refreshCache(t); + return tm.Day; +} + +int weekday() { // Sunday is day 1 + return weekday(now()); +} + +int weekday(time_t t) { + refreshCache(t); + return tm.Wday; +} + +int month(){ + return month(now()); +} + +int month(time_t t) { // the month for the given time + refreshCache(t); + return tm.Month; +} + +int year() { // as in Processing, the full four digit year: (2009, 2010 etc) + return year(now()); +} + +int year(time_t t) { // the year for the given time + refreshCache(t); + return tmYearToCalendar(tm.Year); +} + +/*============================================================================*/ +/* functions to convert to and from system time */ +/* These are for interfacing with time serivces and are not normally needed in a sketch */ + +// leap year calulator expects year argument as years offset from 1970 +#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) + +static const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; // API starts months from 1, this array starts from 0 + +void breakTime(time_t time, tmElements_t &tm){ +// break the given time_t into time components +// this is a more compact version of the C library localtime function +// note that year is offset from 1970 !!! + + uint8_t year; + uint8_t month, monthLength; + unsigned long days; + + tm.Second = time % 60; + time /= 60; // now it is minutes + tm.Minute = time % 60; + time /= 60; // now it is hours + tm.Hour = time % 24; + time /= 24; // now it is days + tm.Wday = ((time + 4) % 7) + 1; // Sunday is day 1 + + year = 0; + days = 0; + while((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { + year++; + } + tm.Year = year; // year is offset from 1970 + + days -= LEAP_YEAR(year) ? 366 : 365; + time -= days; // now it is days in this year, starting at 0 + + days=0; + month=0; + monthLength=0; + for (month=0; month<12; month++) { + if (month==1) { // february + if (LEAP_YEAR(year)) { + monthLength=29; + } else { + monthLength=28; + } + } else { + monthLength = monthDays[month]; + } + + if (time >= monthLength) { + time -= monthLength; + } else { + break; + } + } + tm.Month = month + 1; // jan is month 1 + tm.Day = time + 1; // day of month +} + +time_t makeTime(tmElements_t &tm){ +// assemble time elements into time_t +// note year argument is offset from 1970 (see macros in time.h to convert to other formats) +// previous version used full four digit year (or digits since 2000),i.e. 2009 was 2009 or 9 + + int i; + time_t seconds; + + // seconds from 1970 till 1 jan 00:00:00 of the given year + seconds= tm.Year*(SECS_PER_DAY * 365); + for (i = 0; i < tm.Year; i++) { + if (LEAP_YEAR(i)) { + seconds += SECS_PER_DAY; // add extra days for leap years + } + } + + // add days for this year, months start from 1 + for (i = 1; i < tm.Month; i++) { + if ( (i == 2) && LEAP_YEAR(tm.Year)) { + seconds += SECS_PER_DAY * 29; + } else { + seconds += SECS_PER_DAY * monthDays[i-1]; //monthDay array starts from 0 + } + } + seconds+= (tm.Day-1) * SECS_PER_DAY; + seconds+= tm.Hour * SECS_PER_HOUR; + seconds+= tm.Minute * SECS_PER_MIN; + seconds+= tm.Second; + return seconds; +} +/*=====================================================*/ +/* Low level system time functions */ + +static time_t sysTime = 0; +static time_t prevMillis = 0; +static time_t nextSyncTime = 0; +static timeStatus_t Status = timeNotSet; + +getExternalTime getTimePtr; // pointer to external sync function +//setExternalTime setTimePtr; // not used in this version + +#ifdef TIME_DRIFT_INFO // define this to get drift data +time_t sysUnsyncedTime = 0; // the time sysTime unadjusted by sync +#endif + + +time_t now(){ + while( millis() - prevMillis >= 1000){ + sysTime++; + prevMillis += 1000; +#ifdef TIME_DRIFT_INFO + sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift +#endif + } + if(nextSyncTime <= sysTime){ + if(getTimePtr != 0){ + time_t t = getTimePtr(); + if( t != 0) + setTime(t); + else + Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync; + } + } + return sysTime; +} + +void setTime(time_t t){ +#ifdef TIME_DRIFT_INFO + if(sysUnsyncedTime == 0) + sysUnsyncedTime = t; // store the time of the first call to set a valid Time +#endif + + sysTime = t; + nextSyncTime = t + syncInterval; + Status = timeSet; + prevMillis = millis(); // restart counting from now (thanks to Korman for this fix) +} + +void setTime(int hr,int min,int sec,int dy, int mnth, int yr){ + // year can be given as full four digit year or two digts (2010 or 10 for 2010); + //it is converted to years since 1970 + if( yr > 99) + yr = yr - 1970; + else + yr += 30; + tm.Year = yr; + tm.Month = mnth; + tm.Day = dy; + tm.Hour = hr; + tm.Minute = min; + tm.Second = sec; + setTime(makeTime(tm)); +} + +void adjustTime(long adjustment){ + sysTime += adjustment; +} + +timeStatus_t timeStatus(){ // indicates if time has been set and recently synchronized + return Status; +} + +void setSyncProvider( getExternalTime getTimeFunction){ + getTimePtr = getTimeFunction; + nextSyncTime = sysTime; + now(); // this will sync the clock +} + +void setSyncInterval(time_t interval){ // set the number of seconds between re-sync + syncInterval = interval; +}
\ No newline at end of file diff --git a/Time/Time.h b/Time/Time.h new file mode 100644 index 0000000..e54f3b0 --- /dev/null +++ b/Time/Time.h @@ -0,0 +1,126 @@ +/* + time.h - low level time and date functions +*/ + +/* + July 3 2011 - fixed elapsedSecsThisWeek macro (thanks Vincent Valdy for this) + - fixed daysToTime_t macro (thanks maniacbug) +*/ + +#ifndef _Time_h +#define _Time_h + +#include <inttypes.h> + +typedef unsigned long time_t; + +typedef enum {timeNotSet, timeNeedsSync, timeSet +} timeStatus_t ; + +typedef enum { + dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday +} timeDayOfWeek_t; + +typedef enum { + tmSecond, tmMinute, tmHour, tmWday, tmDay,tmMonth, tmYear, tmNbrFields +} tmByteFields; + +typedef struct { + uint8_t Second; + uint8_t Minute; + uint8_t Hour; + uint8_t Wday; // day of week, sunday is day 1 + uint8_t Day; + uint8_t Month; + uint8_t Year; // offset from 1970; +} tmElements_t, TimeElements, *tmElementsPtr_t; + +//convenience macros to convert to and from tm years +#define tmYearToCalendar(Y) ((Y) + 1970) // full four digit year +#define CalendarYrToTm(Y) ((Y) - 1970) +#define tmYearToY2k(Y) ((Y) - 30) // offset is from 2000 +#define y2kYearToTm(Y) ((Y) + 30) + +typedef time_t(*getExternalTime)(); +//typedef void (*setExternalTime)(const time_t); // not used in this version + + +/*==============================================================================*/ +/* Useful Constants */ +#define SECS_PER_MIN (60UL) +#define SECS_PER_HOUR (3600UL) +#define SECS_PER_DAY (SECS_PER_HOUR * 24UL) +#define DAYS_PER_WEEK (7UL) +#define SECS_PER_WEEK (SECS_PER_DAY * DAYS_PER_WEEK) +#define SECS_PER_YEAR (SECS_PER_WEEK * 52UL) +#define SECS_YR_2000 (946684800UL) // the time at the start of y2k + +/* Useful Macros for getting elapsed time */ +#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN) +#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN) +#define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR) +#define dayOfWeek(_time_) ((( _time_ / SECS_PER_DAY + 4) % DAYS_PER_WEEK)+1) // 1 = Sunday +#define elapsedDays(_time_) ( _time_ / SECS_PER_DAY) // this is number of days since Jan 1 1970 +#define elapsedSecsToday(_time_) (_time_ % SECS_PER_DAY) // the number of seconds since last midnight +// The following macros are used in calculating alarms and assume the clock is set to a date later than Jan 1 1971 +// Always set the correct time before settting alarms +#define previousMidnight(_time_) (( _time_ / SECS_PER_DAY) * SECS_PER_DAY) // time at the start of the given day +#define nextMidnight(_time_) ( previousMidnight(_time_) + SECS_PER_DAY ) // time at the end of the given day +#define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + ((dayOfWeek(_time_)-1) * SECS_PER_DAY) ) // note that week starts on day 1 +#define previousSunday(_time_) (_time_ - elapsedSecsThisWeek(_time_)) // time at the start of the week for the given time +#define nextSunday(_time_) ( previousSunday(_time_)+SECS_PER_WEEK) // time at the end of the week for the given time + + +/* Useful Macros for converting elapsed time to a time_t */ +#define minutesToTime_t ((M)) ( (M) * SECS_PER_MIN) +#define hoursToTime_t ((H)) ( (H) * SECS_PER_HOUR) +#define daysToTime_t ((D)) ( (D) * SECS_PER_DAY) // fixed on Jul 22 2011 +#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK) + +/*============================================================================*/ +/* time and date functions */ +int hour(); // the hour now +int hour(time_t t); // the hour for the given time +int hourFormat12(); // the hour now in 12 hour format +int hourFormat12(time_t t); // the hour for the given time in 12 hour format +uint8_t isAM(); // returns true if time now is AM +uint8_t isAM(time_t t); // returns true the given time is AM +uint8_t isPM(); // returns true if time now is PM +uint8_t isPM(time_t t); // returns true the given time is PM +int minute(); // the minute now +int minute(time_t t); // the minute for the given time +int second(); // the second now +int second(time_t t); // the second for the given time +int day(); // the day now +int day(time_t t); // the day for the given time +int weekday(); // the weekday now (Sunday is day 1) +int weekday(time_t t); // the weekday for the given time +int month(); // the month now (Jan is month 1) +int month(time_t t); // the month for the given time +int year(); // the full four digit year: (2009, 2010 etc) +int year(time_t t); // the year for the given time + +time_t now(); // return the current time as seconds since Jan 1 1970 +void setTime(time_t t); +void setTime(int hr,int min,int sec,int day, int month, int yr); +void adjustTime(long adjustment); + +/* date strings */ +#define dt_MAX_STRING_LEN 9 // length of longest date string (excluding terminating null) +char* monthStr(uint8_t month); +char* dayStr(uint8_t day); +char* monthShortStr(uint8_t month); +char* dayShortStr(uint8_t day); + +/* time sync functions */ +timeStatus_t timeStatus(); // indicates if time has been set and recently synchronized +void setSyncProvider( getExternalTime getTimeFunction); // identify the external time provider +void setSyncInterval(time_t interval); // set the number of seconds between re-sync + +/* low level functions to convert to and from system time */ +void breakTime(time_t time, tmElements_t &tm); // break time_t into elements +time_t makeTime(tmElements_t &tm); // convert time elements into time_t + + +#endif /* _Time_h */ + diff --git a/Time/keywords.txt b/Time/keywords.txt new file mode 100644 index 0000000..f921672 --- /dev/null +++ b/Time/keywords.txt @@ -0,0 +1,33 @@ +####################################### +# Syntax Coloring Map For Time +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### +time_t KEYWORD1 +####################################### +# Methods and Functions (KEYWORD2) +####################################### +now KEYWORD2 +second KEYWORD2 +minute KEYWORD2 +hour KEYWORD2 +day KEYWORD2 +month KEYWORD2 +year KEYWORD2 +isAM KEYWORD2 +isPM KEYWORD2 +weekday KEYWORD2 +setTime KEYWORD2 +adjustTime KEYWORD2 +setSyncProvider KEYWORD2 +setSyncInteval KEYWORD2 +timeStatus KEYWORD2 +####################################### +# Instances (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/TimeAlarms/Examples/TimeAlarmExample/TimeAlarmExample.pde b/TimeAlarms/Examples/TimeAlarmExample/TimeAlarmExample.pde new file mode 100644 index 0000000..5084ffd --- /dev/null +++ b/TimeAlarms/Examples/TimeAlarmExample/TimeAlarmExample.pde @@ -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); +} +
diff --git a/TimeAlarms/TimeAlarms.cpp b/TimeAlarms/TimeAlarms.cpp new file mode 100644 index 0000000..66b94f9 --- /dev/null +++ b/TimeAlarms/TimeAlarms.cpp @@ -0,0 +1,150 @@ +/*
+ 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
+}
+
+#include <WProgram.h>
+#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() ;
\ No newline at end of file diff --git a/TimeAlarms/TimeAlarms.h b/TimeAlarms/TimeAlarms.h new file mode 100644 index 0000000..fd82b10 --- /dev/null +++ b/TimeAlarms/TimeAlarms.h @@ -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 */ + diff --git a/TimeAlarms/keywords.txt b/TimeAlarms/keywords.txt new file mode 100644 index 0000000..1843a88 --- /dev/null +++ b/TimeAlarms/keywords.txt @@ -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
\ No newline at end of file diff --git a/TimeAlarms/readme.txt b/TimeAlarms/readme.txt new file mode 100644 index 0000000..e158c8d --- /dev/null +++ b/TimeAlarms/readme.txt @@ -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 – 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
+}
+
|