VFD modular clock firmware

Dependencies:   DipCortex-EEprom RTC flw mbed

Committer:
Backstrom
Date:
Wed Feb 11 03:08:57 2015 +0000
Revision:
5:5c073029c416
Parent:
0:f6e68b4ce169
Child:
11:34b344fdec98
Enable button sound.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Backstrom 0:f6e68b4ce169 1 /*
Backstrom 0:f6e68b4ce169 2 * VFD Modular Clock - mbed
Backstrom 0:f6e68b4ce169 3 * (C) 2011-14 Akafugu Corporation
Backstrom 0:f6e68b4ce169 4 *
Backstrom 0:f6e68b4ce169 5 * This program is free software; you can redistribute it and/or modify it under the
Backstrom 0:f6e68b4ce169 6 * terms of the GNU General Public License as published by the Free Software
Backstrom 0:f6e68b4ce169 7 * Foundation; either version 2 of the License, or (at your option) any later
Backstrom 0:f6e68b4ce169 8 * version.
Backstrom 0:f6e68b4ce169 9 *
Backstrom 0:f6e68b4ce169 10 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
Backstrom 0:f6e68b4ce169 11 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
Backstrom 0:f6e68b4ce169 12 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
Backstrom 0:f6e68b4ce169 13 *
Backstrom 0:f6e68b4ce169 14 */
Backstrom 0:f6e68b4ce169 15
Backstrom 0:f6e68b4ce169 16 #include "global.h"
Backstrom 0:f6e68b4ce169 17 #include "mbed.h"
Backstrom 0:f6e68b4ce169 18
Backstrom 0:f6e68b4ce169 19 #include "VFDDisplay.h"
Backstrom 0:f6e68b4ce169 20 #include "IV18Display.h"
Backstrom 0:f6e68b4ce169 21
Backstrom 0:f6e68b4ce169 22 #include "prefs.h"
Backstrom 0:f6e68b4ce169 23 #include "gps.h"
Backstrom 0:f6e68b4ce169 24 #include "menu.h"
Backstrom 0:f6e68b4ce169 25 #include "button.h"
Backstrom 0:f6e68b4ce169 26 #include "rtc.h"
Backstrom 0:f6e68b4ce169 27 #include "ds3231m.h"
Backstrom 0:f6e68b4ce169 28 #include "beep.h"
Backstrom 0:f6e68b4ce169 29 #include "flw.h"
Backstrom 0:f6e68b4ce169 30
Backstrom 0:f6e68b4ce169 31 IV18Display display(PinMap::data, PinMap::clock, PinMap::latch, PinMap::blank);
Backstrom 0:f6e68b4ce169 32
Backstrom 0:f6e68b4ce169 33 Menu menu;
Backstrom 0:f6e68b4ce169 34
Backstrom 0:f6e68b4ce169 35 I2C i2c(PinMap::sda, PinMap::scl);
Backstrom 0:f6e68b4ce169 36 DS3231M rtc(i2c);
Backstrom 0:f6e68b4ce169 37 //RTC rtc;
Backstrom 0:f6e68b4ce169 38
Backstrom 0:f6e68b4ce169 39 DigitalOut led(PinMap::led);
Backstrom 0:f6e68b4ce169 40 Beep piezo(PinMap::piezo);
Backstrom 0:f6e68b4ce169 41
Backstrom 0:f6e68b4ce169 42 FourLetterWord flw(&i2c);
Backstrom 0:f6e68b4ce169 43 char flwWord[5];
Backstrom 0:f6e68b4ce169 44 int flwOffset;
Backstrom 0:f6e68b4ce169 45 int flwOffsetDirection = 1;
Backstrom 0:f6e68b4ce169 46 volatile bool haveEEPROM;
Backstrom 0:f6e68b4ce169 47
Backstrom 0:f6e68b4ce169 48 Ticker blanker;
Backstrom 0:f6e68b4ce169 49 Ticker multiplexer;
Backstrom 0:f6e68b4ce169 50 Ticker button_ticker;
Backstrom 0:f6e68b4ce169 51 Ticker rtc_ticker;
Backstrom 0:f6e68b4ce169 52 Ticker tenth_ticker;
Backstrom 0:f6e68b4ce169 53
Backstrom 0:f6e68b4ce169 54 volatile state_t g_clock_state = STATE_CLOCK;
Backstrom 0:f6e68b4ce169 55 uint32_t gps_last_update = 0xffff;
Backstrom 0:f6e68b4ce169 56
Backstrom 0:f6e68b4ce169 57 uint8_t calculate_segments_7(uint8_t character);
Backstrom 0:f6e68b4ce169 58
Backstrom 0:f6e68b4ce169 59 // Alarm
Backstrom 0:f6e68b4ce169 60 volatile bool g_alarm_on;
Backstrom 0:f6e68b4ce169 61 volatile bool g_alarming;
Backstrom 0:f6e68b4ce169 62
Backstrom 0:f6e68b4ce169 63 void write_vfd_8bit(uint8_t data);
Backstrom 0:f6e68b4ce169 64 void write_vfd_iv18(uint8_t digit, uint8_t segments);
Backstrom 0:f6e68b4ce169 65 void write_vfd(uint8_t digit, uint8_t segments);
Backstrom 0:f6e68b4ce169 66 void demo_cycle(char* buf);
Backstrom 0:f6e68b4ce169 67
Backstrom 0:f6e68b4ce169 68 void blank_tick()
Backstrom 0:f6e68b4ce169 69 {
Backstrom 0:f6e68b4ce169 70 static uint32_t cnt = 0;
Backstrom 0:f6e68b4ce169 71
Backstrom 0:f6e68b4ce169 72 if ((cnt%10) > (10-display.getBrightness())) {
Backstrom 0:f6e68b4ce169 73 display.blank(false);
Backstrom 0:f6e68b4ce169 74 }
Backstrom 0:f6e68b4ce169 75 else {
Backstrom 0:f6e68b4ce169 76 display.blank(true);
Backstrom 0:f6e68b4ce169 77 }
Backstrom 0:f6e68b4ce169 78
Backstrom 0:f6e68b4ce169 79 cnt++;
Backstrom 0:f6e68b4ce169 80 }
Backstrom 0:f6e68b4ce169 81
Backstrom 0:f6e68b4ce169 82 void multiplex_tick()
Backstrom 0:f6e68b4ce169 83 {
Backstrom 0:f6e68b4ce169 84 display.multiplexTick();
Backstrom 0:f6e68b4ce169 85 }
Backstrom 0:f6e68b4ce169 86
Backstrom 0:f6e68b4ce169 87 void rtc_tick()
Backstrom 0:f6e68b4ce169 88 {
Backstrom 0:f6e68b4ce169 89 if (haveEEPROM)
Backstrom 0:f6e68b4ce169 90 strncpy(flwWord, flw.getWord(), 4);
Backstrom 0:f6e68b4ce169 91
Backstrom 0:f6e68b4ce169 92 flwOffset += flwOffsetDirection;
Backstrom 0:f6e68b4ce169 93
Backstrom 0:f6e68b4ce169 94 if (flwOffset <= 0) {
Backstrom 0:f6e68b4ce169 95 flwOffset = 0;
Backstrom 0:f6e68b4ce169 96 flwOffsetDirection = 1;
Backstrom 0:f6e68b4ce169 97 }
Backstrom 0:f6e68b4ce169 98 else if (flwOffset > display.digits() -4) {
Backstrom 0:f6e68b4ce169 99 flwOffset = 3;
Backstrom 0:f6e68b4ce169 100 flwOffsetDirection = -1;
Backstrom 0:f6e68b4ce169 101 }
Backstrom 0:f6e68b4ce169 102
Backstrom 0:f6e68b4ce169 103 rtc.tick();
Backstrom 0:f6e68b4ce169 104 }
Backstrom 0:f6e68b4ce169 105
Backstrom 0:f6e68b4ce169 106 void tenth_tick()
Backstrom 0:f6e68b4ce169 107 {
Backstrom 0:f6e68b4ce169 108 rtc.tenth_tick();
Backstrom 0:f6e68b4ce169 109 }
Backstrom 0:f6e68b4ce169 110
Backstrom 0:f6e68b4ce169 111 void counterTest()
Backstrom 0:f6e68b4ce169 112 {
Backstrom 0:f6e68b4ce169 113 display.cls();
Backstrom 0:f6e68b4ce169 114 for (uint16_t i = 0; i < 200; i++) {
Backstrom 0:f6e68b4ce169 115 display.printf("cnt %3d", i);
Backstrom 0:f6e68b4ce169 116 wait(0.01);
Backstrom 0:f6e68b4ce169 117 }
Backstrom 0:f6e68b4ce169 118 }
Backstrom 0:f6e68b4ce169 119
Backstrom 0:f6e68b4ce169 120 void timeAndDateTest()
Backstrom 0:f6e68b4ce169 121 {
Backstrom 0:f6e68b4ce169 122 uint8_t hour = 15;
Backstrom 0:f6e68b4ce169 123 uint8_t min = 59;
Backstrom 0:f6e68b4ce169 124 uint8_t sec = 55;
Backstrom 0:f6e68b4ce169 125
Backstrom 0:f6e68b4ce169 126 display.cls();
Backstrom 0:f6e68b4ce169 127 for (uint8_t i = 0; i < 7; i++) {
Backstrom 0:f6e68b4ce169 128 display.printf("%02d-%02d-%02d", hour, min, sec);
Backstrom 0:f6e68b4ce169 129 sec++;
Backstrom 0:f6e68b4ce169 130 if (sec == 60) { sec = 0; min++; }
Backstrom 0:f6e68b4ce169 131 if (min == 60) { min = 0; hour++; }
Backstrom 0:f6e68b4ce169 132 wait(1.0);
Backstrom 0:f6e68b4ce169 133 }
Backstrom 0:f6e68b4ce169 134
Backstrom 0:f6e68b4ce169 135 display.printf("%02d-%02d-%02d Monday 2014-05-12", hour, min, sec);
Backstrom 0:f6e68b4ce169 136
Backstrom 0:f6e68b4ce169 137 while (!display.scrollFinished()) {
Backstrom 0:f6e68b4ce169 138 display.scroll();
Backstrom 0:f6e68b4ce169 139 wait(0.25);
Backstrom 0:f6e68b4ce169 140 }
Backstrom 0:f6e68b4ce169 141
Backstrom 0:f6e68b4ce169 142 display.resetScroll();
Backstrom 0:f6e68b4ce169 143
Backstrom 0:f6e68b4ce169 144 for (uint8_t i = 0; i < 5; i++) {
Backstrom 0:f6e68b4ce169 145 display.printf("%2d-%02d-%02d", hour, min, sec);
Backstrom 0:f6e68b4ce169 146 sec++;
Backstrom 0:f6e68b4ce169 147 if (sec == 60) { sec = 0; min++; }
Backstrom 0:f6e68b4ce169 148 if (min == 60) { min = 0; hour++; }
Backstrom 0:f6e68b4ce169 149 wait(1.0);
Backstrom 0:f6e68b4ce169 150 }
Backstrom 0:f6e68b4ce169 151
Backstrom 0:f6e68b4ce169 152 }
Backstrom 0:f6e68b4ce169 153
Backstrom 0:f6e68b4ce169 154 int dayOfWeek(int y, int m, int d)
Backstrom 0:f6e68b4ce169 155 {
Backstrom 0:f6e68b4ce169 156 static const int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
Backstrom 0:f6e68b4ce169 157 y -= m < 3;
Backstrom 0:f6e68b4ce169 158 return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
Backstrom 0:f6e68b4ce169 159 }
Backstrom 0:f6e68b4ce169 160
Backstrom 0:f6e68b4ce169 161 void welcomeMessage()
Backstrom 0:f6e68b4ce169 162 {
Backstrom 0:f6e68b4ce169 163 const char* buf = " Akafugu VFD Modular Clock";
Backstrom 0:f6e68b4ce169 164
Backstrom 0:f6e68b4ce169 165 display.cls();
Backstrom 0:f6e68b4ce169 166 display.printf(buf);
Backstrom 0:f6e68b4ce169 167
Backstrom 0:f6e68b4ce169 168 // scroll forward
Backstrom 0:f6e68b4ce169 169 while (!display.scrollFinished()) {
Backstrom 0:f6e68b4ce169 170 display.scroll();
Backstrom 0:f6e68b4ce169 171 led = !led;
Backstrom 0:f6e68b4ce169 172 wait(0.20);
Backstrom 0:f6e68b4ce169 173 }
Backstrom 0:f6e68b4ce169 174
Backstrom 0:f6e68b4ce169 175 display.cls();
Backstrom 0:f6e68b4ce169 176 }
Backstrom 0:f6e68b4ce169 177
Backstrom 0:f6e68b4ce169 178 // helper function for handling time/alarm setting
Backstrom 0:f6e68b4ce169 179 uint8_t handleTimeSetting(uint8_t setting, uint8_t min, uint8_t max,
Backstrom 0:f6e68b4ce169 180 bool backButton, bool nextButton)
Backstrom 0:f6e68b4ce169 181 {
Backstrom 0:f6e68b4ce169 182 if (backButton) {
Backstrom 0:f6e68b4ce169 183 if (setting == 0) {
Backstrom 0:f6e68b4ce169 184 setting = max;
Backstrom 0:f6e68b4ce169 185 }
Backstrom 0:f6e68b4ce169 186 else {
Backstrom 0:f6e68b4ce169 187 setting--;
Backstrom 0:f6e68b4ce169 188 }
Backstrom 0:f6e68b4ce169 189 }
Backstrom 0:f6e68b4ce169 190 else if (nextButton) {
Backstrom 0:f6e68b4ce169 191 if (setting == max) {
Backstrom 0:f6e68b4ce169 192 setting = 0;
Backstrom 0:f6e68b4ce169 193 }
Backstrom 0:f6e68b4ce169 194 else {
Backstrom 0:f6e68b4ce169 195 setting++;
Backstrom 0:f6e68b4ce169 196 }
Backstrom 0:f6e68b4ce169 197 }
Backstrom 0:f6e68b4ce169 198
Backstrom 0:f6e68b4ce169 199 return setting;
Backstrom 0:f6e68b4ce169 200 }
Backstrom 0:f6e68b4ce169 201
Backstrom 0:f6e68b4ce169 202 const uint32_t MENU_TIMEOUT = 3 * 10; // each cycle 0.1s, 3 secs total
Backstrom 0:f6e68b4ce169 203 struct tm* tm_;
Backstrom 0:f6e68b4ce169 204
Backstrom 0:f6e68b4ce169 205 int main()
Backstrom 0:f6e68b4ce169 206 {
Backstrom 0:f6e68b4ce169 207 bool suppress_button_sound = false;
Backstrom 0:f6e68b4ce169 208 uint8_t button3_holdcounter = 0;
Backstrom 0:f6e68b4ce169 209 uint32_t menu_countdown = MENU_TIMEOUT;
Backstrom 0:f6e68b4ce169 210
Backstrom 0:f6e68b4ce169 211 // Enable extra memory banks
Backstrom 0:f6e68b4ce169 212 LPC_SYSCON->SYSAHBCLKCTRL |= 0x1 << 26; // RAM1
Backstrom 0:f6e68b4ce169 213 LPC_SYSCON->SYSAHBCLKCTRL |= 0x1 << 27; // USBSRAM
Backstrom 0:f6e68b4ce169 214
Backstrom 0:f6e68b4ce169 215 // PWM
Backstrom 0:f6e68b4ce169 216 // See: http://developer.mbed.org/forum/mbed/topic/3276/
Backstrom 0:f6e68b4ce169 217 /*
Backstrom 0:f6e68b4ce169 218 LPC_CT16B0->TCR = 2;
Backstrom 0:f6e68b4ce169 219 LPC_CT16B0->PR = 19;
Backstrom 0:f6e68b4ce169 220 LPC_CT16B0->MR0 = 48000; // 1ms
Backstrom 0:f6e68b4ce169 221 LPC_CT16B0->TCR = 1;
Backstrom 0:f6e68b4ce169 222 */
Backstrom 0:f6e68b4ce169 223
Backstrom 0:f6e68b4ce169 224 BUTTON_STATE buttons;
Backstrom 0:f6e68b4ce169 225
Backstrom 0:f6e68b4ce169 226 rtc.begin();
Backstrom 0:f6e68b4ce169 227 init_prefs();
Backstrom 0:f6e68b4ce169 228
Backstrom 0:f6e68b4ce169 229 // FLW initialization
Backstrom 0:f6e68b4ce169 230 tm_ = rtc.getTime();
Backstrom 0:f6e68b4ce169 231
Backstrom 0:f6e68b4ce169 232 flw.begin(tm_->tm_min * 60 + tm_->tm_sec);
Backstrom 0:f6e68b4ce169 233 flw.setCensored(true);
Backstrom 0:f6e68b4ce169 234
Backstrom 0:f6e68b4ce169 235 memset(flwWord, 0, 5);
Backstrom 0:f6e68b4ce169 236 haveEEPROM = flw.hasEeprom();
Backstrom 0:f6e68b4ce169 237 if (haveEEPROM)
Backstrom 0:f6e68b4ce169 238 strncpy(flwWord, flw.getWord(), 4);
Backstrom 0:f6e68b4ce169 239 else
Backstrom 0:f6e68b4ce169 240 memset(flwWord, 0, 4);
Backstrom 0:f6e68b4ce169 241
Backstrom 0:f6e68b4ce169 242 led = 0;
Backstrom 0:f6e68b4ce169 243
Backstrom 0:f6e68b4ce169 244 initialize_buttons();
Backstrom 0:f6e68b4ce169 245 menu.setDigits(display.digits());
Backstrom 0:f6e68b4ce169 246
Backstrom 0:f6e68b4ce169 247 blanker.attach_us(&blank_tick, 100);
Backstrom 0:f6e68b4ce169 248 multiplexer.attach_us(&multiplex_tick, 2000);
Backstrom 0:f6e68b4ce169 249 button_ticker.attach_us(&button_tick, 5000);
Backstrom 0:f6e68b4ce169 250 rtc_ticker.attach(&rtc_tick, 1.0);
Backstrom 0:f6e68b4ce169 251 tenth_ticker.attach(&tenth_tick, 0.1);
Backstrom 0:f6e68b4ce169 252
Backstrom 0:f6e68b4ce169 253 PrefsData* prefs = get_prefs();
Backstrom 0:f6e68b4ce169 254 display.setBrightness(prefs->prefs.brightness);
Backstrom 0:f6e68b4ce169 255
Backstrom 0:f6e68b4ce169 256 wait(1.0);
Backstrom 0:f6e68b4ce169 257 //welcomeMessage();
Backstrom 0:f6e68b4ce169 258 led = 0;
Backstrom 0:f6e68b4ce169 259
Backstrom 0:f6e68b4ce169 260 #ifdef HAVE_GPS
Backstrom 0:f6e68b4ce169 261 gps_init();
Backstrom 0:f6e68b4ce169 262 #endif // HAVE_GPS
Backstrom 0:f6e68b4ce169 263
Backstrom 0:f6e68b4ce169 264 /*
Backstrom 0:f6e68b4ce169 265 // button test
Backstrom 0:f6e68b4ce169 266 while (1) {
Backstrom 0:f6e68b4ce169 267 get_button_state(&buttons);
Backstrom 0:f6e68b4ce169 268
Backstrom 0:f6e68b4ce169 269 display.printf("%d-%d-%d %d", buttons.b1_keydown, buttons.b2_keydown, buttons.b3_keydown, get_keystatus());
Backstrom 0:f6e68b4ce169 270 wait(0.1);
Backstrom 0:f6e68b4ce169 271 }
Backstrom 0:f6e68b4ce169 272 */
Backstrom 0:f6e68b4ce169 273
Backstrom 0:f6e68b4ce169 274 while (1) {
Backstrom 0:f6e68b4ce169 275 get_button_state(&buttons);
Backstrom 0:f6e68b4ce169 276 prefs = get_prefs();
Backstrom 0:f6e68b4ce169 277
Backstrom 0:f6e68b4ce169 278 led = 0;
Backstrom 0:f6e68b4ce169 279
Backstrom 0:f6e68b4ce169 280 #ifdef HAVE_GPS
Backstrom 0:f6e68b4ce169 281 // Read GPS and update RTC if needed
Backstrom 0:f6e68b4ce169 282 if (gpsDataReady()) {
Backstrom 0:f6e68b4ce169 283 char* nmea = gpsNMEA();
Backstrom 0:f6e68b4ce169 284 bool error = false;
Backstrom 0:f6e68b4ce169 285 bool fix = false;
Backstrom 0:f6e68b4ce169 286
Backstrom 0:f6e68b4ce169 287 if ( prefs->prefs.gps && strncmp( nmea, "$GPRMC,", 7 ) == 0 ) {
Backstrom 0:f6e68b4ce169 288 time_t t = parseGPSdata(nmea, error, fix, prefs->prefs.gps_tzh, prefs->prefs.gps_tzm);
Backstrom 0:f6e68b4ce169 289 time_t delta = t - gps_last_update;
Backstrom 0:f6e68b4ce169 290
Backstrom 0:f6e68b4ce169 291 if (fix && !error && delta > 60) {
Backstrom 0:f6e68b4ce169 292 led = 1;
Backstrom 0:f6e68b4ce169 293 struct tm *tmp = localtime(&t);
Backstrom 0:f6e68b4ce169 294 rtc.setTime(tmp);
Backstrom 0:f6e68b4ce169 295 gps_last_update = t;
Backstrom 0:f6e68b4ce169 296 }
Backstrom 0:f6e68b4ce169 297 }
Backstrom 0:f6e68b4ce169 298 }
Backstrom 0:f6e68b4ce169 299 #endif // HAVE_GPS
Backstrom 0:f6e68b4ce169 300
Backstrom 0:f6e68b4ce169 301 if (buttons.b1_keyup || buttons.b2_keyup || buttons.b3_keyup) {
Backstrom 0:f6e68b4ce169 302 if (suppress_button_sound || g_alarming) {
Backstrom 0:f6e68b4ce169 303 suppress_button_sound = false;
Backstrom 0:f6e68b4ce169 304 buttons.b1_keyup = buttons.b2_keyup = buttons.b3_keyup = 0;
Backstrom 0:f6e68b4ce169 305 }
Backstrom 0:f6e68b4ce169 306 else {
Backstrom 5:5c073029c416 307 piezo.play('g');
Backstrom 0:f6e68b4ce169 308 }
Backstrom 0:f6e68b4ce169 309
Backstrom 0:f6e68b4ce169 310 button3_holdcounter = 0;
Backstrom 0:f6e68b4ce169 311 g_alarming = false;
Backstrom 0:f6e68b4ce169 312 }
Backstrom 0:f6e68b4ce169 313
Backstrom 0:f6e68b4ce169 314 switch (g_clock_state) {
Backstrom 0:f6e68b4ce169 315 case STATE_CLOCK:
Backstrom 0:f6e68b4ce169 316 {
Backstrom 0:f6e68b4ce169 317 tm_ = rtc.getTime();
Backstrom 0:f6e68b4ce169 318
Backstrom 0:f6e68b4ce169 319 // button 1 triggers menu
Backstrom 0:f6e68b4ce169 320 if (buttons.b1_keyup) {
Backstrom 0:f6e68b4ce169 321 //display.incBrightness();
Backstrom 0:f6e68b4ce169 322 display.printf("%s ", menu.reset());
Backstrom 0:f6e68b4ce169 323 display.setAlarmIndicator(false);
Backstrom 0:f6e68b4ce169 324 display.setGPSIndicator(false);
Backstrom 0:f6e68b4ce169 325 set_extra_prefs(tm_->tm_year+1900, tm_->tm_mon+1, tm_->tm_mday);
Backstrom 0:f6e68b4ce169 326 g_clock_state = STATE_MENU;
Backstrom 0:f6e68b4ce169 327 menu_countdown = MENU_TIMEOUT;
Backstrom 0:f6e68b4ce169 328 buttons.b1_keyup = 0;
Backstrom 0:f6e68b4ce169 329 break;
Backstrom 0:f6e68b4ce169 330 }
Backstrom 0:f6e68b4ce169 331
Backstrom 0:f6e68b4ce169 332 // Button 2 cycles through display mode
Backstrom 0:f6e68b4ce169 333 if (buttons.b2_keyup) {
Backstrom 0:f6e68b4ce169 334 display.toggleTimeMode();
Backstrom 0:f6e68b4ce169 335 buttons.b2_keyup = 0;
Backstrom 0:f6e68b4ce169 336 }
Backstrom 0:f6e68b4ce169 337
Backstrom 0:f6e68b4ce169 338 // Button 3 toggles FLW mode
Backstrom 0:f6e68b4ce169 339 if (buttons.b3_keyup && haveEEPROM) {
Backstrom 0:f6e68b4ce169 340 buttons.b3_keyup = 0;
Backstrom 0:f6e68b4ce169 341 button3_holdcounter = 0;
Backstrom 0:f6e68b4ce169 342 g_clock_state = STATE_FLW;
Backstrom 0:f6e68b4ce169 343 }
Backstrom 0:f6e68b4ce169 344
Backstrom 0:f6e68b4ce169 345 // Hold button 3 to set alarm
Backstrom 0:f6e68b4ce169 346 if (buttons.b3_repeat) {
Backstrom 0:f6e68b4ce169 347 button3_holdcounter++;
Backstrom 0:f6e68b4ce169 348 buttons.b3_repeat = 0;
Backstrom 0:f6e68b4ce169 349 suppress_button_sound = true;
Backstrom 0:f6e68b4ce169 350
Backstrom 0:f6e68b4ce169 351 if (button3_holdcounter == 6) {
Backstrom 0:f6e68b4ce169 352 g_alarm_on = !g_alarm_on;
Backstrom 0:f6e68b4ce169 353 piezo.play('a');
Backstrom 0:f6e68b4ce169 354 }
Backstrom 0:f6e68b4ce169 355 }
Backstrom 0:f6e68b4ce169 356
Backstrom 0:f6e68b4ce169 357 // Enter auto date
Backstrom 0:f6e68b4ce169 358 if (prefs->prefs.auto_date && tm_->tm_sec == 50) {
Backstrom 0:f6e68b4ce169 359 display.cls();
Backstrom 0:f6e68b4ce169 360 display.printTimeLong(tm_, rtc.getTenths());
Backstrom 0:f6e68b4ce169 361 g_clock_state = STATE_AUTO_DATE;
Backstrom 0:f6e68b4ce169 362 }
Backstrom 0:f6e68b4ce169 363 else if (haveEEPROM && prefs->prefs.flw > 0 && tm_->tm_sec == 30) {
Backstrom 0:f6e68b4ce169 364 g_clock_state = STATE_AUTO_FLW;
Backstrom 0:f6e68b4ce169 365 }
Backstrom 0:f6e68b4ce169 366 else {
Backstrom 0:f6e68b4ce169 367 display.printTime(tm_, rtc.getTenths());
Backstrom 0:f6e68b4ce169 368 }
Backstrom 0:f6e68b4ce169 369 }
Backstrom 0:f6e68b4ce169 370 break;
Backstrom 0:f6e68b4ce169 371 case STATE_MENU:
Backstrom 0:f6e68b4ce169 372 {
Backstrom 0:f6e68b4ce169 373 // button 1 goes to next menu item
Backstrom 0:f6e68b4ce169 374 if (buttons.b1_keyup) {
Backstrom 0:f6e68b4ce169 375 display.printf("%s ", menu.next());
Backstrom 0:f6e68b4ce169 376 menu_countdown = MENU_TIMEOUT;
Backstrom 0:f6e68b4ce169 377 buttons.b1_keyup = 0;
Backstrom 0:f6e68b4ce169 378 }
Backstrom 0:f6e68b4ce169 379
Backstrom 0:f6e68b4ce169 380 // Button 2 selects menu item
Backstrom 0:f6e68b4ce169 381 if (buttons.b2_keyup || buttons.b2_repeat) {
Backstrom 0:f6e68b4ce169 382 bool setTime, setAlarm;
Backstrom 0:f6e68b4ce169 383
Backstrom 0:f6e68b4ce169 384 display.printf("%8s ", menu.select(setTime, setAlarm));
Backstrom 0:f6e68b4ce169 385
Backstrom 0:f6e68b4ce169 386 if (setTime) {
Backstrom 0:f6e68b4ce169 387 menu.leave();
Backstrom 0:f6e68b4ce169 388 display.setBlinkMode(VFDDisplay::Hours);
Backstrom 0:f6e68b4ce169 389 display.blink(true);
Backstrom 0:f6e68b4ce169 390 tm_ = rtc.getTime(); // get time from RTC to use as basis for settings
Backstrom 0:f6e68b4ce169 391 tm_->tm_sec = 0;
Backstrom 0:f6e68b4ce169 392 g_clock_state = STATE_SET_CLOCK_HH;
Backstrom 0:f6e68b4ce169 393 }
Backstrom 0:f6e68b4ce169 394 else if (setAlarm) {
Backstrom 0:f6e68b4ce169 395 menu.leave();
Backstrom 0:f6e68b4ce169 396 display.setBlinkMode(VFDDisplay::Minutes);
Backstrom 0:f6e68b4ce169 397 display.blink(true);
Backstrom 0:f6e68b4ce169 398 tm_ = rtc.getAlarm();
Backstrom 0:f6e68b4ce169 399 g_clock_state = STATE_SET_ALARM_HH;
Backstrom 0:f6e68b4ce169 400 }
Backstrom 0:f6e68b4ce169 401
Backstrom 0:f6e68b4ce169 402 menu_countdown = MENU_TIMEOUT;
Backstrom 0:f6e68b4ce169 403 buttons.b2_keyup = 0;
Backstrom 0:f6e68b4ce169 404 }
Backstrom 0:f6e68b4ce169 405 // Button 3 leaves menu
Backstrom 0:f6e68b4ce169 406 else if (buttons.b3_keyup) {
Backstrom 0:f6e68b4ce169 407 buttons.b3_keyup = 0;
Backstrom 0:f6e68b4ce169 408 menu.leave();
Backstrom 0:f6e68b4ce169 409 g_clock_state = STATE_CLOCK;
Backstrom 0:f6e68b4ce169 410 }
Backstrom 0:f6e68b4ce169 411
Backstrom 0:f6e68b4ce169 412 menu_countdown--;
Backstrom 0:f6e68b4ce169 413
Backstrom 0:f6e68b4ce169 414 // exit menu if unused for preset time
Backstrom 0:f6e68b4ce169 415 if (menu_countdown == 0) {
Backstrom 0:f6e68b4ce169 416 menu.leave();
Backstrom 0:f6e68b4ce169 417 g_clock_state = STATE_CLOCK;
Backstrom 0:f6e68b4ce169 418 }
Backstrom 0:f6e68b4ce169 419
Backstrom 0:f6e68b4ce169 420 // If g_clock_state has changed, we are leaving the menu, update parameters
Backstrom 0:f6e68b4ce169 421 if (g_clock_state == STATE_CLOCK) {
Backstrom 0:f6e68b4ce169 422 display.setGPSIndicator(true);
Backstrom 0:f6e68b4ce169 423
Backstrom 0:f6e68b4ce169 424 tm_ = rtc.getTime();
Backstrom 0:f6e68b4ce169 425 int year, month, day;
Backstrom 0:f6e68b4ce169 426
Backstrom 0:f6e68b4ce169 427 get_extra_prefs(year, month, day);
Backstrom 0:f6e68b4ce169 428 tm_->tm_year = year - 1900;
Backstrom 0:f6e68b4ce169 429 tm_->tm_mon = month-1;
Backstrom 0:f6e68b4ce169 430 tm_->tm_mday = day;
Backstrom 0:f6e68b4ce169 431
Backstrom 0:f6e68b4ce169 432 tm_->tm_wday = dayOfWeek(year, month, day);
Backstrom 0:f6e68b4ce169 433
Backstrom 0:f6e68b4ce169 434 rtc.setTime(tm_);
Backstrom 0:f6e68b4ce169 435
Backstrom 0:f6e68b4ce169 436 wait(0.05);
Backstrom 0:f6e68b4ce169 437 display.setGPSIndicator(false);
Backstrom 0:f6e68b4ce169 438 }
Backstrom 0:f6e68b4ce169 439 }
Backstrom 0:f6e68b4ce169 440 break;
Backstrom 0:f6e68b4ce169 441 case STATE_AUTO_DATE:
Backstrom 0:f6e68b4ce169 442 {
Backstrom 0:f6e68b4ce169 443 // exit scroll if any button is pressed
Backstrom 0:f6e68b4ce169 444 if (buttons.b1_keyup || buttons.b2_keyup || buttons.b3_keyup) {
Backstrom 0:f6e68b4ce169 445 display.cls();
Backstrom 0:f6e68b4ce169 446 g_clock_state = STATE_CLOCK;
Backstrom 0:f6e68b4ce169 447
Backstrom 0:f6e68b4ce169 448 buttons.b1_keyup = 0;
Backstrom 0:f6e68b4ce169 449 buttons.b2_keyup = 0;
Backstrom 0:f6e68b4ce169 450 buttons.b3_keyup = 0;
Backstrom 0:f6e68b4ce169 451 }
Backstrom 0:f6e68b4ce169 452
Backstrom 0:f6e68b4ce169 453 static uint8_t scroll_cnt = 0;
Backstrom 0:f6e68b4ce169 454
Backstrom 0:f6e68b4ce169 455 if (display.scrollFinished()) {
Backstrom 0:f6e68b4ce169 456 display.cls();
Backstrom 0:f6e68b4ce169 457 g_clock_state = STATE_CLOCK;
Backstrom 0:f6e68b4ce169 458 }
Backstrom 0:f6e68b4ce169 459 else {
Backstrom 0:f6e68b4ce169 460 if (++scroll_cnt == 2) {
Backstrom 0:f6e68b4ce169 461 display.scroll();
Backstrom 0:f6e68b4ce169 462 scroll_cnt = 0;
Backstrom 0:f6e68b4ce169 463 }
Backstrom 0:f6e68b4ce169 464 }
Backstrom 0:f6e68b4ce169 465 }
Backstrom 0:f6e68b4ce169 466 break;
Backstrom 0:f6e68b4ce169 467 case STATE_SET_CLOCK_HH:
Backstrom 0:f6e68b4ce169 468 {
Backstrom 0:f6e68b4ce169 469 display.printTimeSet(tm_);
Backstrom 0:f6e68b4ce169 470
Backstrom 0:f6e68b4ce169 471 if (buttons.b1_repeat || buttons.b2_repeat) {
Backstrom 0:f6e68b4ce169 472 display.blink(false);
Backstrom 0:f6e68b4ce169 473 tm_->tm_hour = handleTimeSetting(tm_->tm_hour, 0, 23, buttons.b1_repeat, buttons.b2_repeat);
Backstrom 0:f6e68b4ce169 474 buttons.b1_repeat = 0;
Backstrom 0:f6e68b4ce169 475 buttons.b2_repeat = 0;
Backstrom 0:f6e68b4ce169 476 }
Backstrom 0:f6e68b4ce169 477 if (buttons.b1_keyup) {
Backstrom 0:f6e68b4ce169 478 display.blink(true);
Backstrom 0:f6e68b4ce169 479 tm_->tm_hour = handleTimeSetting(tm_->tm_hour, 0, 23, true, false);
Backstrom 0:f6e68b4ce169 480 buttons.b1_keyup = 0;
Backstrom 0:f6e68b4ce169 481 }
Backstrom 0:f6e68b4ce169 482 else if (buttons.b2_keyup) { // Button 2
Backstrom 0:f6e68b4ce169 483 display.blink(true);
Backstrom 0:f6e68b4ce169 484 tm_->tm_hour = handleTimeSetting(tm_->tm_hour, 0, 23, false, true);
Backstrom 0:f6e68b4ce169 485 buttons.b2_keyup = 0;
Backstrom 0:f6e68b4ce169 486 }
Backstrom 0:f6e68b4ce169 487 else if (buttons.b3_keyup) { // Button 3 moves to minute setting
Backstrom 0:f6e68b4ce169 488 display.setBlinkMode(VFDDisplay::Minutes);
Backstrom 0:f6e68b4ce169 489 g_clock_state = STATE_SET_CLOCK_MM;
Backstrom 0:f6e68b4ce169 490 buttons.b3_keyup = 0;
Backstrom 0:f6e68b4ce169 491 }
Backstrom 0:f6e68b4ce169 492 }
Backstrom 0:f6e68b4ce169 493 break;
Backstrom 0:f6e68b4ce169 494 case STATE_SET_CLOCK_MM:
Backstrom 0:f6e68b4ce169 495 {
Backstrom 0:f6e68b4ce169 496 display.printTimeSet(tm_);
Backstrom 0:f6e68b4ce169 497
Backstrom 0:f6e68b4ce169 498 if (buttons.b1_repeat || buttons.b2_repeat) {
Backstrom 0:f6e68b4ce169 499 display.blink(false);
Backstrom 0:f6e68b4ce169 500 tm_->tm_min = handleTimeSetting(tm_->tm_min, 0, 59, buttons.b1_repeat, buttons.b2_repeat);
Backstrom 0:f6e68b4ce169 501 buttons.b1_repeat = 0;
Backstrom 0:f6e68b4ce169 502 buttons.b2_repeat = 0;
Backstrom 0:f6e68b4ce169 503 }
Backstrom 0:f6e68b4ce169 504 if (buttons.b1_keyup) {
Backstrom 0:f6e68b4ce169 505 display.blink(true);
Backstrom 0:f6e68b4ce169 506 tm_->tm_min = handleTimeSetting(tm_->tm_min, 0, 59, true, false);
Backstrom 0:f6e68b4ce169 507 buttons.b1_keyup = 0;
Backstrom 0:f6e68b4ce169 508 }
Backstrom 0:f6e68b4ce169 509 else if (buttons.b2_keyup) { // Button 2
Backstrom 0:f6e68b4ce169 510 display.blink(true);
Backstrom 0:f6e68b4ce169 511 tm_->tm_min = handleTimeSetting(tm_->tm_min, 0, 59, false, true);
Backstrom 0:f6e68b4ce169 512 buttons.b2_keyup = 0;
Backstrom 0:f6e68b4ce169 513 }
Backstrom 0:f6e68b4ce169 514 else if (buttons.b3_keyup) { // Button 3 moves to second setting
Backstrom 0:f6e68b4ce169 515 display.setBlinkMode(VFDDisplay::Seconds);
Backstrom 0:f6e68b4ce169 516 g_clock_state = STATE_SET_CLOCK_SS;
Backstrom 0:f6e68b4ce169 517 buttons.b3_keyup = 0;
Backstrom 0:f6e68b4ce169 518 }
Backstrom 0:f6e68b4ce169 519 }
Backstrom 0:f6e68b4ce169 520 break;
Backstrom 0:f6e68b4ce169 521 case STATE_SET_CLOCK_SS:
Backstrom 0:f6e68b4ce169 522 {
Backstrom 0:f6e68b4ce169 523 display.printTimeSet(tm_);
Backstrom 0:f6e68b4ce169 524
Backstrom 0:f6e68b4ce169 525 if (buttons.b1_repeat || buttons.b2_repeat) {
Backstrom 0:f6e68b4ce169 526 display.blink(false);
Backstrom 0:f6e68b4ce169 527 tm_->tm_sec = handleTimeSetting(tm_->tm_sec, 0, 59, buttons.b1_repeat, buttons.b2_repeat);
Backstrom 0:f6e68b4ce169 528 buttons.b1_repeat = 0;
Backstrom 0:f6e68b4ce169 529 buttons.b2_repeat = 0;
Backstrom 0:f6e68b4ce169 530 }
Backstrom 0:f6e68b4ce169 531 if (buttons.b1_keyup) {
Backstrom 0:f6e68b4ce169 532 display.blink(true);
Backstrom 0:f6e68b4ce169 533 tm_->tm_sec = handleTimeSetting(tm_->tm_sec, 0, 59, true, false);
Backstrom 0:f6e68b4ce169 534 buttons.b1_keyup = 0;
Backstrom 0:f6e68b4ce169 535 }
Backstrom 0:f6e68b4ce169 536 else if (buttons.b2_keyup) { // Button 2
Backstrom 0:f6e68b4ce169 537 display.blink(true);
Backstrom 0:f6e68b4ce169 538 tm_->tm_sec = handleTimeSetting(tm_->tm_sec, 0, 59, false, true);
Backstrom 0:f6e68b4ce169 539 buttons.b2_keyup = 0;
Backstrom 0:f6e68b4ce169 540 }
Backstrom 0:f6e68b4ce169 541 else if (buttons.b3_keyup) { // Button 3 moves to minute setting
Backstrom 0:f6e68b4ce169 542 display.setBlinkMode(VFDDisplay::Full);
Backstrom 0:f6e68b4ce169 543 display.blink(false);
Backstrom 0:f6e68b4ce169 544 rtc.setTime(tm_);
Backstrom 0:f6e68b4ce169 545 g_clock_state = STATE_CLOCK;
Backstrom 0:f6e68b4ce169 546 buttons.b3_keyup = 0;
Backstrom 0:f6e68b4ce169 547 }
Backstrom 0:f6e68b4ce169 548 }
Backstrom 0:f6e68b4ce169 549 break;
Backstrom 0:f6e68b4ce169 550 case STATE_SET_ALARM_HH:
Backstrom 0:f6e68b4ce169 551 {
Backstrom 0:f6e68b4ce169 552 display.printTimeSet(tm_, false);
Backstrom 0:f6e68b4ce169 553
Backstrom 0:f6e68b4ce169 554 if (buttons.b1_repeat || buttons.b2_repeat) {
Backstrom 0:f6e68b4ce169 555 display.blink(false);
Backstrom 0:f6e68b4ce169 556 tm_->tm_hour = handleTimeSetting(tm_->tm_hour, 0, 23, buttons.b1_repeat, buttons.b2_repeat);
Backstrom 0:f6e68b4ce169 557 buttons.b1_repeat = 0;
Backstrom 0:f6e68b4ce169 558 buttons.b2_repeat = 0;
Backstrom 0:f6e68b4ce169 559 }
Backstrom 0:f6e68b4ce169 560 if (buttons.b1_keyup) {
Backstrom 0:f6e68b4ce169 561 display.blink(true);
Backstrom 0:f6e68b4ce169 562 tm_->tm_hour = handleTimeSetting(tm_->tm_hour, 0, 23, true, false);
Backstrom 0:f6e68b4ce169 563 buttons.b1_keyup = 0;
Backstrom 0:f6e68b4ce169 564 }
Backstrom 0:f6e68b4ce169 565 else if (buttons.b2_keyup) { // Button 2
Backstrom 0:f6e68b4ce169 566 display.blink(true);
Backstrom 0:f6e68b4ce169 567 tm_->tm_hour = handleTimeSetting(tm_->tm_hour, 0, 23, false, true);
Backstrom 0:f6e68b4ce169 568 buttons.b2_keyup = 0;
Backstrom 0:f6e68b4ce169 569 }
Backstrom 0:f6e68b4ce169 570 else if (buttons.b3_keyup) { // Button 3 moves to minute setting
Backstrom 0:f6e68b4ce169 571 display.setBlinkMode(VFDDisplay::Seconds);
Backstrom 0:f6e68b4ce169 572 g_clock_state = STATE_SET_ALARM_MM;
Backstrom 0:f6e68b4ce169 573 buttons.b3_keyup = 0;
Backstrom 0:f6e68b4ce169 574 }
Backstrom 0:f6e68b4ce169 575 }
Backstrom 0:f6e68b4ce169 576 break;
Backstrom 0:f6e68b4ce169 577 case STATE_SET_ALARM_MM:
Backstrom 0:f6e68b4ce169 578 {
Backstrom 0:f6e68b4ce169 579 display.printTimeSet(tm_, false);
Backstrom 0:f6e68b4ce169 580
Backstrom 0:f6e68b4ce169 581 if (buttons.b1_repeat || buttons.b2_repeat) {
Backstrom 0:f6e68b4ce169 582 display.blink(false);
Backstrom 0:f6e68b4ce169 583 tm_->tm_min = handleTimeSetting(tm_->tm_min, 0, 59, buttons.b1_repeat, buttons.b2_repeat);
Backstrom 0:f6e68b4ce169 584 buttons.b1_repeat = 0;
Backstrom 0:f6e68b4ce169 585 buttons.b2_repeat = 0;
Backstrom 0:f6e68b4ce169 586 }
Backstrom 0:f6e68b4ce169 587 if (buttons.b1_keyup) {
Backstrom 0:f6e68b4ce169 588 display.blink(true);
Backstrom 0:f6e68b4ce169 589 tm_->tm_min = handleTimeSetting(tm_->tm_min, 0, 59, true, false);
Backstrom 0:f6e68b4ce169 590 buttons.b1_keyup = 0;
Backstrom 0:f6e68b4ce169 591 }
Backstrom 0:f6e68b4ce169 592 else if (buttons.b2_keyup) { // Button 2
Backstrom 0:f6e68b4ce169 593 display.blink(true);
Backstrom 0:f6e68b4ce169 594 tm_->tm_min = handleTimeSetting(tm_->tm_min, 0, 59, false, true);
Backstrom 0:f6e68b4ce169 595 buttons.b2_keyup = 0;
Backstrom 0:f6e68b4ce169 596 }
Backstrom 0:f6e68b4ce169 597 else if (buttons.b3_keyup) { // Button 3 moves to minute setting
Backstrom 0:f6e68b4ce169 598 display.setBlinkMode(VFDDisplay::Full);
Backstrom 0:f6e68b4ce169 599 display.blink(false);
Backstrom 0:f6e68b4ce169 600 rtc.setAlarm(tm_->tm_hour, tm_->tm_min, 0);
Backstrom 0:f6e68b4ce169 601 g_clock_state = STATE_CLOCK;
Backstrom 0:f6e68b4ce169 602 buttons.b3_keyup = 0;
Backstrom 0:f6e68b4ce169 603 }
Backstrom 0:f6e68b4ce169 604 }
Backstrom 0:f6e68b4ce169 605 break;
Backstrom 0:f6e68b4ce169 606 case STATE_AUTO_FLW:
Backstrom 0:f6e68b4ce169 607 {
Backstrom 0:f6e68b4ce169 608 tm_ = rtc.getTime();
Backstrom 0:f6e68b4ce169 609
Backstrom 0:f6e68b4ce169 610 if (tm_->tm_sec >= 37) {
Backstrom 0:f6e68b4ce169 611 g_clock_state = STATE_CLOCK;
Backstrom 0:f6e68b4ce169 612 }
Backstrom 0:f6e68b4ce169 613 }
Backstrom 0:f6e68b4ce169 614 // fall-through
Backstrom 0:f6e68b4ce169 615 case STATE_FLW:
Backstrom 0:f6e68b4ce169 616 {
Backstrom 0:f6e68b4ce169 617 // exit if any button is pressed
Backstrom 0:f6e68b4ce169 618 if (buttons.b1_keyup || buttons.b2_keyup || buttons.b3_keyup) {
Backstrom 0:f6e68b4ce169 619 display.cls();
Backstrom 0:f6e68b4ce169 620 g_clock_state = STATE_CLOCK;
Backstrom 0:f6e68b4ce169 621
Backstrom 0:f6e68b4ce169 622 buttons.b1_keyup = 0;
Backstrom 0:f6e68b4ce169 623 buttons.b2_keyup = 0;
Backstrom 0:f6e68b4ce169 624 buttons.b3_keyup = 0;
Backstrom 0:f6e68b4ce169 625 }
Backstrom 0:f6e68b4ce169 626
Backstrom 0:f6e68b4ce169 627 if (flwOffset == 0)
Backstrom 0:f6e68b4ce169 628 display.printf("%s ", flwWord);
Backstrom 0:f6e68b4ce169 629 else
Backstrom 0:f6e68b4ce169 630 display.printf("%*s" "%s ", flwOffset, " ", flwWord);
Backstrom 0:f6e68b4ce169 631 }
Backstrom 0:f6e68b4ce169 632 break;
Backstrom 0:f6e68b4ce169 633 default:
Backstrom 0:f6e68b4ce169 634 break;
Backstrom 0:f6e68b4ce169 635 }
Backstrom 0:f6e68b4ce169 636
Backstrom 0:f6e68b4ce169 637 if (g_alarm_on && rtc.checkAlarm()) {
Backstrom 0:f6e68b4ce169 638 g_alarming = true;
Backstrom 0:f6e68b4ce169 639 }
Backstrom 0:f6e68b4ce169 640
Backstrom 0:f6e68b4ce169 641 display.setAlarmIndicator(g_alarm_on);
Backstrom 0:f6e68b4ce169 642 display.setGPSIndicator(g_alarming);
Backstrom 0:f6e68b4ce169 643
Backstrom 0:f6e68b4ce169 644 if (g_alarming) {
Backstrom 0:f6e68b4ce169 645 piezo.play('g');
Backstrom 0:f6e68b4ce169 646 }
Backstrom 0:f6e68b4ce169 647
Backstrom 0:f6e68b4ce169 648 wait(0.1);
Backstrom 0:f6e68b4ce169 649 }
Backstrom 0:f6e68b4ce169 650 }