Created
April 2, 2015 03:20
-
-
Save wyojustin/7d60abeb62a1838dd6cf to your computer and use it in GitHub Desktop.
EMSL Alpha5 mods with Zulu and DST
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
AlphaClock.ino | |
-- Alpha Clock Five Firmware, version 2.1 -- | |
Version 2.1.0 - January 31, 2013 | |
Copyright (c) 2013 Windell H. Oskay. All right reserved. | |
http://www.evilmadscientist.com/ | |
------------------------------------------------------------ | |
Designed for Alpha Clock Five, a five letter word clock designed by | |
Evil Mad Scientist Laboratories http://www.evilmadscientist.com | |
Target: ATmega644A, clock at 16 MHz. | |
Designed to work with Arduino 1.0.3; untested with other versions. | |
For additional requrements, please see: | |
http://wiki.evilmadscience.com/Alpha_Clock_Firmware_v2 | |
Thanks to Trammell Hudson for inspiration and helpful discussion. | |
https://bitbucket.org/hudson/alphaclock | |
Thanks to William Phelps - wm (at) usa.net, for several important | |
bug fixes. https://github.com/wbphelps/AlphaClock | |
------------------------------------------------------------ | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 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 General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this library. If not, see <http://www.gnu.org/licenses/>. | |
Note that the two word lists included with this distribution are NOT licensed under the GPL. | |
- The list in fiveletterwords.h is derived from SCOWL, http://wordlist.sourceforge.net | |
Please see README-SCOWL.txt for copyright restrictions on the use and redistribution of this word list. | |
- The alternative list in fiveletterwordspd.h is in the PUBLIC DOMAIN, | |
and cannot be restricted by the GPL or other copyright licenses. | |
*/ | |
#include "alphafive.h" // Alpha Clock Five library | |
#include <avr/pgmspace.h> | |
#define USE_USA_DST // TJS: dailight savings (or USE_EURO_DST) | |
#define GMT_OFFSET = -5 // TJS: hour-offset from GMT | |
// Comment out exactly one of the following two lines | |
#include "fiveletterwords.h" // Standard word list -- | |
//#include "fiveletterwordspd.h" // Public domain alternative | |
#include <Time.h> // The Arduino Time library, http://www.arduino.cc/playground/Code/Time | |
#include <Wire.h> // For optional RTC module | |
#include <DS1307RTC.h> // For optional RTC module. (This library included with the Arduino Time library) | |
#include <EEPROM.h> // For saving settings | |
// "Factory" default configuration can be configured here: | |
#define a5brightLevelDefault 9 | |
#define a5HourMode24Default 0 | |
#define a5AlarmEnabledDefault 0 | |
#define a5AlarmHrDefault 7 | |
#define a5AlarmMinDefault 30 | |
#define a5NightLightTypeDefault 0 | |
#define a5AlarmToneDefault 2 | |
#define a5NumberCharSetDefault 2; | |
#define a5DisplayModeDefault 0; | |
// Clock mode variables | |
byte HourMode24; | |
byte AlarmEnabled; // If the "ALARM" function is currently turned on or off. | |
byte AlarmTimeHr; | |
byte AlarmTimeMin; | |
int8_t AlarmTone; | |
int8_t NightLightType; | |
byte NightLightSign; | |
unsigned int NightLightStep; | |
// Configuration menu: | |
byte menuItem; //Current position within options menu | |
int8_t optionValue; | |
#define MenuItemsMax 10 | |
#define AMPM24HRMenuItem 0 | |
#define NightLightMenuItem 1 | |
#define AlarmToneMenuItem 2 | |
#define SoundTestMenuItem 3 | |
#define numberCharSetMenuItem 4 | |
#define DisplayStyleMenuItem 5 | |
#define SetYearMenuItem 6 | |
#define SetMonthMenuItem 7 | |
#define SetDayMenuItem 8 | |
#define SetSecondsMenuItem 9 | |
#define AltModeMenuItem 10 | |
// Clock display mode: | |
int8_t DisplayMode; | |
int8_t DisplayModeLocalLast; | |
byte DisplayModePhase; | |
byte DisplayModePhaseCount; | |
byte VCRmode; | |
byte modeShowMenu; | |
byte modeShowDateViaButtons; | |
byte modeLEDTest; | |
byte UpdateEE; | |
int8_t numberCharSet; | |
// Other global variables: | |
byte UseRTC; | |
unsigned long NextClockUpdate, NextAlarmCheck; | |
unsigned long milliTemp; | |
unsigned int FLWoffset; // Counter variable for FLW (Five Letter Word) display mode | |
// Text Display Variables: | |
unsigned long DisplayWordEndTime; | |
char wordCache[5]; | |
char dpCache[5]; | |
byte wordSequence; | |
byte wordSequenceStep; | |
byte modeShowText; | |
byte RedrawNow, RedrawNow_NoFade; | |
// Button Management: | |
#define ButtonCheckInterval 20 // Time delay between responding to button state, ms | |
#define HoldDownTime 2000 // How long to hold buttons to acces smenus requiring holding two buttons | |
byte buttonStateLast; | |
byte buttonMonitor; | |
unsigned long Btn1_AlrmSet_StartTime, Btn2_TimeSet_StartTime, Btn3_Plus_StartTime, Btn4_Minus_StartTime; | |
unsigned long NextButtonCheck, LastButtonPress; | |
byte UpdateAlarmState, UpdateBrightness; | |
byte AlarmTimeChanged, TimeChanged; | |
byte holdDebounce; | |
// Brightness steps for manual brightness adjustment | |
byte Brightness; | |
#define BrightnessMax 11 | |
byte MBlevel[] = { | |
0, 1, 5,10,15,19,15,19, 5,10,15,19}; | |
byte MBmode[] = { | |
0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 2, 2}; | |
// For fade and update management: | |
byte SecLast; | |
byte MinNowOnesLast; | |
byte MinAlarmOnesLast; | |
//Alarm variables | |
byte AlarmTimeSnoozeMin; | |
byte AlarmTimeSnoozeHr; | |
byte snoozed; | |
byte alarmPrimed; | |
byte alarmNow; | |
byte modeShowAlarmTime; | |
byte SoundSequence; | |
void incrementAlarm(void) | |
{ // Advance alarm time by one minute | |
AlarmTimeMin += 1; | |
if (AlarmTimeMin > 59) | |
{ | |
AlarmTimeMin = 0; | |
AlarmTimeHr += 1; | |
if (AlarmTimeHr > 23) | |
AlarmTimeHr = 0; | |
} | |
UpdateEE = 1; | |
} | |
void decrementAlarm(void) | |
{ // Retard alarm time by one minute | |
if (AlarmTimeMin > 0) | |
AlarmTimeMin--; | |
else | |
{ | |
AlarmTimeMin = 59; | |
if (AlarmTimeHr > 0) | |
AlarmTimeHr--; | |
else | |
AlarmTimeHr = 23; | |
} | |
UpdateEE = 1; | |
} | |
void TurnOffAlarm(void) | |
{ // This cancels the alarm when it is going off (or snoozed). | |
// It does leave the alarm enabled for next time, however. | |
if (alarmNow || snoozed){ | |
snoozed = 0; | |
alarmNow = 0; | |
a5noTone(); | |
if (modeShowMenu == 0) | |
DisplayWordSequence(2); // Display: "ALARM OFF", EXCEPT if we are in the menus. | |
} | |
} | |
void checkButtons(void ) | |
{ | |
buttonMonitor |= a5GetButtons(); | |
if (milliTemp >= NextButtonCheck) // Typically, go through this every 20 ms. | |
{ | |
NextButtonCheck = milliTemp + ButtonCheckInterval; | |
/* | |
#define a5alarmSetBtn 1 // Snooze/Set alarm button | |
#define a5timeSetBtn 2 // Set time button | |
#define a5plusBtn 4 // + button | |
#define a5minusBtn 8 // - button | |
*/ | |
if (buttonMonitor){ // If any buttons have been down in last ButtonCheckInterval | |
if (VCRmode) | |
EndVCRmode(); // Turn off VCR-blink mode, if it was still on. | |
// Check to see if any of the buttons has JUST been depressed: | |
if (( buttonMonitor & a5_alarmSetBtn) && ((buttonStateLast & a5_alarmSetBtn) == 0)) | |
{ // If Alarm Set button was just depressed | |
Btn1_AlrmSet_StartTime = milliTemp; | |
if (alarmNow){ // If alarm is going off, this button is the SNOOZE button. | |
if (modeShowMenu) | |
{ | |
TurnOffAlarm(); | |
} | |
else{ | |
alarmNow = 0; | |
a5noTone(); | |
snoozed = 1; | |
a5editFontChar ('a', 54, 1, 37); // Define special character | |
DisplayWord ("SNaZE", 1500); | |
AlarmTimeSnoozeMin = minute() + 9; | |
AlarmTimeSnoozeHr = hour(); | |
if ( AlarmTimeSnoozeMin > 59){ | |
AlarmTimeSnoozeMin -= 60; | |
AlarmTimeSnoozeHr += 1; | |
} | |
if (AlarmTimeSnoozeHr > 23) | |
AlarmTimeSnoozeHr -= 24; | |
} | |
} | |
} | |
if (( buttonMonitor & a5_timeSetBtn) && ((buttonStateLast & a5_timeSetBtn) == 0)){ | |
// Button S2 just depressed. | |
Btn2_TimeSet_StartTime = milliTemp; | |
TimeChanged = 0; | |
} | |
if (( buttonMonitor & a5_plusBtn) && ((buttonStateLast & a5_plusBtn) == 0)) | |
Btn3_Plus_StartTime = milliTemp; | |
if (( buttonMonitor & a5_minusBtn) && ((buttonStateLast & a5_minusBtn) == 0)) | |
Btn4_Minus_StartTime = milliTemp; | |
} | |
else if ((buttonStateLast == 0 ) && ( buttonMonitor == 0)) | |
{ | |
// Reset some variables if all buttons are up, and have not just been released: | |
TimeChanged = 0; | |
AlarmTimeChanged = 0; | |
holdDebounce = 1; | |
} | |
if (modeShowMenu || buttonMonitor) | |
LastButtonPress = milliTemp; //Reset EEPROM Save Timer if menu shown, or if a button pressed. | |
if (modeShowMenu && holdDebounce){ // Button behavior, when in Config menu mode: | |
// Check to see if AlarmSet button was JUST released:: | |
if ( ((buttonMonitor & a5_alarmSetBtn) == 0) && (buttonStateLast & a5_alarmSetBtn)) | |
{ | |
if ( menuItem > 0) //Decrement current position within options menu | |
menuItem--; | |
else | |
menuItem = MenuItemsMax; // Wrap-around at low-end of menu | |
optionValue = 0; | |
TurnOffAlarm(); | |
DisplayMenuOptionName(); | |
} | |
// If TimeSet button was just released:: | |
if (( (buttonMonitor & a5_timeSetBtn) == 0) && (buttonStateLast & a5_timeSetBtn)) | |
{ | |
if ((alarmNow) || (snoozed)){ // Just Turn Off Alarm | |
TurnOffAlarm(); | |
} | |
else { // If we are in a configuration menu | |
menuItem++; | |
if ( menuItem > MenuItemsMax) //Decrement current position within options menu | |
menuItem = 0; // Wrap-around at high-end of menu | |
optionValue = 0; | |
TurnOffAlarm(); | |
DisplayMenuOptionName(); | |
} | |
} | |
if (( (buttonMonitor & a5_plusBtn) == 0) && (buttonStateLast & a5_plusBtn)) | |
{ // The "+" button has just been released. | |
optionValue = 1; | |
UpdateEE = 1; | |
RedrawNow = 1; | |
} | |
if (( (buttonMonitor & a5_minusBtn) == 0) && (buttonStateLast & a5_minusBtn)) | |
{ // The "-" Button has just been released. | |
optionValue = -1; | |
UpdateEE = 1; | |
RedrawNow = 1; | |
} | |
} | |
else | |
{ // Button behavior, when NOT in Config menu mode: | |
///////////////////////////// Time-Of-Day Adjustments ///////////////////////////// | |
// Check to see if both time-set button and plus button are both currently depressed: | |
if (( buttonMonitor & a5_TimeSetPlusBtns) == a5_TimeSetPlusBtns) | |
if (TimeChanged < 2) | |
{ | |
adjustTime(60); // Add one minute | |
RedrawNow = 1; | |
TimeChanged = 2; // One-time press: detected | |
if (UseRTC) | |
RTC.set(now()); | |
} | |
else if ( milliTemp >= (Btn3_Plus_StartTime + 400)) | |
{ | |
adjustTime(60); // Add one minute | |
RedrawNow_NoFade = 1; | |
if (UseRTC) | |
RTC.set(now()); | |
} | |
// Check to see if both time-set button and minus button are both currently depressed: | |
if (( buttonMonitor & a5_TimeSetMinusBtns) == a5_TimeSetMinusBtns) | |
if (TimeChanged < 2) | |
{ | |
adjustTime(-60); // Subtract one minute | |
RedrawNow = 1; | |
TimeChanged = 2; | |
if (UseRTC) | |
RTC.set(now()); | |
} | |
else if ( milliTemp > (Btn4_Minus_StartTime + 400 )) | |
{ | |
adjustTime(-60); // Subtract one minute | |
RedrawNow_NoFade = 1; | |
// TimeChanged = 1; | |
if (UseRTC) | |
RTC.set(now()); | |
} | |
///////////////////////////// Time-Of-Alarm Adjustments ///////////////////////////// | |
// Entering alarm mode: | |
// If Alarm button has been down 40 ms, | |
// (to avoid displaying alarm if Alarm+Time buttons are pressed at the same time) | |
// the Set Time button is not down, | |
// and no other high-priority modes are enabled... | |
if (( buttonMonitor & a5_alarmSetBtn) && (modeShowAlarmTime == 0)) | |
if ((( buttonMonitor & a5_timeSetBtn) == 0) && (modeShowText == 0)) | |
if ( milliTemp >= (Btn1_AlrmSet_StartTime + 40 )) // of those "ifs," Check hold-time LAST. | |
{ | |
modeShowAlarmTime = 1; | |
RedrawNow = 1; | |
AlarmTimeChanged = 0; | |
} | |
// Check to see if both alarm-set button and plus button are both currently depressed: | |
if (( buttonMonitor & a5_AlarmSetPlusBtns) == a5_AlarmSetPlusBtns) | |
if (TimeChanged < 2) | |
{ | |
incrementAlarm(); // Add one minute | |
RedrawNow = 1; | |
TimeChanged = 2; // One-time press: detected | |
snoozed = 0; // Recalculating alarm time *turns snooze off.* | |
} | |
else if ( milliTemp >= (Btn3_Plus_StartTime + 400)) | |
{ | |
incrementAlarm(); // Add one minute | |
RedrawNow_NoFade = 1; | |
// TimeChanged = 1; | |
} | |
// Check to see if both alarm-set button and minus button are both currently depressed: | |
if (( buttonMonitor & a5_AlarmSetMinusBtns) == a5_AlarmSetMinusBtns) | |
if (TimeChanged < 2) | |
{ | |
decrementAlarm(); // Subtract one minute | |
RedrawNow = 1; | |
TimeChanged = 2; // One-time press: detected | |
snoozed = 0; // Recalculating alarm time *turns snooze off.* | |
} | |
else if ( milliTemp > (Btn4_Minus_StartTime + 400)) | |
{ | |
decrementAlarm(); // Subtract one minute | |
RedrawNow_NoFade = 1; | |
// TimeChanged = 1; | |
} | |
// Check to see if both S1 and S2 are both currently depressed: | |
if (( buttonMonitor & a5_alarmSetBtn) && ( buttonMonitor & a5_timeSetBtn)) | |
{ | |
if (modeShowDateViaButtons == 0) | |
{ // Display date | |
modeShowDateViaButtons = 1; | |
TimeChanged = 1; // This overrides the usual alarm on/off function of the time set button. | |
RedrawNow = 1; | |
} | |
} | |
///////////////////////////// ENTERING & LEAVING LED TEST MODE ///////////////////////////// | |
// Check to see if both S1 and S2 are both currently held down: | |
if (( buttonMonitor & a5_alarmSetBtn) && ( buttonMonitor & a5_timeSetBtn)) | |
{ | |
if( (milliTemp >= (Btn1_AlrmSet_StartTime + 2 * HoldDownTime )) && (milliTemp >= (Btn2_TimeSet_StartTime + 2 * HoldDownTime ))) | |
{ | |
Btn1_AlrmSet_StartTime = milliTemp; // Reset hold-down timer | |
Btn2_TimeSet_StartTime = milliTemp; // Reset hold-down timer | |
holdDebounce = 0; | |
if (modeLEDTest) // If we are currently in the LED Test mode, | |
{ | |
modeLEDTest = 0; // Exit LED Test Mode | |
RedrawNow = 1; | |
DisplayWord ("-END-", 1500); | |
} | |
else | |
{ | |
// Display version and enter LED Test Mode | |
modeLEDTest = 1; | |
DisplayWordSequence(5); | |
SoundSequence = 0; | |
} | |
} | |
} | |
// Check to see if AlarmSet button was JUST released:: | |
if ( ((buttonMonitor & a5_alarmSetBtn) == 0) && (buttonStateLast & a5_alarmSetBtn)) | |
{ | |
if (modeShowAlarmTime && holdDebounce){ | |
modeShowAlarmTime = 0; | |
RedrawNow = 1; | |
} | |
if (modeShowDateViaButtons == 1) | |
{ | |
modeShowDateViaButtons = 0; | |
RedrawNow = 1; | |
} | |
} | |
// If TimeSet button was just released:: | |
if (( (buttonMonitor & a5_timeSetBtn) == 0) && (buttonStateLast & a5_timeSetBtn)) | |
{ | |
if (holdDebounce) | |
{ | |
if ((alarmNow) || (snoozed)){ // Just Turn Off Alarm | |
TurnOffAlarm(); | |
} | |
else if (TimeChanged == 0){ // If the time has just been adjusted, DO NOT change alarm status. | |
RedrawNow = 1; | |
UpdateEE = 1; | |
if (AlarmEnabled) | |
AlarmEnabled = 0; | |
else | |
{ | |
AlarmEnabled = 1; | |
} | |
} | |
else | |
{ | |
if (UseRTC) | |
RTC.set(now()); | |
} | |
} | |
} | |
if (( (buttonMonitor & a5_plusBtn) == 0) && (buttonStateLast & a5_plusBtn)) | |
{ // The "+" button has just been released. | |
if (holdDebounce) | |
{ | |
if (TimeChanged > 0) | |
TimeChanged = 1; // Acknowledge that the button has been released, for purposes of time editing. | |
if (AlarmTimeChanged > 0) | |
AlarmTimeChanged = 1; // Acknowledge that the button has been released, for purposes of time editing. | |
// IF no other buttons are down, increase brightness: | |
if (((buttonMonitor & a5_allButtonsButPlus) == 0) && (AlarmTimeChanged + TimeChanged == 0)) | |
if (Brightness < BrightnessMax) | |
{ | |
Brightness++; | |
UpdateBrightness = 1; | |
UpdateEE = 1; | |
} | |
} | |
} | |
if (( (buttonMonitor & a5_minusBtn) == 0) && (buttonStateLast & a5_minusBtn)) | |
{ // The "-" Button has just been released. | |
if (holdDebounce){ | |
if (TimeChanged > 0) | |
TimeChanged = 1; // Acknowledge that the button has been released, for purposes of time editing. | |
if (AlarmTimeChanged > 0) | |
AlarmTimeChanged = 1; // Acknowledge that the button has been released, for purposes of time editing. | |
// IF no other buttons are down, and times have not been adjusted, decrease brightness: | |
if(((buttonMonitor & a5_allButtonsButMinus) == 0) && (AlarmTimeChanged + TimeChanged == 0)) | |
if (Brightness > 0) | |
{ | |
Brightness--; | |
UpdateBrightness = 1; | |
UpdateEE = 1; | |
} | |
} | |
} | |
} // End not-in-config-menu statements | |
///////////////////////////// ENTERING & LEAVING CONFIG MENU ///////////////////////////// | |
// Check to see if both S3 and S4 are both currently held down: | |
if (( buttonMonitor & a5_plusBtn) && ( buttonMonitor & a5_minusBtn)) | |
{ | |
if( (milliTemp >= (Btn3_Plus_StartTime + HoldDownTime )) && (milliTemp >= (Btn4_Minus_StartTime + HoldDownTime ))) | |
{ | |
Btn3_Plus_StartTime = milliTemp; // Reset hold-down timer | |
Btn4_Minus_StartTime = milliTemp; // Reset hold-down timer | |
holdDebounce = 0; | |
TurnOffAlarm(); | |
if (modeShowMenu) // If we are currently in the configuration menu, | |
{ | |
modeShowMenu = 0; // Exit configuration menu | |
DisplayWord (" ", 500); | |
} | |
else | |
{ | |
modeShowMenu = 1; // Enter configuration menu | |
menuItem = 0; | |
DisplayWord (" ", 500); | |
} | |
} | |
} | |
buttonStateLast = buttonMonitor; | |
buttonMonitor = 0; | |
} | |
} | |
void DisplayMenuOptionName(void){ | |
// Display title of menu name after switching to new menu utem. | |
switch (menuItem) { | |
case NightLightMenuItem: | |
DisplayWordSequence(4); // Night Light | |
break; | |
case AlarmToneMenuItem: | |
DisplayWordSequence(6); // Alarm Tone | |
break; | |
case SoundTestMenuItem: | |
DisplayWordSequence(3); // Sound-test menu item, 3. Display "TEST" "SOUND" "USE+-" | |
break; | |
case numberCharSetMenuItem: | |
DisplayWordSequence(7); // Font Style | |
break; | |
case DisplayStyleMenuItem: | |
DisplayWordSequence(8); // Clock Style | |
break; | |
case SetYearMenuItem: | |
DisplayWord ("YEAR ", 800); | |
DisplayWordDP("___12"); | |
break; | |
case SetMonthMenuItem: | |
DisplayWord ("MONTH", 800); | |
break; | |
case SetDayMenuItem: | |
DisplayWord ("DAY ", 800); | |
DisplayWordDP("__12_"); | |
break; | |
case SetSecondsMenuItem: | |
DisplayWord ("SECS ", 800); | |
DisplayWordDP("___12"); | |
break; | |
case AltModeMenuItem: | |
DisplayWordSequence(9); // "TIME AND..." | |
// DisplayWord ("ALTW/", 2000); | |
// DisplayWordDP("__11_"); | |
break; | |
default: // do nothing! | |
break; | |
} | |
} | |
void ManageAlarm (void) { | |
if ((SoundSequence == 0) && (modeShowMenu == 0)) | |
DisplayWord ("ALARM", 400); // Synchronize with sounds! | |
//RedrawNow_NoFade = 1; | |
if ( (TIMSK1 & _BV(OCIE1A)) == 0) { // If last tone has finished | |
if (AlarmTone == 0) // X-Low Tone | |
{ | |
if (SoundSequence < 8) | |
{ | |
if (SoundSequence & 1) | |
a5tone( 50, 300); | |
else | |
a5tone(0, 300); | |
SoundSequence++; | |
} | |
else | |
{ | |
a5tone(0, 1200); | |
SoundSequence = 0; | |
} | |
} | |
else if (AlarmTone == 1) // Low Tone | |
{ | |
if (SoundSequence < 8) | |
{ | |
if (SoundSequence & 1) | |
a5tone( 100, 200); | |
else | |
a5tone(0, 200); | |
SoundSequence++; | |
} | |
else | |
{ | |
a5tone(0, 1200); | |
SoundSequence = 0; | |
} | |
} | |
else if (AlarmTone == 2) // Med Tone | |
{ | |
if (SoundSequence < 6) | |
{ | |
if (SoundSequence & 1) | |
a5tone( 1000, 200); | |
else | |
a5tone( 0, 200); | |
SoundSequence++; | |
} | |
else | |
{ | |
a5tone( 0, 1400); | |
SoundSequence = 0; | |
} | |
} | |
else if (AlarmTone == 3) // High Tone | |
{ | |
if (SoundSequence < 6) | |
{ | |
if (SoundSequence & 1) | |
a5tone( 2050, 300); | |
else | |
a5tone( 0, 200); | |
SoundSequence++; | |
} | |
else | |
{ | |
a5tone(0, 1000); | |
SoundSequence = 0; | |
} | |
} | |
else if (AlarmTone == 4) // Siren Tone | |
{ | |
if (SoundSequence < 254) | |
{ | |
a5tone(20 + 4 * SoundSequence, 2); | |
SoundSequence++; | |
} | |
else if (SoundSequence == 254) | |
{ | |
a5tone(20 + 4 * SoundSequence, 1500); | |
SoundSequence++; | |
} | |
else { | |
a5tone(0, 1000); | |
SoundSequence = 0; | |
} | |
} | |
else if (AlarmTone == 5) // "Tink" Tone | |
{ | |
if (SoundSequence == 0) | |
{ | |
a5tone( 1000, 50); // was 50 | |
SoundSequence++; | |
} | |
else if (SoundSequence == 1) | |
{ | |
a5tone(0, 1900); | |
SoundSequence++; | |
} | |
else | |
{ | |
a5tone(0, 50); | |
SoundSequence = 0; | |
} | |
} | |
} | |
} | |
void DisplayWordSequence (byte sequence) | |
{ // Usage: // DisplayWordSequence(1); // displays "HELLO" "WORLD" | |
if (sequence != wordSequence) | |
{ | |
wordSequence = sequence; | |
wordSequenceStep = 0; | |
} | |
DisplayWordDP("_____"); // Blank DPs unless stated otherwise. | |
wordSequenceStep++; | |
switch (sequence) { | |
case 1: //Display "HELLO" "WORLD" | |
if (wordSequenceStep == 1) | |
DisplayWord ("HELLO", 800); | |
else if (wordSequenceStep == 3) | |
DisplayWord ("WORLD", 800); | |
else if (wordSequenceStep < 5) | |
DisplayWord (" ", 300); | |
else | |
wordSequence = 0; | |
break; | |
case 2: //Display "ALARM" " OFF " | |
if (wordSequenceStep == 1) | |
DisplayWord ("ALARM", 800); | |
else if (wordSequenceStep == 3) | |
DisplayWord (" OFF ", 800); | |
else if (wordSequenceStep < 5) | |
DisplayWord (" ", 100); | |
else | |
wordSequence = 0; | |
break; | |
case 3: //Display "TEST" "SOUND" "USE+-" | |
if (wordSequenceStep == 1) | |
DisplayWord ("TEST ", 600); | |
else if (wordSequenceStep == 3) | |
DisplayWord ("SOUND", 600); | |
else if (wordSequenceStep == 5) | |
DisplayWord ("USE+-", 600); | |
else if (wordSequenceStep < 7) | |
DisplayWord (" ", 200); | |
else | |
wordSequence = 0; | |
break; | |
case 4: //Display "NIGHT" "LIGHT" | |
if (wordSequenceStep == 1) | |
DisplayWord ("NIGHT", 600); | |
else if (wordSequenceStep == 3) | |
DisplayWord ("LIGHT", 600); | |
else if (wordSequenceStep < 5) | |
DisplayWord (" ", 100); | |
else | |
wordSequence = 0; | |
break; | |
case 5: //Display "VER21" " LED " "TEST " // Display software version number, 2.1 | |
if (wordSequenceStep == 1){ | |
DisplayWord ("VER21", 2000); | |
DisplayWordDP("___1_"); | |
} | |
else if (wordSequenceStep == 3) | |
DisplayWord (" LED ", 1000); | |
else if (wordSequenceStep == 5) | |
DisplayWord ("TEST ", 1000); | |
else if (wordSequenceStep < 7) | |
DisplayWord (" ", 200); | |
else | |
wordSequence = 0; | |
break; | |
case 6: //Display "ALARM" "TONE" | |
if (wordSequenceStep == 1) | |
DisplayWord ("ALARM", 700); | |
else if (wordSequenceStep == 3) | |
DisplayWord (" TONE", 700); | |
else if (wordSequenceStep < 5) | |
DisplayWord (" ", 100); | |
else | |
wordSequence = 0; | |
break; | |
case 7: //Display "FONT " "STYLE" | |
if (wordSequenceStep == 1) | |
DisplayWord ("FONT ", 700); | |
else if (wordSequenceStep == 3) | |
DisplayWord ("STYLE", 700); | |
else if (wordSequenceStep < 5) | |
DisplayWord (" ", 100); | |
else | |
wordSequence = 0; | |
break; | |
case 8: //Display "CLOCK" "STYLE" | |
if (wordSequenceStep == 1) | |
DisplayWord ("CLOCK", 700); | |
else if (wordSequenceStep == 3) | |
DisplayWord ("STYLE", 700); | |
else if (wordSequenceStep < 5) | |
DisplayWord (" ", 100); | |
else | |
wordSequence = 0; | |
break; | |
case 9: //Display "TIME" "AND..." | |
if (wordSequenceStep == 1) | |
DisplayWord ("TIME ", 900); | |
else if (wordSequenceStep == 3){ | |
DisplayWord ("AND ", 900); | |
DisplayWordDP("__111"); | |
} | |
else if (wordSequenceStep < 5) | |
DisplayWord (" ", 100); | |
else | |
wordSequence = 0; | |
break; | |
default: | |
// Turn off word sequences. (Catches case 0.) | |
wordSequence = 0; | |
wordSequenceStep = 0; | |
} | |
} | |
void DisplayWord (char WordIn[], unsigned int duration) | |
{ // Usage: DisplayWord ("ALARM", 500); | |
modeShowText = 1; | |
wordCache[0] = WordIn[0]; | |
wordCache[1] = WordIn[1]; | |
wordCache[2] = WordIn[2]; | |
wordCache[3] = WordIn[3]; | |
wordCache[4] = WordIn[4]; | |
DisplayWordEndTime = milliTemp + duration; | |
RedrawNow = 1; | |
} | |
void DisplayWordDP (char WordIn[]) | |
{ | |
// Usage: DisplayWord ("_123_"); | |
// Add or edit decimals for text displayed via DisplayWord(). | |
// Call in conjuction with DisplayWord, just before or after. | |
dpCache[0] = WordIn[0]; | |
dpCache[1] = WordIn[1]; | |
dpCache[2] = WordIn[2]; | |
dpCache[3] = WordIn[3]; | |
dpCache[4] = WordIn[4]; | |
} | |
void EndVCRmode(){ | |
if (VCRmode){ | |
a5_brightLevel = MBlevel[Brightness]; | |
RedrawNow_NoFade = 1; | |
VCRmode = 0; | |
randomSeed(now()); // Either a button press or RTC time | |
} | |
} | |
void setup() { | |
a5Init(); // Required hardware init for Alpha Clock Five library functions | |
VCRmode = 1; | |
Serial.println("\nHello, World."); | |
Serial.println("Alpha Clock Five here, reporting for duty!"); | |
EEReadSettings(); // Read settings stored in EEPROM | |
if (Brightness == 0) | |
Brightness = 1; // If display is fully dark at reset, turn it up to minimum brightness. | |
UseRTC = a5CheckForRTC(); | |
if (UseRTC) | |
{ | |
setSyncProvider(RTC.get); // Function to get the time from the RTC (e.g., Chronodot) | |
if(timeStatus()!= timeSet) { | |
Serial.println("RTC detected, *but* I can't seem to sync to it. ;("); | |
UseRTC = 0; | |
} | |
else { | |
Serial.println("System time: Set by RTC. Rock on!"); | |
EndVCRmode(); | |
} | |
} | |
else | |
Serial.println("RTC not detected. I don't know what time it is. :("); | |
if ( UseRTC == 0) | |
{ | |
Serial.println("Setting the date to 2013. I didn't exist in 1970."); | |
setTime(0,0,0,1, 1, 2013); | |
} | |
SerialPrintTime(); | |
NextClockUpdate = millis() + 1; | |
buttonMonitor = 0; | |
holdDebounce = 0; | |
modeShowAlarmTime = 0; | |
modeShowDateViaButtons = 0; // for button-press date display | |
modeShowMenu = 0; | |
modeShowText = 0; | |
modeLEDTest = 0; | |
// Alarm Setup: | |
snoozed = 0; | |
alarmPrimed = 0; | |
alarmNow = 0; | |
SoundSequence = 0; | |
NextButtonCheck = NextClockUpdate; | |
NextAlarmCheck = NextClockUpdate; | |
UpdateEE = 0; | |
LastButtonPress = NextClockUpdate; | |
wordSequence = 0; | |
wordSequenceStep = 0; | |
RedrawNow = 1; | |
RedrawNow_NoFade = 0; | |
UpdateBrightness = 0; | |
DisplayWordSequence(1); // Display: Hello world | |
buttonMonitor = a5GetButtons(); | |
if (( buttonMonitor & a5_alarmSetBtn) && ( buttonMonitor & a5_timeSetBtn)) | |
{ | |
// If Alarm button and Time button (LED Test buttons) held down at turn on, reset to defaults. | |
Brightness = a5brightLevelDefault; | |
HourMode24 = a5HourMode24Default; | |
AlarmEnabled = a5AlarmEnabledDefault; | |
AlarmTimeHr = a5AlarmHrDefault; | |
AlarmTimeMin = a5AlarmMinDefault; | |
AlarmTone = a5AlarmToneDefault; | |
NightLightType = a5NightLightTypeDefault; | |
numberCharSet = a5NumberCharSetDefault; | |
DisplayMode = a5DisplayModeDefault; | |
wordSequenceStep = 0; | |
DisplayWord ("*****", 1000); | |
} | |
a5_brightLevel = MBlevel[Brightness]; | |
a5_brightMode = MBmode[Brightness]; | |
a5loadAltNumbers(numberCharSet); | |
FLWoffset = 0; | |
NightLightSign = 1; | |
NightLightStep = 0; | |
updateNightLight(); | |
DisplayModePhase = 0; | |
DisplayModePhaseCount = 0; | |
} | |
void loop() { | |
milliTemp = millis(); | |
checkButtons(); | |
if (UpdateBrightness) | |
{ | |
UpdateBrightness = 0; // Reset the flag that triggered this clause. | |
if (a5_brightMode == MBmode[Brightness]) | |
{ | |
a5_brightLevel = MBlevel[Brightness]; | |
UpdateDisplay (1); // Force update of display data, with new brightness level | |
} | |
else | |
{ | |
a5_brightLevel = 0; | |
UpdateDisplay (1); // Force update of display data, with temporary brightness level | |
a5loadVidBuf_fromOSB(); | |
a5_brightLevel = MBlevel[Brightness]; | |
UpdateDisplay (1); // Force update of display data, with new brightness level | |
a5_brightMode = MBmode[Brightness]; | |
} | |
} | |
if (VCRmode) | |
{ | |
if (modeShowText == 0){ | |
byte temp = second() & 1; | |
if((temp) && (VCRmode == 1)) | |
{ | |
a5_brightLevel = 0; | |
RedrawNow_NoFade = 1; | |
VCRmode = 2; | |
} | |
if((temp == 0) && (VCRmode == 2)) | |
{ | |
a5_brightLevel = MBlevel[Brightness]; | |
RedrawNow_NoFade = 1; | |
VCRmode = 1; | |
} | |
} | |
} | |
if (RedrawNow || RedrawNow_NoFade) | |
{ | |
NextClockUpdate = milliTemp + 10; // Reset auto-redraw timer. | |
UpdateDisplay (1); // Force redraw | |
if (RedrawNow_NoFade) // Explicitly do not fade. Takes priority over redraw with fade. | |
a5_FadeStage = -1; | |
a5LoadNextFadeStage(); | |
a5loadVidBuf_fromOSB(); | |
RedrawNow = 0; | |
RedrawNow_NoFade = 0; | |
} | |
else if (milliTemp >= NextClockUpdate) // Update at most 100 times per second | |
{ | |
NextClockUpdate = milliTemp + 10; // Reset auto-redraw timer. | |
UpdateDisplay (0); // Argument 0: Only update if display data has changed. | |
a5LoadNextFadeStage(); | |
a5loadVidBuf_fromOSB(); | |
if (NightLightType >= 4) // Only in pulse mode do we need to regularly update | |
updateNightLight(); | |
if (UpdateEE) // Don't need to check this more than 100 times/second. | |
EESaveSettings(); | |
} | |
// Check for alarm: | |
if (milliTemp >= NextAlarmCheck) | |
{ | |
NextAlarmCheck = milliTemp + 500; // Check again in 1/2 second. | |
if (AlarmEnabled) { | |
byte hourTemp = hour(); | |
byte minTemp = minute(); | |
if ((AlarmTimeHr == hourTemp ) && (AlarmTimeMin == minTemp )) | |
{ | |
if (alarmPrimed){ | |
alarmPrimed = 0; | |
alarmNow = 1; | |
snoozed = 0; | |
SoundSequence = 0; | |
} | |
} | |
else{ | |
alarmPrimed = 1; | |
// Prevent alarm from going off twice in the same minute, after being turned off and back on. | |
} | |
if (snoozed) | |
if ((AlarmTimeSnoozeHr == hourTemp ) && (AlarmTimeSnoozeMin == minTemp )) | |
{ | |
alarmNow = 1; | |
snoozed = 0; | |
SoundSequence = 0; | |
} | |
} | |
} | |
if (alarmNow) | |
ManageAlarm(); | |
if(Serial.available() ) | |
{ | |
processSerialMessage(); | |
} | |
} | |
#define a5_COMM_MSG_LEN 13 // time sync to PC is HEADER followed by unix time_t as ten ascii digits (Was 11) | |
#define a5_COMM_HEADER 255 // Header tag for serial sync messages | |
void SerialSendDataDaisyChain (char DataIn[]) | |
{ | |
char outputBuffer[13]; | |
char *toPtr = &outputBuffer[0]; | |
char *fromPtr = &DataIn[0]; | |
*toPtr++ = 255; | |
*toPtr++ = *fromPtr++; | |
*toPtr++ = *fromPtr++; | |
*toPtr++ = *fromPtr++; | |
*toPtr++ = *fromPtr++; | |
*toPtr++ = *fromPtr++; | |
*toPtr++ = *fromPtr++; | |
*toPtr++ = *fromPtr++; | |
*toPtr++ = *fromPtr++; | |
*toPtr++ = *fromPtr++; | |
*toPtr++ = *fromPtr++; | |
*toPtr++ = *fromPtr++; | |
*toPtr = *fromPtr; | |
Serial1.write(outputBuffer); | |
} | |
void processSerialMessage() { | |
char c,c2; | |
byte i, temp, temp2; | |
int8_t paramNo, valueNo; | |
char OutputCache[13]; | |
// if time sync available from serial port, update time and return true | |
while(Serial.available() >= a5_COMM_MSG_LEN ){ // time message consists of a header and ten ascii digits | |
if( Serial.read() == a5_COMM_HEADER) { | |
c = Serial.read() ; | |
c2 = Serial.read(); | |
if( c == 'S' ) | |
{ | |
if (c2 == 'T') | |
{ // COMMAND: ST, SET TIME | |
time_t pctime = 0; | |
for( i=0; i < 10; 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 | |
DisplayWord ("SYNCD", 900); | |
DisplayWordDP("____2"); | |
Serial.println("PC Time Sync Signal Received."); | |
SerialPrintTime(); | |
if (UseRTC) | |
RTC.set(now()); | |
EndVCRmode(); | |
} | |
} | |
else if( c == 'B' ) | |
{ | |
if ((c2 == '0') || (c2 == 0)) // B0, with either ASCII or Binary 0. | |
{ // COMMAND: B0, Set Parameters | |
c = Serial.read(); // B0 command: Which setting to adjust | |
c2 = Serial.read(); // Read first char of additional data | |
if (c == '2') | |
{ | |
// edit font character | |
// c2 : Idicates which ASCII character location to edit | |
// Read in 8 more ASCII chars: | |
// [___][_][___] <- "A", "B", "C" values, ASCII text | |
i = 100 * (Serial.read() - '0'); | |
i += 10 * (Serial.read() - '0'); | |
i += (Serial.read() - '0'); | |
temp = (Serial.read() - '0'); | |
temp2 = 100 * (Serial.read() - '0'); | |
temp2 += 10 * (Serial.read() - '0'); | |
temp2 += (Serial.read() - '0'); | |
a5editFontChar(c2, i, temp, temp2); | |
Serial.read(); // Empty input buffer, char 10 of 10 | |
} | |
else{ | |
if (c == '0') | |
{ | |
// Set brightness | |
c = Serial.read(); // Read input buffer, char 3 of 10 | |
Brightness = (10 * (c2 - '0') + (c - '0')); | |
UpdateBrightness = 1; | |
} | |
if (c == '1') | |
{// Load altnernate number set | |
a5loadAltNumbers(c2 - '0'); | |
Serial.read(); // Empty input buffer, char 3 of 10 | |
} | |
for( i=3; i < 10; i++){ | |
Serial.read(); // Empty input buffer | |
} | |
} | |
RedrawNow = 1; | |
EndVCRmode(); | |
} | |
else { // Daisy chaining: With Bx, where x is less than 48 or x is less than 10: | |
if (c2 <= '9') | |
{ // if we're here, c2 is <= '9', c2 != 0, and c2 != '0'. | |
OutputCache[0] = 'B'; | |
OutputCache[1] = c2 - 1; | |
for( i=2; i < 12; i++){ | |
OutputCache[i] = Serial.read(); | |
} | |
SerialSendDataDaisyChain (OutputCache); | |
} | |
} | |
} | |
else if( c == 'A' ) | |
{ | |
if ((c2 == '0') || (c2 == 0)) // A0, with either ASCII or Binary 0. | |
{ // COMMAND: A0, DISPLAY ASCII DATA | |
// ASCII display mode, first 5 chars will be displayed, second 5: decimals | |
for( i=0; i < 10; i++){ | |
c = Serial.read(); | |
if (i < 5) | |
wordCache[i] = c; | |
else | |
dpCache[i - 5] = c; | |
} | |
modeShowText = 3; | |
RedrawNow = 1; | |
EndVCRmode(); | |
} | |
else { // Daisy chaining: With Ax, where x is less than 48 or x is less than 10: | |
if (c2 <= '9') | |
{ // if we're here, c2 is <= '9', c2 != 0, and c2 != '0'. | |
OutputCache[0] = 'A'; | |
OutputCache[1] = c2 - 1; | |
for( i=2; i < 12; i++){ | |
OutputCache[i] = Serial.read(); | |
} | |
SerialSendDataDaisyChain (OutputCache); | |
} | |
} | |
} | |
else if( c == 'M' ) // Mode setting commands | |
{// Eventually, it would be nice to have all settings and functions | |
// accessible through the remote interface. | |
if (c2 == 'T') { // Command: 'MT' : Mode: Time | |
modeShowAlarmTime = 0; | |
modeShowMenu = 0; | |
modeShowText = 0; | |
modeLEDTest = 0; | |
EndVCRmode(); | |
} | |
} | |
} | |
} | |
} | |
void updateNightLight(void) | |
{ | |
if (NightLightType == 4) | |
{ // "Sleep" mode | |
unsigned int temp = 0; | |
NightLightStep++; | |
if (NightLightStep <= 255) { | |
if (NightLightSign) | |
temp = NightLightStep; | |
else | |
temp = 255 - NightLightStep; | |
} | |
else | |
{ | |
if (NightLightSign) | |
temp = 255; | |
else | |
temp = 0; | |
if (NightLightStep > 280) | |
{ | |
NightLightStep = 0; | |
if (NightLightSign) | |
NightLightSign = 0; | |
else | |
NightLightSign = 1; | |
} | |
} | |
temp = (temp * temp) >> 8; | |
if (temp > 252) { | |
temp = 252; | |
} | |
temp += 3; | |
a5nightLight(temp); | |
} | |
else if (NightLightType == 0) | |
a5nightLight(0); // OFF | |
else if (NightLightType == 1) | |
a5nightLight(5); // LOW | |
else if (NightLightType == 2) | |
a5nightLight(50); // MED | |
else if (NightLightType == 3) | |
a5nightLight(255); // HIGH | |
} | |
void UpdateDisplay (byte forceUpdate) { | |
byte temp, remainder; | |
if (modeShowText) //Text Display | |
{ | |
if ((milliTemp >= DisplayWordEndTime) && (modeShowText == 1)) | |
{ | |
modeShowText = 0; | |
if (wordSequence) | |
DisplayWordSequence(wordSequence); | |
// If the word sequence is finished, return to clock display: | |
if (wordSequence == 0) | |
RedrawNow = 1; | |
} | |
else | |
{ | |
if(forceUpdate) | |
{ | |
a5clearOSB(); | |
a5loadOSB_Ascii(wordCache,a5_brightLevel); | |
a5loadOSB_DP(dpCache,a5_brightLevel); | |
a5BeginFadeToOSB(); | |
} | |
} | |
} | |
else if (modeLEDTest) //LED Test Mode | |
{ | |
if (milliTemp > DisplayWordEndTime) | |
{ | |
forceUpdate = 1; | |
SoundSequence++; | |
DisplayWordEndTime = milliTemp + 350; // Advance every 350 ms. | |
} | |
if(forceUpdate) | |
{ | |
// Borrow SoundSequence as a dummy variable: | |
if (SoundSequence > 91) | |
SoundSequence = 1; | |
remainder = SoundSequence - 1; | |
temp = 4; | |
while (remainder >= 18){ | |
remainder -= 18; // remainder | |
temp -= 1; // (4 - modulo) | |
} | |
byte map[] = { | |
7,0,1,10,11,3,2,12,13,14,15,16,5,17,8,9,4,6 | |
}; | |
a5clearOSB(); | |
a5_OSB[18 * temp + map[remainder]] = a5_brightLevel; | |
a5BeginFadeToOSB(); | |
RedrawNow = 1; | |
} | |
} | |
else if (modeShowMenu) | |
{ | |
DisplayWordDP("_____"); | |
byte ExtendTextDisplay = 0; | |
if (menuItem == AMPM24HRMenuItem) // Hour mode: 12Hr / 24 Hr | |
{ | |
if (optionValue != 0) | |
{ | |
if (HourMode24) | |
HourMode24 = 0; | |
else | |
HourMode24 = 1; | |
optionValue = 0; | |
} | |
if (HourMode24) | |
DisplayWord ("24 HR", 500); | |
else | |
DisplayWord ("AM/PM", 500); | |
ExtendTextDisplay = 1; | |
} | |
else if (menuItem == NightLightMenuItem) // Night Light | |
{ | |
NightLightType += optionValue; | |
if (NightLightType < 0) | |
NightLightType = 4; | |
if (NightLightType > 4) | |
NightLightType = 0; | |
if (optionValue != 0){ | |
if (NightLightType == 4) | |
{ | |
NightLightStep = 0; | |
NightLightSign = 1; | |
} | |
updateNightLight(); | |
} | |
optionValue = 0; | |
if (NightLightType == 0) | |
DisplayWord (" NONE", 500); | |
else if (NightLightType == 1) | |
DisplayWord (" LOW ", 500); | |
else if (NightLightType == 2) | |
DisplayWord (" MED ", 500); | |
else if (NightLightType == 3) | |
DisplayWord (" HIGH", 500); | |
else // (NightLightType == 4) | |
DisplayWord ("SLEEP", 500); | |
ExtendTextDisplay = 1; | |
} | |
else if (menuItem == AlarmToneMenuItem) // Alarm Tone: 2 | |
{ | |
AlarmTone += optionValue; | |
optionValue = 0; | |
if (AlarmTone < 0) | |
AlarmTone = 5; | |
if (AlarmTone > 5) | |
AlarmTone = 0; | |
if (AlarmTone == 0) | |
DisplayWord ("X LOW", 500); | |
else if (AlarmTone == 1) | |
DisplayWord (" LOW ", 500); | |
else if (AlarmTone == 2) | |
DisplayWord (" MED ", 500); | |
else if (AlarmTone == 3) | |
DisplayWord (" HIGH", 500); | |
else if (AlarmTone == 4) | |
DisplayWord ("SIREN", 500); | |
else | |
DisplayWord (" TINK", 500); | |
ExtendTextDisplay = 1; | |
} | |
else if (menuItem == SoundTestMenuItem) // Alarm Test: 3 | |
{ | |
DisplayWord (" +/- ", 500); | |
if (optionValue != 0) | |
{ | |
if (alarmNow == 0) | |
alarmNow = 1; | |
else | |
TurnOffAlarm(); | |
optionValue = 0; | |
} | |
ExtendTextDisplay = 1; | |
} | |
else if (menuItem == numberCharSetMenuItem) | |
{ | |
numberCharSet += optionValue; | |
if (optionValue != 0){ | |
optionValue = 0; | |
if (numberCharSet < 0) | |
numberCharSet = 9; | |
if (numberCharSet > 9) | |
numberCharSet = 0; | |
a5loadAltNumbers(numberCharSet); | |
} | |
DisplayWord ("01237", 500); // Sample font display | |
ExtendTextDisplay = 1; | |
} | |
else if (menuItem == DisplayStyleMenuItem) | |
{ | |
temp = (DisplayMode & 3U); | |
if (optionValue != 0){ | |
if (optionValue == 1) | |
temp = (temp + 1) & 3U; | |
else if (temp == 0) | |
temp = 3; | |
else | |
temp--; | |
DisplayMode = (DisplayMode & 12U) | (temp); | |
optionValue = 0; | |
forceUpdate = 1; | |
} | |
TimeDisplay(DisplayMode & 3, forceUpdate); // Show clock time, in appropriate style | |
} | |
else if (menuItem == AltModeMenuItem) // Alternate with seconds or date: | |
{ | |
// if (TimeDisplay & 4): Alternate date with time | |
// if (TimeDisplay & 8): Alternate date with seconds | |
// if (TimeDisplay & 16): Alternate date with words | |
if (optionValue != 0) | |
{ | |
temp = 1; | |
if ( DisplayMode & 4) | |
temp = 2; | |
if ( DisplayMode & 8) | |
temp = 3; | |
if ( DisplayMode & 16) | |
temp = 4; | |
temp += optionValue; | |
if (temp == 0) | |
temp = 4; // Wrap around (low side) | |
else if (temp == 5) | |
temp = 0; // wrap around (high side) | |
DisplayMode &= 3U; | |
if (temp > 1) | |
DisplayMode |= (1 << temp); | |
// if temp is 0 or 1, display time only. | |
DisplayModePhaseCount = 0; | |
optionValue = 0; | |
} | |
if (DisplayMode & 4U) | |
DisplayWord ("DATE ", 500); | |
else if (DisplayMode & 8U){ | |
DisplayWord ("SECS ", 500); | |
DisplayWordDP("___1_"); | |
} | |
else if (DisplayMode & 16U){ | |
DisplayWord ("WORDS", 500); | |
} | |
else | |
DisplayWord (" NONE", 500); | |
ExtendTextDisplay = 1; | |
} | |
else if (menuItem == SetYearMenuItem) | |
{ | |
if (optionValue != 0){ | |
AdjDayMonthYear(0,0,optionValue); // Day, Month, Year | |
optionValue = 0; | |
forceUpdate = 1; | |
} | |
TimeDisplay(35, forceUpdate); // Show clock time, in appropriate style | |
} | |
else if (menuItem == SetMonthMenuItem) | |
{ | |
if (optionValue != 0){ | |
AdjDayMonthYear(0,optionValue,0); // Day, Month, Year | |
optionValue = 0; | |
forceUpdate = 1; | |
} | |
TimeDisplay(33, forceUpdate); // Show clock time, in appropriate style | |
} | |
else if (menuItem == SetDayMenuItem) | |
{ | |
if (optionValue != 0){ | |
AdjDayMonthYear(optionValue,0,0); // Day, Month, Year | |
optionValue = 0; | |
forceUpdate = 1; | |
} | |
TimeDisplay(33, forceUpdate); // Show clock time, in appropriate style | |
} | |
else if (menuItem == SetSecondsMenuItem) | |
{ | |
if (optionValue != 0){ | |
adjustTime(optionValue); // Adjust by +/- 1 second | |
if (UseRTC) | |
RTC.set(now()); | |
optionValue = 0; | |
forceUpdate = 1; | |
} | |
TimeDisplay(32, forceUpdate); // Show clock time, seconds | |
} | |
if(forceUpdate && ExtendTextDisplay) | |
{ | |
if (menuItem != DisplayStyleMenuItem) | |
{ | |
a5clearOSB(); | |
a5loadOSB_Ascii(wordCache,a5_brightLevel); | |
a5loadOSB_DP(dpCache,a5_brightLevel); | |
a5BeginFadeToOSB(); | |
} | |
} | |
} | |
else if (modeShowDateViaButtons) | |
{ | |
TimeDisplay(33, forceUpdate); // Show date | |
} | |
else if (modeShowAlarmTime) | |
{ | |
TimeDisplay(20, forceUpdate); // Show alarm time | |
} | |
else | |
{ | |
// Time Display Mode! Possibly with aux. display. | |
if ((DisplayMode > 3) && (DisplayMode < 32)) | |
{ | |
if (buttonMonitor) | |
{ | |
// Do not use alternate display modes when buttons are pressed. | |
DisplayModePhase = 0; | |
DisplayModePhaseCount = 0; | |
} | |
else | |
if (DisplayModePhaseCount >= 7) // Alternate display every 7 seconds | |
{ | |
DisplayModePhaseCount = 0; | |
DisplayModePhase++; | |
if (DisplayModePhase > 1) | |
DisplayModePhase = 0; | |
forceUpdate = 1; | |
DisplayWord (" ", 400); // Blank out between display phases | |
if (AlarmEnabled) | |
DisplayWordDP("2____"); | |
else | |
DisplayWordDP("_____"); | |
} | |
if (DisplayModePhase == 0) | |
{ | |
TimeDisplay(DisplayMode & 3, forceUpdate); // "Normal" time display | |
} | |
else | |
{ // Alternate display modes: "Time and ... " | |
if (DisplayMode & 4) | |
TimeDisplay(33, forceUpdate); // if Bit 4 is set: Show date | |
else if (DisplayMode & 8) | |
TimeDisplay(32, forceUpdate); // if Bit 8 is set: Show seconds | |
else if (DisplayMode & 16) | |
TimeDisplay(36, forceUpdate); // if Bit 16 is set: Show five letter words | |
} | |
} | |
else | |
TimeDisplay(DisplayMode, forceUpdate); | |
} | |
} | |
void AdjDayMonthYear (int8_t AdjDay, int8_t AdjMonth, int8_t AdjYear) | |
{ | |
// From Time library: API starts months from 1, this array starts from 0 | |
const uint8_t monthDays[]={31,28,31,30,31,30,31,31,30,31,30,31}; | |
time_t timeTemp = now(); | |
int yrTemp = year(timeTemp) + (int) AdjYear; | |
int moTemp = month(timeTemp) + AdjMonth; // Avoid changing year, unless requested | |
if (moTemp < 1) | |
moTemp = 12; | |
if (moTemp > 12) | |
moTemp = 1; | |
int dayTemp = day(timeTemp) + AdjDay; // avoid changing month, unless requested | |
if (dayTemp < 1) | |
dayTemp = monthDays[moTemp - 1]; | |
if (dayTemp > monthDays[moTemp - 1]) | |
if (AdjDay > 0) | |
{ // Roll over day-of-month to 1, if explicitly requesting increase in date. | |
dayTemp = 1; | |
} | |
else | |
{ // Otherwise, we should "truncate" the date to last day of month. | |
dayTemp = monthDays[moTemp - 1]; | |
} | |
setTime(hour(timeTemp),minute(timeTemp),second(timeTemp), | |
dayTemp, moTemp, yrTemp); | |
if (UseRTC) | |
RTC.set(now()); | |
} | |
void TimeDisplay (byte DisplayModeLocal, byte forceUpdateCopy) { | |
byte temp; | |
char units; | |
char WordIn[] = { | |
" " }; | |
byte SecNowTens, SecNowOnes; | |
byte SecNow; | |
SecNow = second(); | |
if (SecLast != SecNow){ | |
forceUpdateCopy = 1; | |
DisplayModePhaseCount++; | |
} | |
if ((DisplayModeLocal <= 4) || (DisplayModeLocal == 20)) | |
{ // Normal time display OR Alarm time display | |
// DisplayModeLocal 0: Standard-mode time-of-day display | |
// DisplayModeLocal 1: Time-of-day w/ seconds spinner | |
// DisplayModeLocal 2: Standard-mode time-of-day display + flashing separator | |
// DisplayModeLocal 3: Time-of-day w/ seconds spinner + flashing separator | |
// DisplayModeLocal 20: Standard-mode alarm-time display | |
byte HrNowTens, HrNowOnes, MinNowTens, MinNowOnes; | |
if (DisplayModeLocal == 20) | |
temp = AlarmTimeHr; | |
else | |
temp = (hour() + is_dst(now())) % 24; | |
//temp = hour(); | |
if (HourMode24){ | |
if(second() % 10 > 5){ | |
units = 'L'; // local time 24 hours | |
} | |
else{ | |
temp = (hour() - GMT_OFFSET) % 24; | |
units = 'Z'; // local time 24 hours | |
} | |
} | |
else | |
{ | |
units = 'A'; | |
if (temp >= 12){ | |
units = 'P'; | |
} | |
if (temp > 12){ | |
temp -= 12; // | |
} | |
if (temp == 0) // Represent 00:00 as 12:00 | |
temp += 12; | |
} | |
HrNowTens = U8DIVBY10(temp); //i.e., HrNowTens = temp / 10; | |
HrNowOnes = temp - 10 * HrNowTens; | |
if (DisplayModeLocal == 20) | |
temp = AlarmTimeMin; | |
else | |
temp = minute(); | |
MinNowTens = U8DIVBY10(temp); //i.e., MinNowTens = temp / 10; | |
MinNowOnes = temp - 10 * MinNowTens; | |
if (MinNowOnesLast != MinNowOnes) | |
forceUpdateCopy = 1; | |
SecNow = second(); | |
if (SecLast != SecNow) | |
forceUpdateCopy = 1; | |
if (DisplayModeLocal & 1) // Seconds Spinner Mode | |
{ | |
// binary tree for 8 cases: three tests max, rather than 8. | |
// Split seconds into octants: 0-6,7-14,15-22,23-29,30-36,37-44,45-52,53-59 | |
if (SecNow < 30) | |
{// temp in range 0-29 | |
if (SecNow < 15) | |
{// temp in range 0-14 | |
if (SecNow < 7) | |
{ // temp in range 0-6 | |
temp = 15; // a5editFontChar('a',0,0,32); // N arrow | |
} | |
else | |
{ // temp in range 7-14 | |
temp = 16; // a5editFontChar('a',0,0,64); // NE arrow | |
} | |
} | |
else | |
{// temp in range 15-29 | |
if (SecNow < 23) | |
{ // temp in range 15-22 | |
temp = 5; // a5editFontChar('a',32,0,0); // E arrow | |
} | |
else | |
{ // temp in range 23-29 | |
temp = 17; // a5editFontChar('a',0,0,128); // SE arrow | |
} | |
} | |
} | |
else | |
{// temp in range 30-59 | |
if (SecNow < 45) | |
{// temp in range 30-44 | |
if (SecNow < 37) | |
{ // temp in range 30-36 | |
temp = 8; // a5editFontChar('a',0,1,0); // S arrow | |
} | |
else | |
{ // temp in range 37-44 | |
temp = 9; // a5editFontChar('a',0,2,0); // SW arrow | |
} | |
} | |
else | |
{// temp in range 45-59 | |
if (SecNow < 53) | |
{ // temp in range 45-52 | |
temp = 4; // a5editFontChar('a',16,0,0); // W arrow | |
} | |
else | |
{ // temp in range 53-59 | |
temp = 14; // a5editFontChar('a',0,0,16); // NW arrow | |
} | |
} | |
} | |
} | |
if ((HourMode24) || (HrNowTens > 0)) | |
WordIn[0] = HrNowTens + a5_integerOffset; // Blank leading zero unless in 24-hour mode. | |
WordIn[1] = HrNowOnes + a5_integerOffset; | |
WordIn[2] = MinNowTens + a5_integerOffset; | |
WordIn[3] = MinNowOnes + a5_integerOffset; | |
if (DisplayModeLocal & 1) // Spinner | |
WordIn[4] = ' '; | |
else | |
WordIn[4] = units; | |
if(forceUpdateCopy) | |
{ | |
a5clearOSB(); | |
a5loadOSB_Ascii(WordIn,a5_brightLevel); | |
if (DisplayModeLocal & 1) | |
{ | |
a5loadOSB_Segment (temp, a5_brightLevel); | |
if (units == 'P') | |
a5loadOSB_DP("___1_",a5_brightLevel); // DP dot in DisplayMode 1. | |
} | |
if (AlarmEnabled) | |
a5loadOSB_DP("2____",a5_brightLevel); | |
if ((DisplayModeLocal < 20) && (DisplayModeLocal & 2) && (SecNow & 1)){ | |
// no HOUR:MINUTE separators | |
} | |
else | |
a5loadOSB_DP("01200",a5_brightLevel); | |
a5BeginFadeToOSB(); | |
} | |
MinNowOnesLast = MinNowOnes; | |
} | |
else if (DisplayModeLocal == 32) //Seconds only | |
{ | |
temp = SecNow; | |
SecNowTens = U8DIVBY10(temp); //i.e., SecNowTens = temp / 10; | |
SecNowOnes = temp - 10 * SecNowTens; | |
WordIn[2] = SecNowTens + a5_integerOffset; | |
WordIn[3] = SecNowOnes + a5_integerOffset; | |
if(forceUpdateCopy) | |
{ | |
a5clearOSB(); | |
a5loadOSB_Ascii(WordIn,a5_brightLevel); | |
if (AlarmEnabled) | |
a5loadOSB_DP("21200",a5_brightLevel); | |
else | |
a5loadOSB_DP("01200",a5_brightLevel); | |
a5BeginFadeToOSB(); | |
} | |
SecLast = SecNow; | |
} | |
else if (DisplayModeLocal == 33) //Month, Day | |
{ | |
if(forceUpdateCopy) | |
{ | |
temp = day(); | |
byte monthTemp = 3 * ( month() - 1); | |
//Month name (short): | |
// char a5monthShortNames_P[] PROGMEM = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; | |
WordIn[0] = pgm_read_byte(&(a5_monthShortNames_P[monthTemp++])); | |
WordIn[1] = pgm_read_byte(&(a5_monthShortNames_P[monthTemp++])); | |
WordIn[2] = pgm_read_byte(&(a5_monthShortNames_P[monthTemp])); | |
byte divtemp = U8DIVBY10(temp); //i.e., divtemp = day / 10; | |
WordIn[3] = divtemp + a5_integerOffset; | |
WordIn[4] = ( temp - 10 * divtemp) + a5_integerOffset; | |
a5clearOSB(); | |
a5loadOSB_Ascii(WordIn,a5_brightLevel); | |
if (AlarmEnabled) | |
a5loadOSB_DP("20100",a5_brightLevel); | |
else | |
a5loadOSB_DP("00100",a5_brightLevel); | |
a5BeginFadeToOSB(); | |
} | |
SecLast = SecNow; | |
} | |
else if (DisplayModeLocal == 35) //Year | |
{ | |
unsigned int yeartemp = year(); | |
unsigned int divtemp = U16DIVBY10(yeartemp); //i.e., divtemp = yeartemp / 10; | |
WordIn[4] = yeartemp - 10 * divtemp + a5_integerOffset; | |
yeartemp = U16DIVBY10(divtemp); | |
WordIn[3] = divtemp - 10 * yeartemp + a5_integerOffset; | |
divtemp = U16DIVBY10(yeartemp); | |
WordIn[2] = yeartemp - 10 * divtemp + a5_integerOffset; | |
yeartemp = U16DIVBY10(divtemp); | |
WordIn[1] = divtemp - 10 * yeartemp + a5_integerOffset; | |
if(forceUpdateCopy) | |
{ | |
a5clearOSB(); | |
a5loadOSB_Ascii(WordIn,a5_brightLevel); | |
if (AlarmEnabled) | |
a5loadOSB_DP("20000",a5_brightLevel); | |
else | |
a5loadOSB_DP("00000",a5_brightLevel); | |
a5BeginFadeToOSB(); | |
} | |
} | |
else if (DisplayModeLocal == 36) //FLW - FIVE LETTER WORD mode | |
{ | |
if(forceUpdateCopy) | |
{ | |
if (DisplayModeLocalLast != 36) | |
{ // Pick new display word, but only when first entering mode 36. | |
// Uncomment exactly one of the following two lines: | |
FLWoffset = random(fiveLetterWordsMax); // Random word order! | |
// FLWoffset += 1; // Alphebetical word order! | |
} | |
if (FLWoffset >= fiveLetterWordsMax) | |
FLWoffset = 0; | |
unsigned int index = 4 * FLWoffset; | |
WordIn[1] = pgm_read_byte(&(fiveLetterWords[index++])); | |
WordIn[2] = pgm_read_byte(&(fiveLetterWords[index++])); | |
WordIn[3] = pgm_read_byte(&(fiveLetterWords[index++])); | |
WordIn[4] = pgm_read_byte(&(fiveLetterWords[index])); | |
temp = 0; | |
while (temp < 25){ | |
index = pgm_read_word(&(fiveLetterPosArray[temp])); | |
if (FLWoffset < index){ | |
WordIn[0] = 'A' + temp; | |
temp = 50; | |
} | |
temp++; | |
} | |
if (temp < 50) | |
WordIn[0] = 'Z'; | |
a5clearOSB(); | |
a5loadOSB_Ascii(WordIn,a5_brightLevel); | |
if (AlarmEnabled) | |
a5loadOSB_DP("20000",a5_brightLevel); | |
else | |
a5loadOSB_DP("00000",a5_brightLevel); | |
a5BeginFadeToOSB(); | |
} | |
} | |
DisplayModeLocalLast = DisplayModeLocal; | |
SecLast = SecNow; | |
} | |
void SerialPrintTime(){ | |
// Print time over serial interface. Adapted from Time library. | |
time_t timeTmp = now(); | |
Serial.print(hour(timeTmp)); | |
printDigits(minute(timeTmp)); | |
printDigits(second(timeTmp)); | |
Serial.print(" "); | |
Serial.print(dayStr(weekday(timeTmp))); | |
Serial.print(" "); | |
Serial.print(day(timeTmp)); | |
Serial.print(" "); | |
Serial.print(monthShortStr(month(timeTmp))); | |
Serial.print(" "); | |
Serial.print(year(timeTmp)); | |
Serial.println(); | |
} | |
void printDigits(int digits){ | |
// utility function for digital clock serial output: prints preceding colon and leading 0 | |
// borrowed from Time library. | |
Serial.print(":"); | |
if(digits < 10) | |
Serial.print('0'); | |
Serial.print(digits); | |
} | |
void ApplyDefaults (void) { | |
// VARIABLES THAT HAVE EEPROM STORAGE AND DEFAULTS... | |
a5_brightLevel = a5brightLevelDefault; | |
HourMode24 = a5HourMode24Default; | |
AlarmEnabled = a5AlarmEnabledDefault; | |
AlarmTimeHr = a5AlarmHrDefault; | |
AlarmTimeMin = a5AlarmMinDefault; | |
AlarmTone = a5AlarmToneDefault; | |
NightLightType = a5NightLightTypeDefault; | |
numberCharSet = a5NumberCharSetDefault; | |
} | |
void EEReadSettings (void) { | |
// Check values for sanity at THIS stage. | |
byte value = 255; | |
value = EEPROM.read(0); | |
if ((value > 100 + BrightnessMax) || (value < 100)) | |
Brightness = a5brightLevelDefault; | |
else | |
Brightness = value - 100; | |
value = EEPROM.read(1); | |
if (value > 1) | |
HourMode24 = a5HourMode24Default; | |
else | |
HourMode24 = value; | |
value = EEPROM.read(2); | |
if (value > 1) | |
AlarmEnabled = a5AlarmEnabledDefault; | |
else | |
AlarmEnabled = value; | |
value = EEPROM.read(3); | |
if ((value > 123) || (value < 100)) | |
AlarmTimeHr = a5AlarmHrDefault; | |
else | |
AlarmTimeHr = value - 100; | |
value = EEPROM.read(4); | |
if ((value > 159) || (value < 100)) | |
AlarmTimeMin = a5AlarmMinDefault; | |
else | |
AlarmTimeMin = value - 100; | |
value = EEPROM.read(5); | |
if (value > 5) | |
AlarmTone = a5AlarmToneDefault; | |
else | |
AlarmTone = value; | |
value = EEPROM.read(6); | |
if (value > 4) | |
NightLightType = a5NightLightTypeDefault; | |
else | |
NightLightType = value; | |
value = EEPROM.read(7); | |
if (value > 9) | |
{ | |
numberCharSet = a5NumberCharSetDefault; | |
} | |
else | |
numberCharSet = value; | |
value = EEPROM.read(8); | |
if (value > 31) | |
{ | |
DisplayMode = a5DisplayModeDefault; | |
} | |
else | |
DisplayMode = value; | |
} | |
void EESaveSettings (void){ | |
// If > 4 seconds since last button press, and | |
// we suspect that we need to change the stored settings: | |
byte value; | |
byte indicateEEPROMwritten = 0; | |
if (milliTemp >= (LastButtonPress + 4000)) | |
{ | |
// Careful if you use this function: EEPROM has a limited number of write | |
// cycles in its life. Good for human-operated buttons, bad for automation. | |
// Also, no error checking is provided at this, the write EEPROM stage. | |
value = EEPROM.read(0); | |
if (Brightness != (value - 100)) { | |
a5writeEEPROM(0, Brightness + 100); | |
//NOTE: Do not blink LEDs off to indicate saving of this value | |
} | |
value = EEPROM.read(1); | |
if (HourMode24 != value) { | |
a5writeEEPROM(1, HourMode24); | |
indicateEEPROMwritten = 1; | |
} | |
value = EEPROM.read(2); | |
if (AlarmEnabled != value) { | |
a5writeEEPROM(2, AlarmEnabled); | |
//NOTE: Do not blink LEDs off to indicate saving of this value | |
} | |
value = EEPROM.read(3); | |
if (AlarmTimeHr != (value - 100)) { | |
a5writeEEPROM(3, AlarmTimeHr + 100); | |
//NOTE: Do not blink LEDs off to indicate saving of this value | |
} | |
value = EEPROM.read(4); | |
if (AlarmTimeMin != (value - 100)){ | |
a5writeEEPROM(4, AlarmTimeMin + 100); | |
//NOTE: Do not blink LEDs off to indicate saving of this value | |
} | |
value = EEPROM.read(5); | |
if (AlarmTone != value){ | |
a5writeEEPROM(5, AlarmTone); | |
indicateEEPROMwritten = 1; | |
} | |
value = EEPROM.read(6); | |
if (NightLightType != value){ | |
a5writeEEPROM(6, NightLightType); | |
indicateEEPROMwritten = 1; | |
} | |
value = EEPROM.read(7); | |
if (numberCharSet != value){ | |
a5writeEEPROM(7, numberCharSet); | |
indicateEEPROMwritten = 1; | |
} | |
value = EEPROM.read(8); | |
if (DisplayMode != value){ | |
a5writeEEPROM(8, DisplayMode); | |
indicateEEPROMwritten = 1; | |
} | |
if (indicateEEPROMwritten) { // Blink LEDs off to indicate when we're writing to the EEPROM | |
DisplayWord (" ", 100); | |
} | |
UpdateEE = 0; | |
if (UseRTC) | |
RTC.set(now()); // Update time at RTC, in case time was changed in settings menu | |
} | |
} | |
#ifdef USE_EURO_DST | |
PROGMEM const prog_uint32_t DST[] = { | |
// start, stop, // | |
954050400, 972799200, // 2000-03-26 01:00:00 -- 2000-10-29 01:00:00 | |
985500000, 1004248800, // 2001-03-25 01:00:00 -- 2001-10-28 01:00:00 | |
1017554400, 1035698400, // 2002-03-31 01:00:00 -- 2002-10-27 01:00:00 | |
1049004000, 1067148000, // 2003-03-30 01:00:00 -- 2003-10-26 01:00:00 | |
1080453600, 1099202400, // 2004-03-28 01:00:00 -- 2004-10-31 01:00:00 | |
1111903200, 1130652000, // 2005-03-27 01:00:00 -- 2005-10-30 01:00:00 | |
1143352800, 1162101600, // 2006-03-26 01:00:00 -- 2006-10-29 01:00:00 | |
1174798800, 1193547600, // 2007-03-25 01:00:00 -- 2007-10-28 01:00:00 | |
1206853200, 1224997200, // 2008-03-30 01:00:00 -- 2008-10-26 01:00:00 | |
1238302800, 1256446800, // 2009-03-29 01:00:00 -- 2009-10-25 01:00:00 | |
1269752400, 1288501200, // 2010-03-28 01:00:00 -- 2010-10-31 01:00:00 | |
1301202000, 1319950800, // 2011-03-27 01:00:00 -- 2011-10-30 01:00:00 | |
1332651600, 1351400400, // 2012-03-25 01:00:00 -- 2012-10-28 01:00:00 | |
1364706000, 1382850000, // 2013-03-31 01:00:00 -- 2013-10-27 01:00:00 | |
1396155600, 1414299600, // 2014-03-30 01:00:00 -- 2014-10-26 01:00:00 | |
1427605200, 1445749200, // 2015-03-29 01:00:00 -- 2015-10-25 01:00:00 | |
1459054800, 1477803600, // 2016-03-27 01:00:00 -- 2016-10-30 01:00:00 | |
1490504400, 1509253200, // 2017-03-26 01:00:00 -- 2017-10-29 01:00:00 | |
1521954000, 1540702800, // 2018-03-25 01:00:00 -- 2018-10-28 01:00:00 | |
1554008400, 1572152400, // 2019-03-31 01:00:00 -- 2019-10-27 01:00:00 | |
1585458000, 1603602000, // 2020-03-29 01:00:00 -- 2020-10-25 01:00:00 | |
1616907600, 1635656400, // 2021-03-28 01:00:00 -- 2021-10-31 01:00:00 | |
1648357200, 1667106000, // 2022-03-27 01:00:00 -- 2022-10-30 01:00:00 | |
1679806800, 1698555600, // 2023-03-26 01:00:00 -- 2023-10-29 01:00:00 | |
1711861200, 1730005200, // 2024-03-31 01:00:00 -- 2024-10-27 01:00:00 | |
1743310800, 1761454800, // 2025-03-30 01:00:00 -- 2025-10-26 01:00:00 | |
1774760400, 1792904400, // 2026-03-29 01:00:00 -- 2026-10-25 01:00:00 | |
1806210000, 1824958800, // 2027-03-28 01:00:00 -- 2027-10-31 01:00:00 | |
1837659600, 1856408400, // 2028-03-26 01:00:00 -- 2028-10-29 01:00:00 | |
1869109200, 1887858000, // 2029-03-25 01:00:00 -- 2029-10-28 01:00:00 | |
1901163600, 1919307600, // 2030-03-31 01:00:00 -- 2030-10-27 01:00:00 | |
1932613200, 1950757200, // 2031-03-30 01:00:00 -- 2031-10-26 01:00:00 | |
1964062800, 1982811600, // 2032-03-28 01:00:00 -- 2032-10-31 01:00:00 | |
1995512400, 2014261200, // 2033-03-27 01:00:00 -- 2033-10-30 01:00:00 | |
2026962000, 2045710800, // 2034-03-26 01:00:00 -- 2034-10-29 01:00:00 | |
2058411600, 2077160400, // 2035-03-25 01:00:00 -- 2035-10-28 01:00:00 | |
2090466000, 2108610000, // 2036-03-30 01:00:00 -- 2036-10-26 01:00:00 | |
2121915600, 2140059600, // 2037-03-29 01:00:00 -- 2037-10-25 01:00:00 | |
2153365200, 2172114000, // 2038-03-28 01:00:00 -- 2038-10-31 01:00:00 | |
2184814800, 2203563600, // 2039-03-27 01:00:00 -- 2039-10-30 01:00:00 | |
2216264400, 2235013200, // 2040-03-25 01:00:00 -- 2040-10-28 01:00:00 | |
2248318800, 2266462800, // 2041-03-31 01:00:00 -- 2041-10-27 01:00:00 | |
2279768400, 2297912400, // 2042-03-30 01:00:00 -- 2042-10-26 01:00:00 | |
2311218000, 2329362000, // 2043-03-29 01:00:00 -- 2043-10-25 01:00:00 | |
2342667600, 2361416400, // 2044-03-27 01:00:00 -- 2044-10-30 01:00:00 | |
2374117200, 2392866000, // 2045-03-26 01:00:00 -- 2045-10-29 01:00:00 | |
2405566800, 2424315600, // 2046-03-25 01:00:00 -- 2046-10-28 01:00:00 | |
2437621200, 2455765200, // 2047-03-31 01:00:00 -- 2047-10-27 01:00:00 | |
2469070800, 2487214800, // 2048-03-29 01:00:00 -- 2048-10-25 01:00:00 | |
2500520400, 2519269200, // 2049-03-28 01:00:00 -- 2049-10-31 01:00:00 | |
2531970000, 2550718800, // 2050-03-27 01:00:00 -- 2050-10-30 01:00:00 | |
2563419600, 2582168400, // 2051-03-26 01:00:00 -- 2051-10-29 01:00:00 | |
2595474000, 2613618000, // 2052-03-31 01:00:00 -- 2052-10-27 01:00:00 | |
2626923600, 2645067600, // 2053-03-30 01:00:00 -- 2053-10-26 01:00:00 | |
2658373200, 2676517200, // 2054-03-29 01:00:00 -- 2054-10-25 01:00:00 | |
2689822800, 2708571600, // 2055-03-28 01:00:00 -- 2055-10-31 01:00:00 | |
2721272400, 2740021200, // 2056-03-26 01:00:00 -- 2056-10-29 01:00:00 | |
2752722000, 2771470800, // 2057-03-25 01:00:00 -- 2057-10-28 01:00:00 | |
2784776400, 2802920400, // 2058-03-31 01:00:00 -- 2058-10-27 01:00:00 | |
2816226000, 2834370000, // 2059-03-30 01:00:00 -- 2059-10-26 01:00:00 | |
2847675600, 2866424400, // 2060-03-28 01:00:00 -- 2060-10-31 01:00:00 | |
2879125200, 2897874000, // 2061-03-27 01:00:00 -- 2061-10-30 01:00:00 | |
2910574800, 2929323600, // 2062-03-26 01:00:00 -- 2062-10-29 01:00:00 | |
2942024400, 2960773200, // 2063-03-25 01:00:00 -- 2063-10-28 01:00:00 | |
2974078800, 2992222800, // 2064-03-30 01:00:00 -- 2064-10-26 01:00:00 | |
3005528400, 3023672400, // 2065-03-29 01:00:00 -- 2065-10-25 01:00:00 | |
3036978000, 3055726800, // 2066-03-28 01:00:00 -- 2066-10-31 01:00:00 | |
3068427600, 3087176400, // 2067-03-27 01:00:00 -- 2067-10-30 01:00:00 | |
3099877200, 3118626000, // 2068-03-25 01:00:00 -- 2068-10-28 01:00:00 | |
3131931600, 3150075600, // 2069-03-31 01:00:00 -- 2069-10-27 01:00:00 | |
3163381200, 3181525200, // 2070-03-30 01:00:00 -- 2070-10-26 01:00:00 | |
3194830800, 3212974800, // 2071-03-29 01:00:00 -- 2071-10-25 01:00:00 | |
3226280400, 3245029200, // 2072-03-27 01:00:00 -- 2072-10-30 01:00:00 | |
3257730000, 3276478800, // 2073-03-26 01:00:00 -- 2073-10-29 01:00:00 | |
3289179600, 3307928400, // 2074-03-25 01:00:00 -- 2074-10-28 01:00:00 | |
3321234000, 3339378000, // 2075-03-31 01:00:00 -- 2075-10-27 01:00:00 | |
3352683600, 3370827600, // 2076-03-29 01:00:00 -- 2076-10-25 01:00:00 | |
3384133200, 3402882000, // 2077-03-28 01:00:00 -- 2077-10-31 01:00:00 | |
3415582800, 3434331600, // 2078-03-27 01:00:00 -- 2078-10-30 01:00:00 | |
3447032400, 3465781200, // 2079-03-26 01:00:00 -- 2079-10-29 01:00:00 | |
3479086800, 3497230800, // 2080-03-31 01:00:00 -- 2080-10-27 01:00:00 | |
3510536400, 3528680400, // 2081-03-30 01:00:00 -- 2081-10-26 01:00:00 | |
3541986000, 3560130000, // 2082-03-29 01:00:00 -- 2082-10-25 01:00:00 | |
3573435600, 3592184400, // 2083-03-28 01:00:00 -- 2083-10-31 01:00:00 | |
3604885200, 3623634000, // 2084-03-26 01:00:00 -- 2084-10-29 01:00:00 | |
3636334800, 3655083600, // 2085-03-25 01:00:00 -- 2085-10-28 01:00:00 | |
3668389200, 3686533200, // 2086-03-31 01:00:00 -- 2086-10-27 01:00:00 | |
3699838800, 3717982800, // 2087-03-30 01:00:00 -- 2087-10-26 01:00:00 | |
3731288400, 3750037200, // 2088-03-28 01:00:00 -- 2088-10-31 01:00:00 | |
3762738000, 3781486800, // 2089-03-27 01:00:00 -- 2089-10-30 01:00:00 | |
3794187600, 3812936400, // 2090-03-26 01:00:00 -- 2090-10-29 01:00:00 | |
3825637200, 3844386000, // 2091-03-25 01:00:00 -- 2091-10-28 01:00:00 | |
3857691600, 3875835600, // 2092-03-30 01:00:00 -- 2092-10-26 01:00:00 | |
3889141200, 3907285200, // 2093-03-29 01:00:00 -- 2093-10-25 01:00:00 | |
3920590800, 3939339600, // 2094-03-28 01:00:00 -- 2094-10-31 01:00:00 | |
3952040400, 3970789200, // 2095-03-27 01:00:00 -- 2095-10-30 01:00:00 | |
3983490000, 4002238800, // 2096-03-25 01:00:00 -- 2096-10-28 01:00:00 | |
4015544400, 4033688400, // 2097-03-31 01:00:00 -- 2097-10-27 01:00:00 | |
4046994000, 4065138000 // 2098-03-30 01:00:00 -- 2098-10-26 01:00:00 | |
}; | |
#endif | |
#ifdef USE_USA_DST | |
PROGMEM const uint32_t DST[] = { | |
// start, stop, // year | |
952840800, 973404000, // 2000 | |
984290400, 1004853600, // 2001 | |
1015740000, 1036303200, // 2002 | |
1047189600, 1067752800, // 2003 | |
1079244000, 1099807200, // 2004 | |
1110693600, 1131256800, // 2005 | |
1142143200, 1162706400, // 2006 | |
1173592800, 1194156000, // 2007 | |
1205042400, 1225605600, // 2008 | |
1236492000, 1257055200, // 2009 | |
1268546400, 1289109600, // 2010 | |
1299996000, 1320559200, // 2011 | |
1331445600, 1352008800, // 2012 | |
1362895200, 1383458400, // 2013 | |
1394344800, 1414908000, // 2014 | |
1425794400, 1446357600, // 2015 | |
1457848800, 1478412000, // 2016 | |
1489298400, 1509861600, // 2017 | |
1520748000, 1541311200, // 2018 | |
1552197600, 1572760800, // 2019 | |
1583647200, 1604210400, // 2020 | |
1615701600, 1636264800, // 2021 | |
1647151200, 1667714400, // 2022 | |
1678600800, 1699164000, // 2023 | |
1710050400, 1730613600, // 2024 | |
1741500000, 1762063200, // 2025 | |
1772949600, 1793512800, // 2026 | |
1805004000, 1825567200, // 2027 | |
1836453600, 1857016800, // 2028 | |
1867903200, 1888466400, // 2029 | |
1899352800, 1919916000, // 2030 | |
1930802400, 1951365600, // 2031 | |
1962856800, 1983420000, // 2032 | |
1994306400, 2014869600, // 2033 | |
2025756000, 2046319200, // 2034 | |
2057205600, 2077768800, // 2035 | |
2088655200, 2109218400, // 2036 | |
2120104800, 2140668000, // 2037 | |
2152159200, 2172722400, // 2038 | |
2183608800, 2204172000, // 2039 | |
2215058400, 2235621600, // 2040 | |
2246508000, 2267071200, // 2041 | |
2277957600, 2298520800, // 2042 | |
2309407200, 2329970400, // 2043 | |
2341461600, 2362024800, // 2044 | |
2372911200, 2393474400, // 2045 | |
2404360800, 2424924000, // 2046 | |
2435810400, 2456373600, // 2047 | |
2467260000, 2487823200, // 2048 | |
2499314400, 2519877600, // 2049 | |
2530764000, 2551327200, // 2050 | |
2562213600, 2582776800, // 2051 | |
2593663200, 2614226400, // 2052 | |
2625112800, 2645676000, // 2053 | |
2656562400, 2677125600, // 2054 | |
2688616800, 2709180000, // 2055 | |
2720066400, 2740629600, // 2056 | |
2751516000, 2772079200, // 2057 | |
2782965600, 2803528800, // 2058 | |
2814415200, 2834978400, // 2059 | |
2846469600, 2867032800, // 2060 | |
2877919200, 2898482400, // 2061 | |
2909368800, 2929932000, // 2062 | |
2940818400, 2961381600, // 2063 | |
2972268000, 2992831200, // 2064 | |
3003717600, 3024280800, // 2065 | |
3035772000, 3056335200, // 2066 | |
3067221600, 3087784800, // 2067 | |
3098671200, 3119234400, // 2068 | |
3130120800, 3150684000, // 2069 | |
3161570400, 3182133600, // 2070 | |
3193020000, 3213583200, // 2071 | |
3225074400, 3245637600, // 2072 | |
3256524000, 3277087200, // 2073 | |
3287973600, 3308536800, // 2074 | |
3319423200, 3339986400, // 2075 | |
3350872800, 3371436000, // 2076 | |
3382927200, 3403490400, // 2077 | |
3414376800, 3434940000, // 2078 | |
3445826400, 3466389600, // 2079 | |
3477276000, 3497839200, // 2080 | |
3508725600, 3529288800, // 2081 | |
3540175200, 3560738400, // 2082 | |
3572229600, 3592792800, // 2083 | |
3603679200, 3624242400, // 2084 | |
3635128800, 3655692000, // 2085 | |
3666578400, 3687141600, // 2086 | |
3698028000, 3718591200, // 2087 | |
3730082400, 3750645600, // 2088 | |
3761532000, 3782095200, // 2089 | |
3792981600, 3813544800, // 2090 | |
3824431200, 3844994400, // 2091 | |
3855880800, 3876444000, // 2092 | |
3887330400, 3907893600, // 2093 | |
3919384800, 3939948000, // 2094 | |
3950834400, 3971397600, // 2095 | |
3982284000, 4002847200, // 2096 | |
4013733600, 4034296800, // 2097 | |
4045183200, 4065746400, // 2098 | |
4076632800, 4097196000, // 2099 | |
}; | |
#endif | |
uint8_t is_dst(unsigned long time){ | |
uint8_t out = 0; | |
#if defined(USE_USA_DST) || defined(USE_EURO_DST) | |
int yy = year(time) % 100; | |
time_t start = pgm_read_dword_near(DST + 2 * yy); | |
time_t stop = pgm_read_dword_near(DST + 2 * yy + 1); | |
out = (start < time) && (time < stop); | |
#endif | |
return out; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment