summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--DS1307RTC/DS1307RTC.cpp124
-rw-r--r--DS1307RTC/DS1307RTC.h31
-rw-r--r--DS1307RTC/keywords.txt22
-rw-r--r--DS1307RTC/readme.txt7
-rw-r--r--Time/DateStrings.cpp80
-rw-r--r--Time/Examples/Processing/SyncArduinoClock/SyncArduinoClock.pde70
-rw-r--r--Time/Examples/Processing/SyncArduinoClock/readme.txt9
-rw-r--r--Time/Examples/TimeGPS/TimeGPS.pde82
-rw-r--r--Time/Examples/TimeNTP/TimeNTP.pde120
-rw-r--r--Time/Examples/TimeRTC/TimeRTC.pde47
-rw-r--r--Time/Examples/TimeRTCLog/TimeRTCLog.pde106
-rw-r--r--Time/Examples/TimeRTCSet/TimeRTCSet.pde82
-rw-r--r--Time/Examples/TimeSerial/TimeSerial.pde82
-rw-r--r--Time/Examples/TimeSerialDateStrings/TimeSerialDateStrings.pde80
-rw-r--r--Time/Readme.txt131
-rw-r--r--Time/Time.cpp307
-rw-r--r--Time/Time.h126
-rw-r--r--Time/keywords.txt33
-rw-r--r--TimeAlarms/Examples/TimeAlarmExample/TimeAlarmExample.pde77
-rw-r--r--TimeAlarms/TimeAlarms.cpp150
-rw-r--r--TimeAlarms/TimeAlarms.h127
-rw-r--r--TimeAlarms/keywords.txt25
-rw-r--r--TimeAlarms/readme.txt220
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
+}
+