VFD modular clock firmware

Dependencies:   DipCortex-EEprom RTC flw mbed

Files at this revision

API Documentation at this revision

Comitter:
Backstrom
Date:
Mon Feb 09 13:40:46 2015 +0000
Child:
1:391b0fbc3bc0
Commit message:
Initial commit

Changed in this revision

.gitignore Show annotated file Show diff for this revision Revisions of this file
DipCortex-EEprom/DipCortex-EEprom.cpp Show annotated file Show diff for this revision Revisions of this file
DipCortex-EEprom/DipCortex-EEprom.h Show annotated file Show diff for this revision Revisions of this file
IV18Display.cpp Show annotated file Show diff for this revision Revisions of this file
IV18Display.h Show annotated file Show diff for this revision Revisions of this file
RTC/ds1302.cpp Show annotated file Show diff for this revision Revisions of this file
RTC/ds1302.h Show annotated file Show diff for this revision Revisions of this file
RTC/ds3231m.cpp Show annotated file Show diff for this revision Revisions of this file
RTC/ds3231m.h Show annotated file Show diff for this revision Revisions of this file
RTC/rtc.cpp Show annotated file Show diff for this revision Revisions of this file
RTC/rtc.h Show annotated file Show diff for this revision Revisions of this file
VFDDisplay.cpp Show annotated file Show diff for this revision Revisions of this file
VFDDisplay.h Show annotated file Show diff for this revision Revisions of this file
_24LCXXX.lib Show annotated file Show diff for this revision Revisions of this file
beep/beep.cpp Show annotated file Show diff for this revision Revisions of this file
beep/beep.h Show annotated file Show diff for this revision Revisions of this file
button.cpp Show annotated file Show diff for this revision Revisions of this file
button.h Show annotated file Show diff for this revision Revisions of this file
features.h Show annotated file Show diff for this revision Revisions of this file
flw/flw.cpp Show annotated file Show diff for this revision Revisions of this file
flw/flw.h Show annotated file Show diff for this revision Revisions of this file
flw/flw_blacklist.h Show annotated file Show diff for this revision Revisions of this file
font_7seg.cpp Show annotated file Show diff for this revision Revisions of this file
global.h Show annotated file Show diff for this revision Revisions of this file
gps.cpp Show annotated file Show diff for this revision Revisions of this file
gps.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
menu.cpp Show annotated file Show diff for this revision Revisions of this file
menu.h Show annotated file Show diff for this revision Revisions of this file
prefs.cpp Show annotated file Show diff for this revision Revisions of this file
prefs.h Show annotated file Show diff for this revision Revisions of this file
vfd_modular_clock.uvopt Show annotated file Show diff for this revision Revisions of this file
vfd_modular_clock.uvproj Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.gitignore	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,2 @@
+.hg
+.hgignore
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DipCortex-EEprom/DipCortex-EEprom.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,211 @@
+//-----------------------------------------------------------------------------
+//* Software that is described herein is for illustrative purposes only
+//* which provides customers with programming information regarding the
+//* products. This software is supplied "AS IS" without any warranties.
+//* NXP Semiconductors assumes no responsibility or liability for the
+//* use of the software, conveys no license or title under any patent,
+//* copyright, or mask work right to the product. NXP Semiconductors
+//* reserves the right to make changes in the software without
+//* notification. NXP Semiconductors also make no representation or
+//* warranty that such application will be suitable for the specified
+//* use without further testing or modification.
+//* Permission to use, copy, modify, and distribute this software and its
+//* documentation is hereby granted, under NXP Semiconductors'
+//* relevant copyright in the software, without fee, provided that it
+//* is used in conjunction with NXP Semiconductors microcontrollers.  This
+//* copyright, permission, and disclaimer notice must appear in all copies of
+//* this code.
+//-----------------------------------------------------------------------------
+
+#include <stdint.h>
+#include <string.h>
+#include "DipCortex-EEprom.h"
+#include "LPC13Uxx.h"            
+
+unsigned param_table[5];
+unsigned result_table[5];
+
+unsigned cclk;
+char flash_buf[FLASH_BUF_SIZE];
+unsigned * flash_address;
+unsigned byte_ctr;
+
+#define iap_entry ((void (*)(unsigned [],unsigned []))(IAP_ADDRESS))
+
+void IAP_WriteData(unsigned cclk,unsigned flash_address,unsigned * flash_data_buf, unsigned count);
+void IAP_PrepareEraseSector( unsigned flash_address );
+void IAP_EraseSector(unsigned start_sector,unsigned end_sector,unsigned cclk);
+void IAP_PrepareSector(unsigned start_sector,unsigned end_sector,unsigned cclk);
+
+
+void IAP_WriteData(unsigned cclk,unsigned flash_address,unsigned * flash_data_buf, unsigned count)
+{
+    param_table[0] = COPY_RAM_TO_FLASH;
+    param_table[1] = flash_address;
+    param_table[2] = (unsigned)flash_data_buf;
+    param_table[3] = count;
+    param_table[4] = cclk;
+    iap_entry(param_table,result_table);
+}
+
+void IAP_EraseSector(unsigned start_sector,unsigned end_sector,unsigned cclk)
+{
+    param_table[0] = ERASE_SECTOR;
+    param_table[1] = start_sector;
+    param_table[2] = end_sector;
+    param_table[3] = cclk;
+    iap_entry(param_table,result_table);
+}
+
+void IAP_PrepareSector(unsigned start_sector,unsigned end_sector,unsigned cclk)
+{
+    param_table[0] = PREPARE_SECTOR_FOR_WRITE;
+    param_table[1] = start_sector;
+    param_table[2] = end_sector;
+    param_table[3] = cclk;
+    iap_entry(param_table,result_table);
+}
+
+int IAP_ErasePage ( unsigned startPageNo, unsigned endPageNo, unsigned cclk )
+{
+    param_table[0] = ERASE_PAGE;
+    param_table[1] = startPageNo;
+    param_table[2] = endPageNo;
+    param_table[3] = cclk;
+    iap_entry(param_table,result_table);
+
+    if( result_table[0] == CMD_SUCCESS )
+    {
+        return (1);
+    }
+    else
+    {
+        return (0);
+    }
+}
+
+void IAP_PrepareEraseSector( unsigned flash_address )
+{
+unsigned i;
+unsigned end_sector;
+
+    end_sector = MAX_USER_SECTOR;
+
+    for(i=0; i<=end_sector; i++)
+    {
+        if(flash_address < (SECTOR_0_START_ADDR + ((i + 1) * SECTOR_SIZE)))
+        {
+            LPC_GPIO->NOT[ 1 ] = 1<<16;
+
+            // if its the start of a sector, erase it
+            if( flash_address == SECTOR_0_START_ADDR + (SECTOR_SIZE * i))
+            {
+                IAP_PrepareSector(i,i,cclk);
+                IAP_EraseSector(i,i,cclk);
+            }
+            IAP_PrepareSector(i,i,cclk);
+            break;
+        }
+    }
+}
+
+int IAP_WritePage (unsigned * dst, char * src, unsigned no_of_bytes)
+{
+unsigned enabled_irqs;
+
+    // A copy of any enabled interrupts
+    enabled_irqs = NVIC->ISER[0];
+    NVIC->ICER[0] = enabled_irqs;
+
+    memcpy(&flash_buf[0], src, no_of_bytes);
+
+    // If the address is the start of a sector then, prepare and erase it
+    IAP_PrepareEraseSector((unsigned)dst);
+    //IAP_ErasePage (1, 1, cclk);
+
+    IAP_WriteData(cclk, (unsigned)dst, (unsigned *)flash_buf, FLASH_BUF_SIZE);
+
+    NVIC->ISER[0] = enabled_irqs;
+
+    return( result_table[0] );
+}
+
+int IAP_CheckForUserCode(void)
+{
+    unsigned *pmem, checksum,i;
+
+    param_table[0] = BLANK_CHECK_SECTOR;
+    param_table[1] = USER_START_SECTOR;
+    param_table[2] = USER_START_SECTOR;
+    iap_entry(param_table,result_table);
+
+    if( result_table[0] == CMD_SUCCESS )
+    {
+        // it's blank
+        return (0);
+    }
+    else
+    {
+        /*
+         * The reserved Cortex-M3 exception vector location 7 (offset 0x001C
+         * in the vector table) should contain the 2’s complement of the
+         * checksum of table entries 0 through 6. This causes the checksum
+         * of the first 8 table entries to be 0. This code checksums the
+         * first 8 locations of the start of user flash. If the result is 0,
+         * then the contents is deemed a 'valid' image.
+         */
+        checksum = 0;
+        pmem = (unsigned *)USER_START_SECTOR;
+        for (i = 0; i <= 7; i++)
+        {
+            checksum += *pmem;
+            pmem++;
+        }
+        if (checksum != 0)
+        {
+            // Failed to checksum, not valid
+        }
+        else
+        {
+            // Checksum passed
+            return (1);
+        }
+    }
+
+    return (0);
+}
+
+void IAP_Init( void )
+{
+    cclk = CCLK;
+    byte_ctr = 0;
+    flash_address = (unsigned *)UPDATE_REQD;
+}
+
+void IAP_Eeprom_Write ( uint32_t eeAddress, uint8_t* buffAddress, uint32_t byteCount )
+{
+    unsigned int command[5], result[4];
+
+    command[0] = EEPROM_WRITE;
+    command[1] = (uint32_t) eeAddress;
+    command[2] = (uint32_t) buffAddress;
+    command[3] = byteCount;
+    command[4] = cclk;
+
+    /* Invoke IAP call...*/
+    iap_entry(command, result);
+}
+
+void IAP_Eeprom_Read ( uint32_t eeAddress, uint8_t* buffAddress, uint32_t byteCount )
+{
+    unsigned int command[5], result[4];
+
+    command[0] = EEPROM_READ;
+    command[1] = (uint32_t) eeAddress;
+    command[2] = (uint32_t) buffAddress;
+    command[3] = byteCount;
+    command[4] = cclk;
+
+    /* Invoke IAP call...*/
+    iap_entry( command, result);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DipCortex-EEprom/DipCortex-EEprom.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,83 @@
+#define USER_START_SECTOR       SECTOR_2_START
+
+#ifndef  _SBL_IAP_H
+#define  _SBL_IAP_H
+
+
+#define SECTOR_0_START          0x00000000
+#define SECTOR_1_START          0x00001000
+#define SECTOR_2_START          0x00002000
+#define SECTOR_3_START          0x00003000
+#define SECTOR_4_START          0x00004000
+#define SECTOR_5_START          0x00005000
+#define SECTOR_6_START          0x00006000
+#define SECTOR_7_START          0x00007000
+#define SECTOR_8_START          0x00008000
+#define SECTOR_9_START          0x00009000
+#define SECTOR_10_START         0x0000A000
+#define SECTOR_11_START         0x0000B000
+#define SECTOR_12_START         0x0000C000
+#define SECTOR_13_START         0x0000D000
+#define SECTOR_14_START         0x0000E000
+#define SECTOR_15_START         0x0000F000
+
+
+#define SECTOR_0_END            0x00000FFF
+#define SECTOR_1_END            0x00001FFF
+#define SECTOR_2_END            0x00002FFF
+#define SECTOR_3_END            0x00003FFF
+#define SECTOR_4_END            0x00004FFF
+#define SECTOR_5_END            0x00005FFF
+#define SECTOR_6_END            0x00006FFF
+#define SECTOR_7_END            0x00007FFF
+#define SECTOR_8_END            0x00008FFF
+#define SECTOR_9_END            0x00009FFF
+#define SECTOR_10_END           0x0000AFFF
+#define SECTOR_11_END           0x0000BFFF
+#define SECTOR_12_END           0x0000CFFF
+#define SECTOR_13_END           0x0000DFFF
+#define SECTOR_14_END           0x0000EFFF
+#define SECTOR_15_END           0x0000FFFF
+
+#define CCLK 72000              /* 72,000 KHz for IAP call WiFI Dip and M3 - TODO : Addjust for M0*/
+
+#define FLASH_BUF_SIZE          256
+#define SECTOR_0_START_ADDR     0
+#define SECTOR_SIZE             4096
+#define MAX_USER_SECTOR         16
+#define PAGES_PER_SECTOR        16
+
+//extern const unsigned sector_start_map[];
+//extern const unsigned sector_end_map[];
+extern const unsigned crp;
+
+unsigned write_flash(unsigned * dst, char * src, unsigned no_of_bytes);
+void erase_user_flash(void);
+void IAP_Init(void);
+int IAP_CheckForUserCode(void);
+int IAP_WritePage (unsigned * dst, char * src, unsigned no_of_bytes);
+void IAP_Eeprom_Write ( uint32_t eeAddress, uint8_t* buffAddress, uint32_t byteCount );
+void IAP_Eeprom_Read ( uint32_t eeAddress, uint8_t* buffAddress, uint32_t byteCount );
+
+typedef enum
+{
+PREPARE_SECTOR_FOR_WRITE=50,
+COPY_RAM_TO_FLASH=51,
+ERASE_SECTOR=52,
+BLANK_CHECK_SECTOR=53,
+READ_PART_ID=54,
+READ_BOOT_VER=55,
+COMPARE=56,
+REINVOKE_ISP=57,
+ERASE_PAGE=59,
+EEPROM_WRITE=61,
+EEPROM_READ=62,
+
+}IAP_Command_Code;
+
+#define CMD_SUCCESS 0
+#define IAP_ADDRESS 0x1FFF1FF1
+
+#define UPDATE_REQD 133
+
+#endif /* _SBL_IAP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IV18Display.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,178 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#include "IV18Display.h"
+#include "prefs.h"
+
+uint8_t calculate_segments_7(uint8_t character);
+
+IV18Display::IV18Display(PinName data, PinName clock, PinName latch, PinName blank)
+  : VFDDisplay(data, clock, latch, blank, 8)
+{
+    m_reverse_display = true;
+    m_multiplex_limit = 8; // fixme: set to 8 to run . and - digit
+    m_has_dots = true;
+    
+    printf(" Akafugu");
+}
+
+// Writes to the HV5812 driver for IV-18
+// HV1~10:  Digit grids, 10 bits
+// HV11~18: VFD segments, 8 bits
+// HV19~20: NC
+void IV18Display::writeDisplay(uint8_t digit, uint16_t segments)
+{
+  if (digit < 8 && m_dots & (1<<digit))
+    segments |= (1<<7); // DP is at bit 7
+  
+  uint32_t val = (1 << digit) | ((uint32_t)segments << 10);
+
+  writeHV5812(0); // unused upper byte: for HV518P compatibility
+  writeHV5812(val >> 16);
+  writeHV5812(val >> 8);
+  writeHV5812(val);
+  
+  m_latch = 1;
+  m_latch = 0;
+}
+
+uint16_t IV18Display::calculateSegments(char c, uint8_t digit)
+{
+    if (digit == 8) {
+        uint16_t ret = 0;
+        if (m_alarm_indicator)
+            ret |= (1<<7);
+        if (m_gps_indicator)
+            ret |= (1<<6);
+        return ret;
+    }
+    else {
+        return calculate_segments_7(c);
+    }
+}
+
+/*
+void IV18Display::printTime(time_t t, uint8_t hundredths) {
+    struct tm *tmp = localtime(&t);
+    if (tmp == NULL) return;
+    
+    char buf[16];
+
+    if (m_mode == Short) {
+        strftime(buf, 16, " %H.%M.%S ", tmp);
+    }
+    else if (m_mode == Extra) {
+        strftime(buf, 16, "%H.%M.%S", tmp);        
+    }
+    else {
+        strftime(buf, 16, "%H-%M-%S", tmp);
+    }
+    
+    if (m_mode == Extra)
+        printf("%s.%d", buf, hundredths-1);
+    else
+        printf(buf);
+}
+*/
+
+void IV18Display::printTime(struct tm* tm, uint8_t hundredths) {
+    char buf[16];
+    
+    PrefsData* prefs = get_prefs();
+    
+    if (!prefs->prefs.disp_24h && tm->tm_hour >= 12) { // set dot for PM
+        m_gps_indicator = true;
+    }
+    else {
+        m_gps_indicator = false;
+    }
+
+    if (m_mode == Short && prefs->prefs.disp_24h) {
+        strftime(buf, 16, " %H.%M.%S ", tm);
+    }
+    else if (m_mode == Short) {
+        strftime(buf, 16, " %I.%M.%S ", tm);        
+    }
+    else if (m_mode == Extra && prefs->prefs.disp_24h) {
+        strftime(buf, 16, "%H.%M.%S", tm);        
+    }
+    else if (m_mode == Extra) {
+        strftime(buf, 16, "%I.%M.%S", tm);        
+    }
+    else if (prefs->prefs.disp_24h) {
+        strftime(buf, 16, "%H-%M-%S", tm);    
+    }
+    else {
+        strftime(buf, 16, "%I-%M-%S", tm);
+    }
+    
+    if (m_mode == Extra)
+        printf("%s.%d", buf, hundredths-1);
+    else
+        printf(buf);    
+}
+
+void IV18Display::printTimeLong(struct tm* tm, uint8_t hundredths) {
+    char buf[48];
+
+    if (m_mode == Short || m_mode == Extra) {
+        strftime(buf, 48, " %H%M%S %A %B %d %Y", tm);
+    }
+    else {
+        strftime(buf, 48, "%H-%M-%S %A %B %d %Y", tm);
+    }
+    
+    printf(buf);    
+}
+
+void IV18Display::printTimeSet(struct tm* tm, bool showSeconds) {
+        char buf[16];
+        if (showSeconds) {
+                strftime(buf, 16, "%H-%M-%S", tm);
+        }
+        else {
+                strftime(buf, 16, "AL %H-%M", tm);
+        }
+        printf(buf); 
+}
+
+void IV18Display::printDate(struct tm* tm) {
+    char buf[16];
+    strftime(buf, 16, "%F", tm);
+    printf(buf);
+}
+
+void IV18Display::handleBlink(char d) {
+        // fixme: blink should be handled in virtual function in IV18Display
+    if (m_display_on)
+        writeDisplay(m_multiplex_counter, calculateSegments(d, m_multiplex_counter));
+    else {
+            if (m_blink_mode == Seconds && m_multiplex_counter <= 1) {
+        writeDisplay(m_multiplex_counter, 0);               
+            }
+            else if (m_blink_mode == Minutes && m_multiplex_counter >= 3 && m_multiplex_counter <= 4) {
+        writeDisplay(m_multiplex_counter, 0);               
+            }
+            else if (m_blink_mode == Hours && m_multiplex_counter >= 6 && m_multiplex_counter <= 7) {
+        writeDisplay(m_multiplex_counter, 0);               
+            }
+            else if (m_blink_mode == Full) {
+        writeDisplay(m_multiplex_counter, 0);               
+            }
+            else {
+        writeDisplay(m_multiplex_counter, calculateSegments(d, m_multiplex_counter));
+            }
+        }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/IV18Display.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,40 @@
+/*
+ * VFDDeluxe / Simpleclock VFD - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+
+#ifndef __IV18_DISPLAY_H_
+#define __IV18_DISPLAY_H_
+
+#include "mbed.h"
+#include "VFDDisplay.h"
+
+class IV18Display : public VFDDisplay
+{
+public:
+    IV18Display(PinName data, PinName clock, PinName latch, PinName blank);
+    
+    virtual void writeDisplay(uint8_t digit, uint16_t segments);
+    //virtual void printTime(time_t t, uint8_t hundredths);
+    virtual void printTime(struct tm* tm, uint8_t hundredths);
+    virtual void printTimeLong(struct tm* tm, uint8_t hundredths);
+    virtual void printTimeSet(struct tm* tm, bool showSeconds = true);
+    virtual void printDate(struct tm* tm);
+
+private:
+    virtual uint16_t calculateSegments(char c, uint8_t digit);
+    virtual void handleBlink(char d);
+};
+    
+#endif // __IV18_DISPLAY_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RTC/ds1302.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,189 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#include "global.h"
+#include "ds1302.h"
+
+DS1302::DS1302(PinName sclk, PinName io, PinName rst)
+ : m_sclk(sclk)
+ , m_io(io)
+ , m_rst(rst)
+{
+}
+
+void DS1302::begin()
+{
+    uint8_t x;
+    
+    m_rst = 0;
+    wait_us(2);
+    m_sclk = 0;
+    
+    write_byte(0x8e,0);
+    write_byte(0x90,0xa4);
+    
+    x=read_byte(0x81);
+    
+    if((x & 0x80) != 0) // start oscillator
+        write_byte(0x80,0);
+}
+
+
+time_t DS1302::time()
+{
+    return m_time;
+}
+
+struct tm* DS1302::getTime()
+{    
+    m_tm.tm_sec  = bcd2dec(read_byte(0x81));
+    m_tm.tm_min  = bcd2dec(read_byte(0x83));
+    m_tm.tm_hour = bcd2dec(read_byte(0x84));
+
+    return &m_tm;    
+}
+
+void DS1302::getTime(uint8_t* hour, uint8_t* min, uint8_t* sec)
+{
+    if (sec)  *sec =  bcd2dec(read_byte(0x81));
+    if (min)  *min =  bcd2dec(read_byte(0x83));
+    if (hour) *hour = bcd2dec(read_byte(0x84));
+}
+
+void DS1302::setTime(time_t t)
+{
+}
+
+void DS1302::setTime(uint8_t hour, uint8_t min, uint8_t sec)
+{   
+    write_byte(0x84, dec2bcd(hour));
+    write_byte(0x82, dec2bcd(min));
+    write_byte(0x80, dec2bcd(sec));
+}
+
+void DS1302::setTime(struct tm* tm)
+{
+/*
+    write_byte(0x86, dec2bcd(day));
+    write_byte(0x88, dec2bcd(month));
+    write_byte(0x8c, dec2bcd(year));
+    write_byte(0x8a, dec2bcd(dayofweek));
+    write_byte(0x84, dec2bcd(hour));
+    write_byte(0x82, dec2bcd(min));
+    write_byte(0x80, dec2bcd(sec));
+
+void ds1302::set_datetime(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE min)
+{
+    write(0x86,get_bcd(day));
+    write(0x88,get_bcd(mth));
+    write(0x8c,get_bcd(year));
+    write(0x8a,get_bcd(dow));
+    write(0x84,get_bcd(hr));
+    write(0x82,get_bcd(min));
+    write(0x80,get_bcd(0));
+}
+*/
+}
+
+void DS1302::setAlarm(time_t t)
+{
+}
+
+void DS1302::setAlarm(uint8_t hour, uint8_t min, uint8_t sec)
+{
+}
+
+struct tm* DS1302::getAlarm(void)
+{
+    return 0;
+}
+
+void DS1302::getAlarm(uint8_t* hour, uint8_t* min, uint8_t* sec)
+{
+}
+
+bool DS1302::checkAlarm(void)
+{
+    return false;
+}
+
+void DS1302::SQWEnable(bool enable)
+{
+}
+
+void DS1302::SQWSetFreq(enum RTC_SQW_FREQ freq)
+{
+}
+
+uint8_t DS1302::read_byte(uint8_t cmd)
+{
+    uint8_t data=0;
+    
+    m_rst = 1;
+    write_byte(cmd);
+    
+    m_io.input();
+    wait_us(1);
+    
+    for (uint8_t i = 0; i <= 7; i++)
+    {
+       data += m_io<<i;
+       m_sclk = 1;
+       wait_us(1);
+       m_sclk = 0;
+       wait_us(1);
+    }
+    
+    m_rst = 0;
+    
+    return data;
+}
+
+void DS1302::write_byte(uint8_t cmd, uint8_t data)
+{
+    m_rst = 1;
+    wait_us(1);
+    
+    write_byte(cmd);
+    write_byte(data);
+    
+    m_rst = 0;
+}
+
+void DS1302::write_byte(uint8_t cmd)
+{
+    m_io.output();
+    
+    for (uint8_t i=0; i<=7; i++)
+    {
+        m_io = (cmd >> i) & 0x01;
+        wait_us(1);
+        m_sclk = 1;
+        wait_us(1);
+        m_sclk = 0;
+    }
+    
+    m_io.input();
+}
+
+void DS1302::writeRam(uint8_t addr, uint8_t data)
+{
+    write_byte(addr|0xC0, data);
+}
+
+uint8_t DS1302::readRam(uint8_t addr)
+{
+    return read_byte(addr|0xC1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RTC/ds1302.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,58 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#ifndef __DS1302_H_
+#define __DS1302_H_
+
+#include "rtc.h"
+
+class DS1302 : public RTC {
+public:
+    DS1302(PinName sclk, PinName io, PinName rst);    
+
+    virtual void begin();
+    
+    virtual time_t time();
+    virtual struct tm* getTime();
+    virtual void getTime(uint8_t* hour, uint8_t* min, uint8_t* sec);
+
+    virtual void setTime(time_t t);
+    virtual void setTime(struct tm* tm);
+    virtual void setTime(uint8_t hour, uint8_t min, uint8_t sec);
+
+    virtual void setAlarm(time_t t);
+    virtual void setAlarm(uint8_t hour, uint8_t min, uint8_t sec);
+    virtual struct tm* getAlarm(void);
+    virtual void getAlarm(uint8_t* hour, uint8_t* min, uint8_t* sec);
+    virtual bool checkAlarm(void);
+    
+    virtual void SQWEnable(bool enable);
+    virtual void SQWSetFreq(enum RTC_SQW_FREQ freq);
+
+private:
+    DigitalOut m_sclk;
+    DigitalInOut m_io;
+    DigitalOut m_rst;
+    
+    uint8_t read_byte(uint8_t cmd);
+    void write_byte(uint8_t cmd, uint8_t data);
+    void write_byte(uint8_t cmd);
+    
+    void writeRam(uint8_t addr, uint8_t data);
+    uint8_t readRam(uint8_t addr);
+};
+
+
+#endif // __DS1302_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RTC/ds3231m.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,225 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#include "global.h"
+#include "ds3231m.h"
+
+#define DS3231M_SLAVE_ADDR 0xD0
+
+DS3231M::DS3231M(I2C& i2c)
+ : RTC()
+ , m_i2c(i2c)
+{
+    m_i2c.frequency(100000);    
+}
+
+void DS3231M::begin()
+{
+}
+
+time_t DS3231M::time()
+{
+    return m_time;
+}
+
+struct tm* DS3231M::getTime()
+{
+    char rtc[7];
+    
+    rtc[0] = 0; // second register, 0
+    int w = m_i2c.write(DS3231M_SLAVE_ADDR, rtc, 1);
+    int r = m_i2c.read(DS3231M_SLAVE_ADDR, rtc, 7);
+    
+    // Clear clock halt bit from read data
+    //rtc[0] &= ~(_BV(CH_BIT));
+    
+    m_tm.tm_sec  = bcd2dec(rtc[0]);
+    m_tm.tm_min  = bcd2dec(rtc[1]);
+    m_tm.tm_hour = bcd2dec(rtc[2]);
+    m_tm.tm_wday = bcd2dec(rtc[3])-1;
+    m_tm.tm_mday = bcd2dec(rtc[4]);
+    m_tm.tm_mon  = bcd2dec(rtc[5])-1; // tm_mon is 0-11
+    m_tm.tm_year = bcd2dec(rtc[6]);
+    
+    return &m_tm;    
+}
+
+void DS3231M::getTime(uint8_t* hour, uint8_t* min, uint8_t* sec)
+{
+    char rtc[3];
+    
+    rtc[0] = 0; // second register, 0
+    int w = m_i2c.write(DS3231M_SLAVE_ADDR, rtc, 1);
+    int r = m_i2c.read(DS3231M_SLAVE_ADDR, rtc, 3);
+    
+    // Clear clock halt bit from read data
+    //rtc[0] &= ~(_BV(CH_BIT));
+    
+    if (sec)  *sec =  bcd2dec(rtc[0]);
+    if (min)  *min =  bcd2dec(rtc[1]);
+    if (hour) *hour = bcd2dec(rtc[2]);
+}
+
+void DS3231M::setTime(time_t t)
+{
+    struct tm * timeinfo;
+    timeinfo = localtime (&t);
+    setTime(timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
+}
+
+void DS3231M::setTime(uint8_t hour, uint8_t min, uint8_t sec)
+{
+    write_byte(dec2bcd(sec), 0);
+    write_byte(dec2bcd(min), 1);
+    write_byte(dec2bcd(hour), 2);
+}
+
+void DS3231M::setTime(struct tm* tm)
+{
+    write_byte(dec2bcd(tm->tm_sec),  0);
+    write_byte(dec2bcd(tm->tm_min),  1);
+    write_byte(dec2bcd(tm->tm_hour), 2);
+    write_byte(dec2bcd(tm->tm_wday+1),  3);
+    write_byte(dec2bcd(tm->tm_mday),  4);
+    write_byte(dec2bcd(tm->tm_mon+1), 5);
+    write_byte(dec2bcd(tm->tm_year),  6);
+}
+
+void DS3231M::setAlarm(time_t t)
+{
+    struct tm * timeinfo;
+    timeinfo = localtime (&t);
+    setAlarm(timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
+}
+
+void DS3231M::setAlarm(uint8_t hour, uint8_t min, uint8_t sec)
+{
+    /*
+     *  07h: A1M1:0  Alarm 1 seconds
+     *  08h: A1M2:0  Alarm 1 minutes
+     *  09h: A1M3:0  Alarm 1 hour (bit6 is am/pm flag in 12h mode)
+     *  0ah: A1M4:1  Alarm 1 day/date (bit6: 1 for day, 0 for date)
+     *  Sets alarm to fire when hour, minute and second matches
+     */
+    write_byte(dec2bcd(sec), 0x07); // second
+    write_byte(dec2bcd(min), 0x08); // minute
+    write_byte(dec2bcd(hour), 0x09); // hour
+    write_byte(0x81, 0x0a); // day (upper bit must be set)
+    
+    // clear alarm flag
+    uint8_t val = read_byte(0x0f);
+    write_byte(val & ~0x01, 0x0f);
+}
+
+
+struct tm* DS3231M::getAlarm(void)
+{
+    struct tm * timeinfo = getTime();
+    uint8_t hour, min, sec;
+    
+    getAlarm(&hour, &min, &sec);
+    timeinfo->tm_hour = hour;
+    timeinfo->tm_min = min;
+    timeinfo->tm_sec = sec;
+    return timeinfo;
+}
+
+void DS3231M::getAlarm(uint8_t* hour, uint8_t* min, uint8_t* sec)
+{
+    *sec  = bcd2dec(read_byte(0x07) & ~0x80);
+    *min  = bcd2dec(read_byte(0x08) & ~0x80);
+    *hour = bcd2dec(read_byte(0x09) & ~0x80);
+}
+
+bool DS3231M::checkAlarm(void)
+{
+    // Alarm 1 flag (A1F) in bit 0
+    uint8_t val = read_byte(0x0f);
+
+    // clear flag when set
+    if (val & 1)
+        write_byte(val & ~0x01, 0x0f);
+        
+    return val & 1 ? 1 : 0;
+}
+
+void DS3231M::SQWEnable(bool enable)
+{
+    uint8_t control = read_byte(0x0E);  // read control register
+    if (enable) {
+        control |=  0x40; // set BBSQW to 1
+        control &= ~0x04; // set INTCN to 0
+    }
+    else {
+        control &= ~0x40; // set BBSQW to 0
+    }
+    // write control back
+    write_byte(control, 0x0E);
+}
+
+void DS3231M::SQWSetFreq(enum RTC_SQW_FREQ freq)
+{
+    uint8_t control = read_byte(0x0E);  // read control register
+    control &= ~0x18; // Set to 0
+    control |= (freq << 4); // Set freq bitmask
+
+    // write control back
+    write_byte(control, 0x0E);
+}
+
+void DS3231M::Osc32kHzEnable(bool enable)
+{
+    uint8_t status = read_byte(0x0F);  // read status
+
+    if (enable)
+        status |= 0x08; // set to 1
+    else
+        status &= ~0x08; // Set to 0
+
+    // write status back
+    write_byte(status, 0x0F);
+}
+
+uint8_t DS3231M::read_byte(uint8_t offset)
+{
+    char buf[1];
+    buf[0] = offset;
+    
+    int w = m_i2c.write(DS3231M_SLAVE_ADDR, buf, 1);
+    int r = m_i2c.read(DS3231M_SLAVE_ADDR,  buf, 1);    
+    //error = ((w!=0) || (r!=0));
+    
+    return buf[0];
+}
+
+void DS3231M::write_byte(uint8_t b, uint8_t offset)
+{
+    char buf[2];
+    buf[0] = offset;
+    buf[1] = b;
+    
+    int w = m_i2c.write(DS3231M_SLAVE_ADDR, buf, 2); 
+    //error=(w!=0);   
+}
+
+void DS3231M::write_addr(uint8_t addr)
+{
+    /*
+    Wire.beginTransmission(RTC_ADDR);
+    Wire.write(addr);
+    Wire.endTransmission();
+    */
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RTC/ds3231m.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,67 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#ifndef __DS3231M_H_
+#define __DS3231M_H_
+
+#include "rtc.h"
+
+// leap year calulator expects year argument as years offset from 1970
+#define LEAP_YEAR(Y)     ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) )
+/* Useful Constants */
+#define SECS_PER_MIN  (60UL)
+#define SECS_PER_HOUR (3600UL)
+#define SECS_PER_DAY  (SECS_PER_HOUR * 24UL)
+#define DAYS_PER_WEEK (7UL)
+#define SECS_PER_WEEK (SECS_PER_DAY * DAYS_PER_WEEK)
+#define SECS_PER_YEAR (SECS_PER_WEEK * 52UL)
+#define SECS_YR_2000  (946684800UL) // the time at the start of y2k
+
+class DS3231M : public RTC {
+public:
+    DS3231M(I2C& i2c);
+    
+    virtual void begin();
+    
+    virtual time_t time();
+    virtual struct tm* getTime();
+    virtual void getTime(uint8_t* hour, uint8_t* min, uint8_t* sec);
+
+    virtual void setTime(time_t t);
+    virtual void setTime(struct tm* tm);
+    virtual void setTime(uint8_t hour, uint8_t min, uint8_t sec);
+
+    virtual void setAlarm(time_t t);
+    virtual void setAlarm(uint8_t hour, uint8_t min, uint8_t sec);
+    virtual struct tm* getAlarm(void);
+    virtual void getAlarm(uint8_t* hour, uint8_t* min, uint8_t* sec);
+    virtual bool checkAlarm(void);
+    
+    virtual void SQWEnable(bool enable);
+    virtual void SQWSetFreq(enum RTC_SQW_FREQ freq);
+    virtual void Osc32kHzEnable(bool enable);
+
+private:
+    I2C& m_i2c;
+
+    bool m_is_ds1307;
+    bool m_is_ds3231;
+
+    uint8_t read_byte(uint8_t offset);
+    void write_byte(uint8_t b, uint8_t offset);
+    void write_addr(uint8_t addr);
+};
+
+#endif // __DS3231M_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RTC/rtc.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,107 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#include "global.h"
+#include "rtc.h"
+
+RTC::RTC() : m_time(1388534400+40000+60)
+{
+    m_tenths = 0;
+}
+
+void RTC::begin()
+{
+}
+
+void RTC::tick()
+{
+    m_time++;
+    m_tenths = 0;
+}
+
+void RTC::tenth_tick()
+{
+    m_tenths++;    
+}
+
+time_t RTC::time()
+{
+    return m_time;
+}
+
+struct tm* RTC::getTime()
+{
+    struct tm *tmp = localtime(&m_time);     
+    return tmp;
+}
+
+void RTC::getTime(uint8_t* hour, uint8_t* min, uint8_t* sec)
+{
+
+}
+
+void RTC::setTime(time_t t)
+{
+    m_time = t;
+}
+
+void RTC::setTime(uint8_t hour, uint8_t min, uint8_t sec)
+{
+}
+
+void RTC::setTime(struct tm* tm)
+{
+}
+
+void RTC::setAlarm(time_t t)
+{
+}
+
+void RTC::setAlarm(uint8_t hour, uint8_t min, uint8_t sec)
+{
+}
+
+struct tm* RTC::getAlarm(void)
+{
+    return 0;
+}
+
+void RTC::getAlarm(uint8_t* hour, uint8_t* min, uint8_t* sec)
+{
+}
+
+bool RTC::checkAlarm(void)
+{
+    return false;
+}
+
+void RTC::SQWEnable(bool enable)
+{
+}
+
+void RTC::SQWSetFreq(enum RTC_SQW_FREQ freq)
+{
+}
+
+uint8_t RTC::dec2bcd(uint8_t d)
+{
+    return ((d/10 * 16) + (d % 10));
+}
+
+uint8_t RTC::bcd2dec(uint8_t d)
+{
+    return(((d&0xF0)>>4) * 10 + (d&0x0F));
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RTC/rtc.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,61 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#ifndef __RTC_H_
+#define __RTC_H_
+
+#include "mbed.h"
+
+class RTC {
+protected:
+    struct tm m_tm;
+    time_t m_time;
+    uint8_t m_tenths;
+
+public:
+    RTC();
+    
+    enum RTC_SQW_FREQ { FREQ_1 = 0, FREQ_1024, FREQ_4096, FREQ_8192 };
+    
+    virtual void begin();
+
+    void tick();
+    void tenth_tick();
+
+    virtual time_t time();
+    virtual struct tm* getTime();
+    virtual void getTime(uint8_t* hour, uint8_t* min, uint8_t* sec);
+
+    virtual void setTime(time_t t);
+    virtual void setTime(uint8_t hour, uint8_t min, uint8_t sec);
+    virtual void setTime(struct tm* tm);
+
+    virtual void setAlarm(time_t t);
+    virtual void setAlarm(uint8_t hour, uint8_t min, uint8_t sec);
+    virtual struct tm* getAlarm(void);
+    virtual void getAlarm(uint8_t* hour, uint8_t* min, uint8_t* sec);
+    virtual bool checkAlarm(void);
+    
+    virtual void SQWEnable(bool enable);
+    virtual void SQWSetFreq(enum RTC_SQW_FREQ freq);
+    
+    uint8_t getTenths() { return m_tenths; }
+    
+protected:
+     uint8_t bcd2dec(uint8_t d);
+     uint8_t dec2bcd(uint8_t d);
+};
+
+#endif // __RTC_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/VFDDisplay.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,232 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#include "VFDDisplay.h"
+#include <stdarg.h>
+
+#define sbi(a, b) (a) |= (1 << (b))
+#define cbi(a, b) (a) &= ~(1 << (b))
+
+uint8_t calculate_segments_7(uint8_t character);
+
+VFDDisplay::VFDDisplay(PinName data, PinName clock, PinName latch, PinName blank, uint8_t digits)
+        : m_mode(Long)
+                , m_blink_mode(Full)
+        , m_data(data)
+        , m_clock(clock)
+        , m_latch(latch)
+        , m_blank(blank)
+        , m_digits(digits)
+        , m_multiplex_counter(0)
+        , m_position(0)
+        , m_scroll_offset(0)
+        , m_message_length(0)
+        , m_blink(false)
+        , m_display_on(true)
+        , m_brightness(10)
+{
+    //m_blank.period_ms(1);
+    //m_blank = 0.0;
+    m_blank = 0;
+}
+
+void VFDDisplay::cls()
+{
+    memset(m_buffer, ' ', MESSAGE_LIMIT);
+    memset(m_char_buffer, ' ', MESSAGE_LIMIT);
+    memset(m_dot_buffer, ' ', MESSAGE_LIMIT);
+    m_position = 0;
+    m_scroll_offset = 0;
+    m_message_length = 0;
+}
+
+void VFDDisplay::setPosition(uint8_t pos)
+{
+    m_position = pos;
+    if (m_position >= MESSAGE_LIMIT)
+        m_position = MESSAGE_LIMIT-1;
+}
+
+// Write 8 bits to HV5812 driver
+void VFDDisplay::writeHV5812(uint8_t data)
+{
+    // shift out MSB first
+    for (uint8_t i = 0; i < 8; i++)  {
+        if (!!(data & (1 << (7 - i))))
+            m_data = 1;
+        else
+            m_data = 0;
+
+        m_clock = 1;
+        m_clock = 0;
+    }
+}
+
+const uint32_t BLINK_OFF_TIMER = 200;
+const uint32_t BLINK_ON_TIMER = 350;
+volatile uint32_t blink_countdown = BLINK_ON_TIMER;
+
+extern DigitalOut led;
+
+void VFDDisplay::multiplexTick()
+{
+    char d;
+    
+    if (m_reverse_display)
+        d = m_char_buffer[m_digits - m_multiplex_counter - 1 + m_scroll_offset];
+    else
+        d = m_char_buffer[m_multiplex_counter + m_scroll_offset];
+
+    // fixme: does not work properly when scrolling
+    if (m_dot_buffer[m_multiplex_counter + m_scroll_offset - 1] == '.')
+        setDot(m_multiplex_counter, true);
+    else
+        setDot(m_multiplex_counter, false);
+
+    if (m_blink) {
+        blink_countdown--;
+        
+        if (blink_countdown == 0) {
+            m_display_on = !m_display_on;
+
+            if (m_display_on)
+                blink_countdown = BLINK_ON_TIMER;
+            else  
+                blink_countdown = BLINK_OFF_TIMER;
+        }
+    }
+        
+        handleBlink(d);
+            
+    m_multiplex_counter++;  
+    if (m_multiplex_counter > m_multiplex_limit)
+        m_multiplex_counter = 0;
+}
+
+int VFDDisplay::printf(const char* format, ...)
+{
+    va_list ap;
+    va_start(ap, format);
+    int ret = vsnprintf(m_buffer, MESSAGE_LIMIT, format, ap);
+    va_end(ap);
+    
+    // post-processing for seamless dot support
+    // splits buffer into two: one that contains characters
+    // and one that contains dots
+    uint8_t pos = 0;
+    
+    char* temp = m_buffer;
+    
+    while (*temp) {
+        if (*temp == '.') {
+            if (pos > 0) m_dot_buffer[pos-1] = '.';
+            temp++;   
+        }
+        else {
+            m_dot_buffer[pos] = ' ';
+            m_char_buffer[pos++] = *temp;
+            temp++;    
+        }
+    }
+      
+    /*    
+    for (uint8_t i = 0; i < strlen(m_buffer); i++) {
+        char c = m_buffer[i];
+        
+        if (c == '.') {
+            m_dot_buffer[pos-1] = '.';
+            //m_char_buffer[pos++] = c;
+            i++;
+        }
+        else {
+            m_dot_buffer[pos] = ' ';
+            m_char_buffer[pos++] = c;
+        }    
+    }
+    */
+    
+    m_dot_buffer[pos] = 0;
+    m_char_buffer[pos] = 0;
+    
+    m_position = ret;
+    m_message_length = strlen(m_char_buffer);
+
+    return ret;
+}
+
+int VFDDisplay::_putc(int c)
+{
+    // fixme: support dot buffer
+    m_char_buffer[m_position] = c;
+    m_buffer[m_position++] = c;
+    m_message_length++; 
+    return 1;
+}
+    
+int VFDDisplay::_getc()
+{
+    return -1;
+}
+
+void VFDDisplay::scroll(int8_t spaces /*= 1*/)
+{
+    m_scroll_offset += spaces;
+    //if (m_scroll_offset > MESSAGE_LIMIT - m_digits)
+    //    m_scroll_offset = 0;
+}
+
+void VFDDisplay::resetScroll()
+{
+    m_scroll_offset = 0;
+}
+
+bool VFDDisplay::scrollFinished()
+{
+    if (m_scroll_offset > strlen(m_char_buffer))
+        return true;
+    return false;
+}
+
+void VFDDisplay::setDot(uint8_t pos, bool on)
+{
+    if (on) {
+        sbi(m_dots, pos);
+    }
+    else {
+        cbi(m_dots, pos);
+    }
+}
+
+void VFDDisplay::toggleTimeMode()
+{
+    if (m_mode == Short) m_mode = Extra;
+    else if (m_mode == Extra) m_mode = Long;
+    else m_mode = Short;
+}
+
+void VFDDisplay::setBrightness(uint8_t brite)
+{
+    if (brite > 10) brite = 10;
+    m_brightness = brite;
+}
+
+uint8_t VFDDisplay::incBrightness()
+{
+    float f = m_blank;
+    if (f >= 0.9) f = 0.0;
+    f+= 0.1;
+    m_blank = f;
+    return f*10;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/VFDDisplay.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,129 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#ifndef __VFDDISPLAY_H_
+#define __VFDDISPLAY_H_
+
+#include "mbed.h"
+
+#define MESSAGE_LIMIT 96
+
+class VFDDisplay : public Stream {
+public:
+    enum TimeMode {
+        Long = 0,
+        Short,
+        Extra 
+    };
+    
+    // Controls how display blinks when m_blink is true
+    enum BlinkMode {
+        Full = 0, // Blink whole display
+        Hours,    // Blink hours
+        Minutes,  // Blink minutes
+        Seconds   // Blink seconds
+    };
+    
+protected:
+    TimeMode m_mode;
+    BlinkMode m_blink_mode;
+    
+public:
+    VFDDisplay(PinName data, PinName clock, PinName latch, PinName blank, uint8_t digits);
+
+    virtual void cls();
+    virtual void setPosition(uint8_t pos);
+    
+    virtual int putc(int c) { return _putc(c); }
+    int printf(const char* format, ...);
+
+    void scroll(int8_t spaces = 1);
+    void resetScroll();
+    bool scrollFinished();
+    bool scrollAtOrigin() { return m_scroll_offset == 0; }
+
+    void setAlarmIndicator(bool on) { m_alarm_indicator = on; }
+    void setGPSIndicator(bool on)   { m_gps_indicator   = on; }
+    void setColon(bool on)          { m_colon = on; }
+    
+    void setDots(uint16_t dots) { m_dots = dots; }
+    void setDot(uint8_t pos, bool on);
+
+    void setTimeMode(TimeMode mode) { m_mode = mode; }
+    void toggleTimeMode();
+    
+    //virtual void printTime(time_t t, uint8_t hundredths) = 0;
+    virtual void printTime(struct tm* tm, uint8_t hundredths) = 0;
+    virtual void printTimeLong(struct tm* tm, uint8_t hundredths) = 0;
+    virtual void printTimeSet(struct tm* tm, bool showSeconds = true) = 0;
+    virtual void printDate(struct tm* tm) = 0;
+    
+    void setBrightness(uint8_t brite);
+    uint8_t getBrightness() { return m_brightness; }
+    uint8_t incBrightness();
+
+    uint8_t digits() { return m_digits; }
+    
+    void setBlinkMode(BlinkMode blink_mode) { m_blink_mode = blink_mode; }
+    void blink(bool b) { m_blink = b; m_display_on = true; }
+    void blank(bool b) { m_blank = b; }    
+    
+protected:
+    DigitalOut m_data;
+    DigitalOut m_clock;
+    DigitalOut m_latch;
+    //PwmOut m_blank;
+    DigitalOut m_blank;
+
+    uint8_t m_digits;
+    uint8_t m_multiplex_limit;
+    uint8_t m_multiplex_counter;
+    bool m_reverse_display;
+    uint8_t m_position;
+    int8_t m_scroll_offset;
+    uint8_t m_message_length;
+    bool m_has_dots;
+
+    char m_buffer[MESSAGE_LIMIT];
+    char m_dot_buffer[MESSAGE_LIMIT];
+    char m_char_buffer[MESSAGE_LIMIT];
+        
+    void writeHV5812(uint8_t data);
+    virtual uint16_t calculateSegments(char c, uint8_t digit) = 0;
+    virtual void handleBlink(char d) = 0;
+    
+    // extra indicators (not present on all displays
+    bool m_alarm_indicator;
+    bool m_gps_indicator;
+    bool m_colon;
+    uint16_t m_dots;
+    
+    // display blinking
+    volatile bool m_blink;
+    volatile bool m_display_on;
+    
+    // brightness
+    uint8_t m_brightness;
+
+public:
+    virtual void writeDisplay(uint8_t digit, uint16_t segments) = 0;
+    void multiplexTick();
+            
+protected:
+    virtual int _putc(int c);
+    virtual int _getc();
+};
+
+#endif // __VFDDISPLAY_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/_24LCXXX.lib	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/bant62/code/_24LCXXX/#859387a87312
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/beep/beep.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,163 @@
+#include "beep.h"
+#include "mbed.h"
+
+/** class to make sound with a buzzer, based on a PwmOut
+ *   The class use a timeout to switch off the sound  - it is not blocking while making noise
+ *
+ * Example:
+ * @code
+ * // Beep with 1Khz for 0.5 seconds
+ * #include 'mbed.h'
+ * #include 'beep.h'
+ * 
+ * Beep buzzer(p21);
+ * 
+ * int main() {
+ *       ...
+ *   buzzer.beep(1000,0.5);    
+ *       ...
+ * }
+ * @endcode
+ */
+
+//using namespace mbed;
+ // constructor
+ /** Create a Beep object connected to the specified PwmOut pin
+  *
+  * @param pin PwmOut pin to connect to 
+  */
+    
+Beep::Beep(PinName pin) : _pwm(pin) {
+    _pwm.write(0.0);     // after creating it have to be off
+}
+
+ /** stop the beep instantaneous 
+  * usually not used 
+  */
+void Beep::nobeep() {
+    _pwm.write(0.0);
+}
+
+/** Beep with given frequency and duration.
+ *
+ * @param frequency - the frequency of the tone in Hz
+ * @param time - the duration of the tone in seconds
+ */
+     
+void Beep::beep(float freq, float time) {
+
+    _pwm.period(1.0/freq);
+    _pwm.write(0.5);            // 50% duty cycle - beep on
+    toff.attach(this,&Beep::nobeep, time);   // time to off
+}
+
+#define NOTE_GB 0
+#define NOTE_EB 1
+#define NOTE_FS 2
+
+void Beep::play(char note) {
+    if (note=='a') {
+        beep(880,0.1);
+    }
+    if (note=='b') {
+        beep(987,0.1);
+    }
+    if (note=='c') {
+        beep(1024,0.1);
+    }
+    if (note=='d') {
+        beep(1175,0.1);
+    }
+    if (note=='e') {
+        beep(1319,0.1);
+    }
+    if (note=='f') {
+        beep(1397,0.1);
+    }
+    if (note=='g') {
+        beep(1568,0.1);
+    }
+
+    if (note==NOTE_GB) {
+        beep(830,0.1);
+    }
+    if (note==NOTE_EB) {
+        beep(659,0.1);
+    }
+    if (note==NOTE_FS) {
+        beep(1480,0.1);
+    }
+    if (note=='w') {
+        wait(0.05);
+    }
+    wait (0.2); //wait while the note plays.
+}
+
+void Beep::popcorn() {
+
+    play('e');
+    play('d');
+    play('e');
+    play('c');
+    play(NOTE_GB);
+    play('c');
+    play(NOTE_EB);
+    play('w');
+    play('e');
+    play('d');
+    play('e');
+    play('c');
+    play(NOTE_GB);
+    play('c');
+    play(NOTE_EB);
+    play('w');
+    play('e');
+    play(NOTE_FS);
+    play('g');
+    play(NOTE_FS);
+    play('g');
+    play('e');
+    play(NOTE_FS);
+    play('e');
+    play(NOTE_FS);
+    play('d');
+    play('e');
+    play('d');
+    play('e');
+    play('d');
+    play('e');
+    play('w');
+    play('e');
+    play('d');
+    play('e');
+    play('c');
+    play(NOTE_GB);
+    play('c');
+    play(NOTE_EB);
+    play('w');
+    play('e');
+    play('d');
+    play('e');
+    play('c');
+    play(NOTE_GB);
+    play('c');
+    play(NOTE_EB);
+    play('w');
+    play('e');
+    play(NOTE_FS);
+    play('g');
+    play(NOTE_FS);
+    play('g');
+    play('e');
+    play(NOTE_FS);
+    play('e');
+    play(NOTE_FS);
+    play('d');
+    play('e');
+    play('d');
+    play('e');
+    play('d');
+    play('g');
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/beep/beep.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,62 @@
+#ifndef MBED_BEEP_H
+#define MBED_BEEP_H
+
+#include "mbed.h"
+
+/** class to make sound with a buzzer, based on a PwmOut
+ *   The class use a timeout to switch off the sound  - it is not blocking while making noise
+ *
+ * Example:
+ * @code
+ * // Beep with 1Khz for 0.5 seconds
+ * #include "mbed.h"
+ * #include "beep.h"
+ * 
+ * Beep buzzer(p21);
+ * 
+ * int main() {
+ *        ...
+ *   buzzer.beep(1000,0.5);    
+ *       ...
+ * }
+ * @endcode
+ */
+
+
+namespace mbed {
+
+/* Class: Beep
+ *  A class witch uses pwm to controle a beeper to generate sounds.
+ */
+class Beep {
+
+public:
+
+/** Create a Beep object connected to the specified PwmOut pin
+ *
+ * @param pin PwmOut pin to connect to 
+ */
+    Beep (PinName pin);
+
+/** Beep with given frequency and duration.
+ *
+ * @param frequency - the frequency of the tone in Hz
+ * @param time - the duration of the tone in seconds
+ */
+    void beep (float frequency, float time);
+
+/** stop the beep instantaneous 
+ * usually not used 
+ */
+    void nobeep();
+    
+    void play(char note);
+    void popcorn();
+
+private :
+    PwmOut _pwm;
+    Timeout toff;
+};
+
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/button.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,122 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#include "global.h"
+#include "button.h"
+
+DigitalIn button1(PinMap::button1);
+DigitalIn button2(PinMap::button2);
+DigitalIn button3(PinMap::button3);
+
+uint8_t button_count = 3;
+
+uint8_t saved_keystatus = 0;
+uint8_t keydown_keys = 0;
+uint8_t keyup_keys = 0;
+uint8_t keyrepeat_keys = 0;
+
+uint16_t keyboard_counter[3] = {0, 0, 0};
+uint8_t button_bit[3] = { 1, 2, 4};
+
+#define REPEAT_SPEED    35
+volatile uint8_t repeat_speed = REPEAT_SPEED;
+
+void initialize_buttons()
+{
+    // enable pullups
+    button1.mode(PullUp);
+    button2.mode(PullUp);
+    button3.mode(PullUp);
+}
+
+uint8_t get_keystatus() {
+    return (!button1) | (!button2 << 1) | (!button3 << 2);
+}
+
+void button_tick()
+{
+    uint8_t keystatus = (!button1) | (!button2 << 1) | (!button3 << 2);
+
+    keydown_keys |= (uint8_t)(keystatus & ~(saved_keystatus));
+    keyup_keys   |= (uint8_t)(~(keystatus) & saved_keystatus);
+    saved_keystatus = keystatus;
+
+    for(uint8_t i = 0; i < button_count; i++) {
+        if(~(keydown_keys)&button_bit[i])
+            ; // Do nothing, no keyrepeat is needed
+        else if(keyup_keys&button_bit[i])
+            keyboard_counter[i] = 0;
+        else {
+            if(keyboard_counter[i] >= repeat_speed) {
+                keyrepeat_keys |= button_bit[i];
+                keyboard_counter[i] = 0;
+            }
+            
+            keyboard_counter[i]++;
+        }
+    }
+}
+
+void get_button_state(struct BUTTON_STATE* buttons)
+{
+    buttons->b1_keydown = keydown_keys&(button_bit[0]);
+    buttons->b1_keyup   = keyup_keys&(button_bit[0]);
+    buttons->b1_repeat  = keyrepeat_keys&(button_bit[0]);
+    
+    if (keyrepeat_keys&(button_bit[0]))
+      keyrepeat_keys &= ~(button_bit[0]);
+
+    // Reset if we got keyup
+    if(keyup_keys&(button_bit[0])) {
+        keydown_keys   &= ~(button_bit[0]);
+        keyup_keys     &= ~(button_bit[0]);
+        keyrepeat_keys &= ~(button_bit[0]);
+        keyboard_counter[0] = 0;
+    }
+
+    buttons->b2_keydown = keydown_keys&(button_bit[1]);
+    buttons->b2_keyup = keyup_keys&(button_bit[1]);
+    buttons->b2_repeat = keyrepeat_keys&(button_bit[1]);
+
+    if (keyrepeat_keys&(button_bit[1]))
+      keyrepeat_keys &= ~(button_bit[1]);
+    
+    // Reset if we got keyup
+    if(keyup_keys&(button_bit[1])) {
+        keydown_keys   &= ~(button_bit[1]);
+        keyup_keys     &= ~(button_bit[1]);
+        keyrepeat_keys &= ~(button_bit[1]);
+        keyboard_counter[1] = 0;
+    }
+
+    buttons->b3_keydown = keydown_keys&(button_bit[2]);
+    buttons->b3_keyup   = keyup_keys&(button_bit[2]);
+    buttons->b3_repeat  = keyrepeat_keys&(button_bit[2]);
+    
+    if (keyrepeat_keys&(button_bit[2]))
+      keyrepeat_keys &= ~(button_bit[2]);
+
+    // Reset if we got keyup
+    if(keyup_keys&(button_bit[2])) {
+        keydown_keys   &= ~(button_bit[2]);
+        keyup_keys     &= ~(button_bit[2]);
+        keyrepeat_keys &= ~(button_bit[2]);
+        keyboard_counter[2] = 0;
+    }
+
+    buttons->both_held = (keydown_keys&(button_bit[0])) && (keydown_keys&(button_bit[1]));
+    buttons->none_held = ~(saved_keystatus)&(button_bit[0]) && ~(saved_keystatus)&((button_bit[1]));
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/button.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,42 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#ifndef BUTTON_H_
+#define BUTTON_H_
+
+#include <stdbool.h>
+
+struct BUTTON_STATE
+{
+    bool b1_keydown : 1;
+    bool b1_keyup : 1;
+    bool b1_repeat : 1;
+    bool b2_keydown : 1;
+    bool b2_keyup : 1;
+    bool b2_repeat : 1;
+    bool b3_keydown : 1;
+    bool b3_keyup : 1;
+    bool b3_repeat : 1;
+    bool both_held : 1;
+    bool none_held : 1;
+};
+
+void initialize_buttons();
+void get_button_state(struct BUTTON_STATE* buttons);
+void button_tick(void);
+
+uint8_t get_keystatus();
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/features.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,66 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#ifndef FEATURES_H_
+#define FEATURES_H_
+
+#define YES 2
+#define NO  1
+
+///////////////////////////////////////////
+
+#if !(defined FEATURE_3BUTTON) || FEATURE_3BUTTON < NO || FEATURE_3BUTTON > YES
+#  error Must define FEATURE_3BUTTON to be YES or NO
+#endif
+
+#if FEATURE_3BUTTON == YES
+#define HAVE_3BUTTON
+#endif
+
+///////////////////////////////////////////
+
+#if !(defined FEATURE_GPS) || FEATURE_GPS < NO || FEATURE_GPS > YES
+#  error Must define FEATURE_GPS to be YES or NO
+#endif
+
+#if FEATURE_GPS == YES
+#define HAVE_GPS
+#endif
+
+///////////////////////////////////////////
+
+#if !(defined FEATURE_DS1302) || FEATURE_DS1302 < NO || FEATURE_DS1302 > YES
+#  error Must define FEATURE_DS1302 to be YES or NO
+#endif
+
+#if FEATURE_DS1302 == YES
+#define HAVE_DS1302
+#endif
+
+///////////////////////////////////////////
+
+#if !(defined FEATURE_DS3231M) || FEATURE_DS3231M < NO || FEATURE_DS3231M > YES
+#  error Must define FEATURE_DS3231M to be YES or NO
+#endif
+
+#if FEATURE_DS3231M == YES
+#define HAVE_DS3231M
+#endif
+
+#if FEATURE_DS1302 == YES && FEATURE_DS3231M == YES
+#  error Use either FEATURE_DS1202 or FEATURE_DS3231M, not both
+#endif
+
+#endif /* FEATURES_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flw/flw.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,146 @@
+/*
+ * Four Letter Word Generator
+ * (C) 2015 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+/*
+ * To use this Four Letter Word generator you will need the following:
+ *
+ * - A 512kbit/64kb I2C EEPROM
+ * - A database file, generated from this Processing application:
+ *   https://github.com/perjg/fourletterword
+ * - A method for uploading the data file to the EEPROM
+ *   (Either an Arduino Mega, or a normal Arduino with a micro SD card)
+ */
+
+#include <string.h>
+#include "flw.h"
+#include "flw_blacklist.h"
+
+
+#define EEPROM_ADDR 0b1010000
+
+void FourLetterWord::rot13(char* w)
+{
+    while (*w != '\0') {
+        if (*w >= 'A' && *w <= 'M') {
+            *w += 13;
+        }
+        else if (*w >= 'N' && *w <= 'Z') {
+            *w -= 13;
+        }
+
+      w++;
+    }
+}
+
+bool FourLetterWord::binary_search(const char *key, int imin, int imax)
+{
+  int pos;
+  int cond = 0;
+  char buf[5];
+
+  while (imin <= imax) {
+    pos = (imin+imax) / 2;
+    
+    strcpy(buf, flw_blacklist[pos]);
+    rot13(buf);
+    cond = strcmp(key, buf);
+    
+    if (cond == 0)   return true;
+    else if (cond>0) imin = pos+1;
+    else             imax = pos-1;
+  }
+  
+  return false;
+}
+
+
+uint8_t FourLetterWord::read_byte(unsigned int addr) {
+  uint8_t rdata = 0xFF;
+  
+  _24lc.nbyte_read(addr, &rdata, 1);
+  return rdata;
+}
+
+void FourLetterWord::read_buffer(unsigned int addr, uint8_t *buffer, int length) {
+  _24lc.nbyte_read(addr, buffer, length);
+}
+
+
+void FourLetterWord::begin(uint32_t seed, bool censored)
+{
+  m_lfsr = seed;
+  m_censored = censored;
+}
+
+uint32_t FourLetterWord::randomize()
+{
+  // http://en.wikipedia.org/wiki/Linear_feedback_shift_register
+  // Galois LFSR: taps: 32 31 29 1; characteristic polynomial: x^32 + x^31 + x^29 + x + 1 */
+  m_lfsr = (m_lfsr >> 1) ^ (-(m_lfsr & 1u) & 0xD0000001u);
+  return m_lfsr;  
+}
+
+bool FourLetterWord::hasEeprom()
+{
+   uint8_t b1 = read_byte(0); 
+   uint8_t b2 = read_byte(1); 
+   
+   if (b1 == 65 && b2 == 66)
+     return true;
+   return false;
+}
+
+char* FourLetterWord::get_word_censored()
+{
+  char* w = get_word_uncensored();
+  
+  // assume a maximum of 5 censored words chosen in a row
+  for (uint8_t i = 0; i < 5; i++) {
+    if (binary_search(w, 0, BLACKLIST_SIZE)) { // censored
+      w = get_word_uncensored();
+    }
+    else
+      return w;
+  }
+  
+  return w;
+}
+
+char* FourLetterWord::get_word_uncensored()
+{
+  unsigned char low = 0xFF, high = 0xFF;
+  unsigned char count = 0;
+  int next = 0;
+
+  read_buffer(m_offset, (uint8_t*)m_current_word, 5);
+  count = m_current_word[4];
+  m_current_word[4] = '\0';
+
+  next = randomize() % count;
+  m_offset += 5 + next * 2;
+
+  high = read_byte(m_offset++);
+  low  = read_byte(m_offset++);
+
+  m_offset = (high << 8) | low;
+
+  return m_current_word;
+}
+
+char* FourLetterWord::getWord()
+{
+  if (m_censored) return get_word_censored();
+  return get_word_uncensored();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flw/flw.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,59 @@
+/*
+ * Four Letter Word Generator
+ * (C) 2015 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#ifndef FLW_H__
+#define FLW_H__
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+
+#include "_24LCXXX.h"
+
+class FourLetterWord
+{
+private:
+    _24LCXXX _24lc;
+    bool m_censored;
+    unsigned long m_offset;
+    char m_current_word[6];
+    uint32_t m_lfsr;
+    
+    uint32_t randomize();
+    
+    void rot13(char* w);
+    bool binary_search(const char *key, int imin, int imax);
+    uint8_t read_byte(unsigned int addr);
+    void read_buffer(unsigned int addr, uint8_t *buffer, int length);
+    
+    char* get_word_censored();
+    char* get_word_uncensored();
+
+public:
+    FourLetterWord(I2C *i2c, uint8_t addr = 0x50) :
+      _24lc(i2c, addr),
+      m_censored(true),
+      m_offset(0),
+      m_lfsr(0xbeefcace) {}
+
+    void begin(uint32_t seed = 0xbeefcace, bool censored = true);
+    
+    void setCensored(bool c) { m_censored = c; }
+    
+    bool hasEeprom();
+    char* getWord();
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/flw/flw_blacklist.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,72 @@
+/*
+ * Four Letter Word Generator
+ * (C) 2015 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+//
+// Swear word blacklist for Four Letter Word database
+// All words are encoded using ROT13 so that the cencored words are not
+// directly visible in the file
+//
+// Must be alphabetized (according to the decrypted value!), since the
+// list is searched by binary search
+//
+
+const char word_0[]  = "NAHF";
+const char word_1[]  = "NEFR";
+const char word_2[]  = "PNJX";
+const char word_3[]  = "PYVG";
+const char word_4[]  = "PBPX";
+const char word_5[]  = "PBBA";
+const char word_6[]  = "PENC";
+const char word_7[]  = "PHAG";
+const char word_8[]  = "QNTB";
+const char word_9[]  = "QNZA";
+const char word_10[] = "QVPX";
+const char word_11[] = "QLXR";
+const char word_12[] = "SNTF";
+const char word_13[] = "SNEG";
+const char word_14[] = "SHPX";
+const char word_15[] = "TBBX";
+const char word_16[] = "URYY";
+const char word_17[] = "WRJF";
+const char word_18[] = "WVFZ";
+const char word_19[] = "WVMZ";
+const char word_20[] = "WVMM";
+const char word_21[] = "XVXR";
+const char word_22[] = "ZHSS";
+const char word_23[] = "ANMV";
+const char word_24[] = "CNXV";
+const char word_25[] = "CVFF";
+const char word_26[] = "CBBA";
+const char word_27[] = "CBBC";
+const char word_28[] = "CBEA";
+const char word_29[] = "ENCR";
+const char word_30[] = "FUVG";
+const char word_31[] = "FZHG";
+const char word_32[] = "FCVP";
+const char word_33[] = "FYHG";
+const char word_34[] = "GVGF";
+const char word_35[] = "GHEQ";
+const char word_36[] = "GJNG";
+const char word_37[] = "JNAX";
+
+#define BLACKLIST_SIZE 37
+
+const char *flw_blacklist[] =
+{   
+    word_0, word_1, word_2, word_3, word_4, word_5, word_6, word_7, word_8, word_9, 
+    word_10, word_11, word_12, word_13, word_14, word_15, word_16, word_17, word_18, word_19,
+    word_20, word_21, word_22, word_23, word_24, word_25, word_26, word_27, word_28, word_29, 
+    word_30, word_31, word_32, word_33, word_34, word_35, word_36, word_37
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/font_7seg.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,214 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#include "mbed.h"
+
+uint8_t calculate_segments_7(uint8_t character);
+
+#define A   0
+#define B   1
+#define C   2
+#define D   3
+#define E   4
+#define F   5
+#define G   6
+#define DP  7
+
+uint8_t calculate_segments_7(uint8_t character)
+{
+    uint8_t segments = 0;
+    
+    switch (character)
+    {
+        case 0:
+            segments = 0;
+            break;
+        case '0':
+        case 'O':
+            segments = (1<<A)|(1<<B)|(1<<C)|(1<<D)|(1<<E)|(1<<F);
+            break;
+        case 1:
+        case '1':
+        case 'l':
+            segments = (1<<B)|(1<<C);
+            break;
+        case 2:
+        case '2':
+            segments = (1<<A)|(1<<B)|(1<<D)|(1<<E)|(1<<G);
+            break;
+        case 3:
+        case '3':
+            segments = (1<<A)|(1<<B)|(1<<C)|(1<<D)|(1<<G);
+            break;
+        case 4:
+        case '4':
+            segments = (1<<B)|(1<<C)|(1<<F)|(1<<G);
+            break;
+        case 5:
+        case '5':
+        case 'S':
+        case 's':
+            segments = (1<<A)|(1<<C)|(1<<D)|(1<<F)|(1<<G);
+            break;
+        case 6:
+        case '6':
+            segments = (1<<A)|(1<<C)|(1<<D)|(1<<E)|(1<<F)|(1<<G);
+            break;
+        case 7:
+        case '7':
+            segments = (1<<A)|(1<<B)|(1<<C);
+            break;
+        case 8:
+        case '8':
+            segments = (1<<A)|(1<<B)|(1<<C)|(1<<D)|(1<<E)|(1<<F)|(1<<G);
+            break;
+        case 9:
+        case '9':
+        case 'g':
+            segments = (1<<A)|(1<<B)|(1<<C)|(1<<D)|(1<<F)|(1<<G);
+            break;
+        case 10:
+        case 'A':
+        case 'a':
+            segments = (1<<A)|(1<<B)|(1<<C)|(1<<E)|(1<<F)|(1<<G);
+            break;
+        case 11:
+        case 'B':
+        case 'b':
+            segments = (1<<C)|(1<<D)|(1<<E)|(1<<F)|(1<<G);
+            break;
+        case 12:
+        case 'C':
+            segments = (1<<A)|(1<<D)|(1<<E)|(1<<F);
+            break;
+        case 'c':
+            segments = (1<<D)|(1<<E)|(1<<G);
+            break;
+        case 13:
+        case 'D':
+        case 'd':
+            segments = (1<<B)|(1<<C)|(1<<D)|(1<<E)|(1<<G);
+            break;
+        case 14:
+        case 'E':
+            segments = (1<<A)|(1<<D)|(1<<E)|(1<<F)|(1<<G);
+            break;
+        case 'e':
+            segments = (1<<A)|(1<<B)|(1<<D)|(1<<E)|(1<<F)|(1<<G);
+            break;
+        case 15:
+        case 'F':
+        case 'f':
+            segments = (1<<A)|(1<<E)|(1<<F)|(1<<G);
+            break;
+        case 'G':
+            segments = (1<<A)|(1<<C)|(1<<D)|(1<<E)|(1<<F);
+            break;
+        case 'H':
+            segments = (1<<B)|(1<<C)|(1<<E)|(1<<F)|(1<<G);
+            break;
+        case 'h':
+            segments = (1<<C)|(1<<E)|(1<<F)|(1<<G);
+            break;
+        case 'I':
+            segments = (1<<B)|(1<<C);
+            break;
+        case 'i':
+            segments = (1<<C);
+            break;
+        case 'J':
+        case 'j':
+            segments = (1<<B)|(1<<C)|(1<<D)|(1<<E);
+            break;
+        case 'K':
+        case 'k':
+            segments = (1<<E)|(1<<F)|(1<<G);
+            break;
+        case 'L':
+            segments = (1<<D)|(1<<E)|(1<<F);
+            break;
+        case 'M':
+        case 'm':
+            segments = (1<<A)|(1<<C)|(1<<E)|(1<<G);
+            break;
+        case 'N':
+        case 'n':
+            segments = (1<<C)|(1<<E)|(1<<G);
+            break;
+        case 'o':
+            segments = (1<<C)|(1<<D)|(1<<E)|(1<<G);
+            break;
+        case 'P':
+        case 'p':
+            segments = (1<<A)|(1<<B)|(1<<E)|(1<<F)|(1<<G);
+            break;
+        case 'Q':
+        case 'q':
+            segments = (1<<A)|(1<<B)|(1<<C)|(1<<F)|(1<<G);
+            break;
+        case 'R':
+        case 'r':
+            segments = (1<<E)|(1<<G);
+            break;
+        case 'T':
+        case 't':
+            segments = (1<<D)|(1<<E)|(1<<F)|(1<<G);
+            break;
+        case 'U':
+            segments = (1<<B)|(1<<C)|(1<<D)|(1<<E)|(1<<F);
+            break;
+        case 'u':
+            segments = (1<<C)|(1<<D)|(1<<E);
+            break;
+        case 'V':
+        case 'v':
+            segments = (1<<C)|(1<<D)|(1<<E);
+            break;
+        case 'W':
+        case 'w':
+            segments = (1<<A)|(1<<C)|(1<<D)|(1<<E);
+            break;
+        case 'X':
+        case 'x':
+            segments = (1<<B)|(1<<C)|(1<<E)|(1<<F);
+            break;
+        case 'Y':
+        case 'y':
+            segments = (1<<B)|(1<<C)|(1<<D)|(1<<F)|(1<<G);
+            break;
+        case 'Z':
+        case 'z':
+            segments = (1<<A)|(1<<D)|(1<<G);
+            break;
+        case '-':
+            segments = (1<<G);
+            break;
+        case '"':
+            segments = (1<<B)|(1<<F);
+            break;
+        case 0x27:  // "'"
+            segments = (1<<B);
+            break;
+        case '_':
+            segments = (1<<D);
+            break;
+        case ' ':
+        default:
+            segments = 0;
+            break;
+    }
+    
+    return segments;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/global.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,180 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#include "mbed.h"
+
+/// VFD Modular Clock - SMT mbed IV-18
+#if defined(TARGET_LPC11U24) || defined(TARGET_LPC1347)
+
+#define FEATURE_3BUTTON  YES
+#define FEATURE_GPS      YES
+#define FEATURE_DS1302    NO
+#define FEATURE_DS3231M  YES
+
+struct PinMap {
+    static const PinName data  = P0_18;
+    static const PinName clock = P0_17;
+    static const PinName latch = P0_19;
+    static const PinName blank = P0_13;
+    
+    static const PinName button2 = P1_28;  // button
+    static const PinName button1 = P0_7; // button
+    static const PinName button3 = P0_1;  // button
+    
+    // RTC
+    static const PinName sda = P0_5;
+    static const PinName scl = P0_4;
+    
+    // Other
+    static const PinName piezo = P0_9;
+    static const PinName led = P1_16;
+    //static const PinName tx = P1_13;
+    //static const PinName rx = P1_14;
+    static const PinName ext1 = P1_19;
+    static const PinName ext2 = P1_20;
+};
+
+#endif
+
+/// VFD Modular Clock - mbed test board
+#ifdef TARGET_LPC1114
+
+#define FEATURE_3BUTTON  NO
+#define FEATURE_GPS     YES
+#define FEATURE_DS1302   NO
+#define FEATURE_DS3231M YES
+
+struct PinMap {
+    // VFD Driver
+    static const PinName data  = dp14;
+    static const PinName clock = dp10;
+    static const PinName latch = dp13;
+    static const PinName blank = dp1;
+
+    // Buttons / switches
+    static const PinName button1 = dp26; // button
+    static const PinName button2 = dp24; // button
+    static const PinName button3 = dp28; // switch
+    
+    // Board signature
+    static const PinName sig0 = dp4;
+    static const PinName sig1 = dp2;
+    static const PinName sig2 = dp6;
+
+    // Other
+    static const PinName piezo = dp18;
+    static const PinName led = dp25;
+    static const PinName sqw = dp17;
+    static const PinName tx = dp16;
+    static const PinName rx = dp16;
+    static const PinName ext1 = dp9;
+    static const PinName ext2 = dp11;
+};
+
+#endif
+
+/// VFD Modular Clock - mbed test board
+#ifdef TARGET_LPC1549
+
+#define FEATURE_3BUTTON  NO
+#define FEATURE_GPS      NO
+#define FEATURE_DS1302   NO
+#define FEATURE_DS3231M YES
+
+struct PinMap {
+    // VFD Driver
+    static const PinName data  = A5;
+    static const PinName clock = D13; // P0_16
+    static const PinName latch = A4;
+    static const PinName blank = D5;
+    /*
+    static const PinName data  = P0_22; // A5
+    static const PinName clock = P0_16; // D13
+    static const PinName latch = P0_23; // A4
+    static const PinName blank = P0_16; // D5
+    */
+
+    // Buttons / switches
+    static const PinName button1 = D8;
+    static const PinName button2 = D7;
+    static const PinName button3 = D2;
+    /*
+    static const PinName button1 = P0_24; // button D8
+    static const PinName button2 = P0_0; // button D7
+    static const PinName button3 = P0_29; // switch D2
+    */
+    
+    // Board signature
+    static const PinName sig0 = A0; //P0_8
+    static const PinName sig1 = A1; //P0_7
+    static const PinName sig2 = A2; //P0_6
+    
+    // Other
+    static const PinName piezo = D4; // P0_10
+    static const PinName led = D9; // P1_0
+    //static const PinName sqw = P1_3; // D6
+    //static const PinName tx = P0_18; // D1
+    //static const PinName rx = P0_13; // D0
+    static const PinName ext1 = A3; // P0_5
+    static const PinName ext2 = D3; // P1_2
+    
+    // I2C
+    //static const PinName sda = 
+    //static const PinName scl =
+};
+
+#endif
+
+
+/// VFD Modular Clock - BLE
+#ifdef TARGET_NRF51822
+
+#define FEATURE_3BUTTON  NO
+#define FEATURE_GPS      NO
+#define FEATURE_DS1302   NO
+#define FEATURE_DS3231M YES
+
+struct PinMap {
+    static const PinName data  = P0_15;
+    static const PinName clock = P0_12;
+    static const PinName latch = P0_13;
+    static const PinName blank = P0_13;
+    
+    static const PinName button1 = P0_1;
+    static const PinName button2 = P0_1;
+};
+
+#endif
+
+#include "features.h"
+
+// display state
+typedef enum {
+  // basic states
+  STATE_CLOCK = 0,    // shows hh-mm-ss / hh.mm.ss / hh.mm.ss.x depending on g_display_mode
+  STATE_SHOW_ALARM,   // shows current alarm for a brief time
+  STATE_ALARMING,     // alarm is going off
+  STATE_AUTO_DATE,    // scroll date across the screen
+  STATE_AUTO_FLW,     // show FLW briefly
+  STATE_AUTO_TEMP,    // show temperature briefly
+  STATE_SET_ALARM_HH, // set alarm, hours
+  STATE_SET_ALARM_MM, // set alarm, minutes
+  STATE_SET_CLOCK_HH, // set clock, hours 
+  STATE_SET_CLOCK_MM, // set clock, minutes 
+  STATE_SET_CLOCK_SS, // set clock, seconds
+  STATE_FLW,          // four letter word
+  STATE_TEMP,         // temperature
+  STATE_MENU,         // menu
+} state_t;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gps.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,261 @@
+/*
+ * GPS support for VFD Modular Clock
+ * (C) 2012 William B Phelps
+ *
+ * mbed Port (C) 2014 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#include "global.h"
+#include "gps.h"
+
+#ifdef HAVE_GPS
+
+//Serial gps(P1_13, P1_14);
+Serial* gps;
+
+bool g_gps_updating = false;
+int g_gps_cks_errors = 0;
+int g_gps_parse_errors = 0;
+int g_gps_time_errors = 0;
+
+unsigned long tGPSupdate;
+
+// we double buffer: read into one line and leave one for the main program
+//volatile char gpsBuffer1[GPSBUFFERSIZE];
+//volatile char gpsBuffer2[GPSBUFFERSIZE];
+volatile char* gpsBuffer1;
+volatile char* gpsBuffer2;
+
+// our index into filling the current line
+volatile uint8_t gpsBufferPtr;
+// pointers to the double buffers
+volatile char *gpsNextBuffer;
+volatile char *gpsLastBuffer;
+volatile uint8_t gpsDataReady_;
+
+time_t tLast = 0;  // for checking GPS messages
+
+void GPSread() 
+{
+    char c = gps->getc();
+    
+    if (c == '$') {
+        gpsNextBuffer[gpsBufferPtr] = 0;
+        gpsBufferPtr = 0;
+    }
+    if (c == '\n') {  // newline marks end of sentence
+        gpsNextBuffer[gpsBufferPtr] = 0;  // terminate string
+        if (gpsNextBuffer == gpsBuffer1) {  // switch buffers
+            gpsNextBuffer = gpsBuffer2;
+            gpsLastBuffer = gpsBuffer1;
+        } else {
+            gpsNextBuffer = gpsBuffer1;
+            gpsLastBuffer = gpsBuffer2;
+        }
+        gpsBufferPtr = 0;
+        gpsDataReady_ = true;  // signal data ready
+    }
+    
+    gpsNextBuffer[gpsBufferPtr++] = c;  // add char to current buffer, then increment index
+    if (gpsBufferPtr >= GPSBUFFERSIZE)  // if buffer full
+        gpsBufferPtr = GPSBUFFERSIZE-1;  // decrement index to make room (overrun)
+}
+
+uint8_t gpsDataReady(void) {
+    return gpsDataReady_;
+}
+
+char *gpsNMEA(void) {
+  gpsDataReady_ = false;
+  return (char *)gpsLastBuffer;
+}
+
+uint32_t parsedecimal(char *str, uint8_t len) {
+  uint32_t d = 0;
+    for (uint8_t i=0; i<len; i++) {
+   if ((str[i] > '9') || (str[0] < '0'))
+     return d;  // no more digits
+     d = (d*10) + (str[i] - '0');
+  }
+  return d;
+}
+
+int32_t _abs(int32_t a) {
+    if (a < 0) return -a;
+    return a;    
+}
+
+const char hex[17] = "0123456789ABCDEF";
+
+uint8_t atoh(char x) {
+  return (strchr(hex, x) - hex);
+}
+
+uint32_t hex2i(char *str, uint8_t len) {
+  uint32_t d = 0;
+    for (uint8_t i=0; i<len; i++) {
+     d = (d*10) + (strchr(hex, str[i]) - hex);
+    }
+    return d;
+}
+
+// find next token in GPS string - find next comma, then point to following char
+char * ntok ( char *ptr ) {
+    ptr = strchr(ptr, ',');  // Find the next comma
+    if (ptr == NULL) return NULL;
+    ptr++;  // point at next char after comma
+    return ptr;
+}
+
+//  225446       Time of fix 22:54:46 UTC
+//  A            Navigation receiver warning A = OK, V = warning
+//  4916.45,N    Latitude 49 deg. 16.45 min North
+//  12311.12,W   Longitude 123 deg. 11.12 min West
+//  000.5        Speed over ground, Knots
+//  054.7        Course Made Good, True
+//  191194       Date of fix  19 November 1994
+//  020.3,E      Magnetic variation 20.3 deg East
+//  *68          mandatory checksum
+
+//$GPRMC,225446.000,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68\r\n
+// 0         1         2         3         4         5         6         7
+// 0123456789012345678901234567890123456789012345678901234567890123456789012
+//    0     1       2    3    4     5    6   7     8      9     10  11 12
+time_t parseGPSdata(char *gpsBuffer, bool& error, bool& fix, int8_t tzh, uint8_t tzm) {
+    time_t tNow;
+    struct tm tm;
+    uint8_t gpsCheck1, gpsCheck2;  // checksums
+
+    char gpsFixStat;  // fix status
+//  char gpsLat[7];  // ddmm.ff  (with decimal point)
+//  char gpsLatH;  // hemisphere 
+//  char gpsLong[8];  // dddmm.ff  (with decimal point)
+//  char gpsLongH;  // hemisphere 
+//  char gpsSpeed[5];  // speed over ground
+//  char gpsCourse[5];  // Course
+//  char gpsDate[6];  // Date
+//  char gpsMagV[5];  // Magnetic variation 
+//  char gpsMagD;  // Mag var E/W
+//  char gpsCKS[2];  // Checksum without asterisk
+
+    error = false;
+    fix = false;
+
+    char *ptr;
+    uint32_t tmp;
+    if ( strncmp( gpsBuffer, "$GPRMC,", 7 ) == 0 ) {
+        //Calculate checksum from the received data
+        ptr = &gpsBuffer[1];  // start at the "G"
+        gpsCheck1 = 0;  // init collector
+
+        // Loop through entire string, XORing each character to the next
+        while (*ptr != '*') // count all the bytes up to the asterisk
+        {
+            gpsCheck1 ^= *ptr;
+            ptr++;
+            if (ptr>(gpsBuffer+GPSBUFFERSIZE)) goto GPSerrorP;  // extra sanity check, can't hurt...
+        }
+        // now get the checksum from the string itself, which is in hex
+        gpsCheck2 = atoh(*(ptr+1)) * 16 + atoh(*(ptr+2));
+    
+        if (gpsCheck1 == gpsCheck2) {  // if checksums match, process the data
+            ptr = &gpsBuffer[1];  // start at beginning of buffer
+            ptr = ntok(ptr);  // Find the time string
+            if (ptr == NULL) goto GPSerrorP;
+            char *p2 = strchr(ptr, ',');  // find comma after Time
+            if (p2 == NULL) goto GPSerrorP;
+            if (p2 < (ptr+6)) goto GPSerrorP;  // Time must be at least 6 chars
+            tmp = parsedecimal(ptr, 6);   // parse integer portion
+            tm.tm_hour = tmp / 10000;
+            tm.tm_min = (tmp / 100) % 100;
+            tm.tm_sec = tmp % 100;
+            ptr = ntok(ptr);  // Find the next token - Status
+            if (ptr == NULL) goto GPSerrorP;
+            gpsFixStat = ptr[0];
+            if (gpsFixStat == 'A') {  // if data valid, parse time & date
+                fix = true;
+            
+                for (uint8_t n=0; n<7; n++) { // skip 6 tokend, find date
+                    ptr = ntok(ptr);  // Find the next token
+                    if (ptr == NULL) goto GPSerrorP; // error if not found
+                }
+                p2 = strchr(ptr, ',');  // find comma after Date
+                if (p2 == NULL) goto GPSerrorP;
+                if (p2 != (ptr+6)) goto GPSerrorP;  // check date length
+                tmp = parsedecimal(ptr, 6); 
+                tm.tm_mday = tmp / 10000;
+                tm.tm_mon = ((tmp / 100) % 100) - 1; // zero offset for month
+                tm.tm_year = tmp % 100;
+                                
+                ptr = strchr(ptr, '*');  // Find Checksum
+                if (ptr == NULL) goto GPSerrorP;
+
+                tm.tm_year = y2kYearToTm(tm.tm_year);  // convert yy year to (yyyy-1900) (add 100)                
+                tNow = mktime(&tm);  // convert to time_t - seconds since 0/0/1970
+                
+                // If time jumps by more than a minute, complain about it. Either poor GPS signal or an error in the data
+                if ( (tLast>0) && (_abs(tNow - tLast)>60) )  // Beep if over 60 seconds since last GPRMC?
+                {
+                    goto GPSerrorT;  // it's probably an error
+                }
+                else {
+                    tLast = tNow;
+                    tNow = tNow + (long)(tzh) * SECS_PER_HOUR + (long)tzm;
+
+                }
+            } // if fix status is A
+        } // if checksums match
+        else  // checksums do not match
+            goto GPSerrorC;
+        
+        return tNow;
+
+GPSerrorC:
+        g_gps_cks_errors++;  // increment error count
+        goto GPSerror2a;
+GPSerrorP:
+        g_gps_parse_errors++;  // increment error count
+        goto GPSerror2a;
+GPSerrorT:
+#ifdef HAVE_SERIAL_DEBUG
+        tDelta = tNow - tGPSupdate;
+        Serial.print("tNow="); Serial.print(tNow); Serial.print(", tLast="); Serial.print(tLast); Serial.print(", diff="); Serial.print(tNow-tLast);
+        Serial.print(", tDelta="); Serial.print(tDelta);
+        Serial.println(" ");
+#endif
+        g_gps_time_errors++;  // increment error count
+        tLast = tNow;  // save new time
+
+GPSerror2a:
+        strcpy(gpsBuffer, "");  // wipe GPS buffer
+    }  // if "$GPRMC"
+    
+    error = true;
+    return 0;
+}
+
+void gps_init() {
+    gps = new Serial(P1_13, P1_14);
+    gps->attach(&GPSread);
+    
+    gpsBuffer1 = new char[GPSBUFFERSIZE];
+    gpsBuffer2 = new char[GPSBUFFERSIZE];
+            
+    tGPSupdate = 0;  // reset GPS last update time
+    gpsDataReady_ = false;
+    gpsBufferPtr = 0;
+    gpsNextBuffer = gpsBuffer1;
+    gpsLastBuffer = gpsBuffer2;
+}
+
+#endif // HAVE_GPS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gps.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,58 @@
+/*
+ * GPS support for VFD Modular Clock
+ * (C) 2012 William B Phelps
+ *
+ * mbed Port (C) 2014 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#ifndef GPS_H_
+#define GPS_H_
+
+#ifdef HAVE_GPS
+
+#include "mbed.h"
+
+//convenience macro to convert to and from tm years
+#define  tmYearToY2k(Y)      ((Y) - 100)    // offset is from 1900
+#define  y2kYearToTm(Y)      ((Y) + 100)
+
+// String buffer size:
+#define GPSBUFFERSIZE 96 
+//The year the clock was programmed, used for error checking
+#define PROGRAMMING_YEAR 14
+
+#define SECS_PER_HOUR (3600UL)
+
+extern unsigned long tGPSupdate;  // really time_t
+
+// we double buffer: read into one line and leave one for the main program
+//extern volatile char gpsBuffer1[GPSBUFFERSIZE];
+//extern volatile char gpsBuffer2[GPSBUFFERSIZE];
+// our index into filling the current line
+//extern volatile uint8_t gpsBufferPtr;
+// pointers to the double buffers
+//extern volatile char *gpsNextBuffer;
+//extern volatile char *gpsLastBuffer;
+//extern volatile uint8_t gpsDataReady_;
+
+//GPS serial data handling functions:
+uint8_t gpsDataReady(void);
+void GPSread(char c);
+char *gpsNMEA(void);
+time_t parseGPSdata(char *gpsBuffer, bool& error, bool& fix, int8_t tzh, uint8_t tzm);
+
+uint8_t leapyear(uint16_t y);
+void gps_init();
+
+#endif // HAVE_GPS
+#endif // GPS_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,650 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#include "global.h"
+#include "mbed.h"
+
+#include "VFDDisplay.h"
+#include "IV18Display.h"
+
+#include "prefs.h"
+#include "gps.h"
+#include "menu.h"
+#include "button.h"
+#include "rtc.h"
+#include "ds3231m.h"
+#include "beep.h"
+#include "flw.h"
+
+IV18Display display(PinMap::data, PinMap::clock, PinMap::latch, PinMap::blank);
+
+Menu menu;
+
+I2C i2c(PinMap::sda, PinMap::scl);
+DS3231M rtc(i2c);
+//RTC rtc;
+
+DigitalOut led(PinMap::led);
+Beep piezo(PinMap::piezo);
+
+FourLetterWord flw(&i2c);
+char flwWord[5];
+int flwOffset;
+int flwOffsetDirection = 1;
+volatile bool haveEEPROM;
+
+Ticker blanker;
+Ticker multiplexer;
+Ticker button_ticker;
+Ticker rtc_ticker;
+Ticker tenth_ticker;
+
+volatile state_t g_clock_state = STATE_CLOCK;
+uint32_t gps_last_update = 0xffff;
+
+uint8_t calculate_segments_7(uint8_t character);
+
+// Alarm
+volatile bool g_alarm_on;
+volatile bool g_alarming;
+
+void write_vfd_8bit(uint8_t data);
+void write_vfd_iv18(uint8_t digit, uint8_t segments);
+void write_vfd(uint8_t digit, uint8_t segments);
+void demo_cycle(char* buf);
+
+void blank_tick()
+{
+    static uint32_t cnt = 0;
+    
+    if ((cnt%10) > (10-display.getBrightness())) {
+        display.blank(false);
+    }
+    else {
+       display.blank(true);
+    }
+    
+    cnt++;
+}
+
+void multiplex_tick()
+{
+    display.multiplexTick();
+}
+
+void rtc_tick()
+{
+    if (haveEEPROM)
+        strncpy(flwWord, flw.getWord(), 4);
+    
+    flwOffset += flwOffsetDirection;
+    
+    if (flwOffset <= 0) {
+        flwOffset = 0;
+        flwOffsetDirection = 1;    
+    }
+    else if (flwOffset > display.digits() -4) {
+        flwOffset = 3;    
+        flwOffsetDirection = -1;
+    }
+    
+    rtc.tick();
+}
+
+void tenth_tick()
+{
+    rtc.tenth_tick(); 
+}
+
+void counterTest()
+{
+    display.cls();
+    for (uint16_t i = 0; i < 200; i++) {
+        display.printf("cnt %3d", i);
+        wait(0.01);
+    }
+}
+
+void timeAndDateTest()
+{
+    uint8_t hour = 15;
+    uint8_t min = 59;
+    uint8_t sec = 55;
+    
+    display.cls();
+    for (uint8_t i = 0; i < 7; i++) {
+        display.printf("%02d-%02d-%02d", hour, min, sec);
+        sec++;
+        if (sec == 60) { sec = 0; min++;  }
+        if (min == 60) { min = 0; hour++; }
+        wait(1.0);    
+    }
+    
+    display.printf("%02d-%02d-%02d  Monday 2014-05-12", hour, min, sec);
+
+    while (!display.scrollFinished()) {                 
+        display.scroll();    
+        wait(0.25);
+    }
+    
+    display.resetScroll();
+
+    for (uint8_t i = 0; i < 5; i++) {
+        display.printf("%2d-%02d-%02d", hour, min, sec);
+        sec++;
+        if (sec == 60) { sec = 0; min++;  }
+        if (min == 60) { min = 0; hour++; }
+        wait(1.0);    
+    }
+    
+}
+
+int dayOfWeek(int y, int m, int d)
+{
+    static const int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
+    y -= m < 3;
+    return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
+}
+
+void welcomeMessage()
+{
+    const char* buf = " Akafugu VFD Modular Clock";    
+    
+    display.cls();
+    display.printf(buf);
+        
+    // scroll forward
+    while (!display.scrollFinished()) {                 
+        display.scroll(); 
+        led = !led;   
+        wait(0.20);
+    }
+
+    display.cls();
+}
+
+// helper function for handling time/alarm setting
+uint8_t handleTimeSetting(uint8_t setting, uint8_t min, uint8_t max, 
+                          bool backButton, bool nextButton)
+{
+    if (backButton) {
+        if (setting == 0) {
+            setting = max;
+        }
+        else {
+            setting--;
+        }
+    }
+    else if (nextButton) {
+        if (setting == max) {
+            setting = 0;
+        }
+        else {
+            setting++;
+        }
+    }
+    
+    return setting;
+}
+
+const uint32_t MENU_TIMEOUT = 3 * 10; // each cycle 0.1s, 3 secs total
+struct tm* tm_;
+
+int main()
+{
+    bool suppress_button_sound = false;
+    uint8_t button3_holdcounter = 0;
+    uint32_t menu_countdown = MENU_TIMEOUT;
+
+    // Enable extra memory banks
+    LPC_SYSCON->SYSAHBCLKCTRL |= 0x1 << 26; // RAM1
+    LPC_SYSCON->SYSAHBCLKCTRL |= 0x1 << 27; // USBSRAM
+
+    // PWM
+    // See: http://developer.mbed.org/forum/mbed/topic/3276/
+    /*
+    LPC_CT16B0->TCR = 2;
+    LPC_CT16B0->PR = 19;
+    LPC_CT16B0->MR0 = 48000; // 1ms
+    LPC_CT16B0->TCR = 1;
+    */
+    
+    BUTTON_STATE buttons;
+        
+    rtc.begin();
+    init_prefs();
+    
+    // FLW initialization
+    tm_ = rtc.getTime();
+    
+    flw.begin(tm_->tm_min * 60 + tm_->tm_sec);
+    flw.setCensored(true);
+
+    memset(flwWord, 0, 5);
+    haveEEPROM = flw.hasEeprom();
+    if (haveEEPROM)
+        strncpy(flwWord, flw.getWord(), 4);
+    else
+        memset(flwWord, 0, 4);    
+
+    led = 0;
+    
+    initialize_buttons();
+    menu.setDigits(display.digits());
+    
+    blanker.attach_us(&blank_tick, 100);
+    multiplexer.attach_us(&multiplex_tick, 2000);
+    button_ticker.attach_us(&button_tick, 5000);
+    rtc_ticker.attach(&rtc_tick, 1.0);
+    tenth_ticker.attach(&tenth_tick, 0.1);
+
+    PrefsData* prefs = get_prefs();
+    display.setBrightness(prefs->prefs.brightness);
+
+    wait(1.0);
+    //welcomeMessage();
+    led = 0;
+    
+#ifdef HAVE_GPS
+    gps_init();
+#endif // HAVE_GPS
+
+    /*
+    // button test
+    while (1) {
+        get_button_state(&buttons);
+        
+        display.printf("%d-%d-%d %d", buttons.b1_keydown, buttons.b2_keydown, buttons.b3_keydown, get_keystatus());
+        wait(0.1);
+    }
+    */
+    
+    while (1) {
+        get_button_state(&buttons);
+        prefs = get_prefs();
+        
+        led = 0;
+        
+#ifdef HAVE_GPS
+        // Read GPS and update RTC if needed
+        if (gpsDataReady()) {
+            char* nmea = gpsNMEA();
+            bool error = false;
+            bool fix = false;
+
+            if ( prefs->prefs.gps && strncmp( nmea, "$GPRMC,", 7 ) == 0 ) {
+                time_t t = parseGPSdata(nmea, error, fix, prefs->prefs.gps_tzh, prefs->prefs.gps_tzm);
+                time_t delta = t - gps_last_update;
+
+                if (fix && !error && delta > 60) {
+                    led = 1;
+                    struct tm *tmp = localtime(&t);
+                    rtc.setTime(tmp);
+                    gps_last_update = t;
+                }
+            }
+        }
+#endif // HAVE_GPS
+        
+        if (buttons.b1_keyup || buttons.b2_keyup || buttons.b3_keyup) {            
+            if (suppress_button_sound || g_alarming) {
+                suppress_button_sound = false;
+                buttons.b1_keyup = buttons.b2_keyup = buttons.b3_keyup = 0;
+            }
+            else {
+                //piezo.play('g');
+            }
+            
+            button3_holdcounter = 0;
+            g_alarming = false;
+        }
+        
+        switch (g_clock_state) {            
+            case STATE_CLOCK:
+            {
+                tm_ = rtc.getTime();
+
+                // button 1 triggers menu
+                if (buttons.b1_keyup) {
+                    //display.incBrightness();
+                    display.printf("%s                ", menu.reset());
+                    display.setAlarmIndicator(false);
+                    display.setGPSIndicator(false);
+                    set_extra_prefs(tm_->tm_year+1900, tm_->tm_mon+1, tm_->tm_mday);
+                    g_clock_state = STATE_MENU;
+                    menu_countdown = MENU_TIMEOUT;
+                    buttons.b1_keyup = 0;
+                    break;
+                }
+                
+                // Button 2 cycles through display mode
+                if (buttons.b2_keyup) {
+                    display.toggleTimeMode();
+                    buttons.b2_keyup = 0;
+                }
+                
+                // Button 3 toggles FLW mode
+                if (buttons.b3_keyup && haveEEPROM) {
+                    buttons.b3_keyup = 0;
+                    button3_holdcounter = 0;
+                    g_clock_state = STATE_FLW;
+                }
+                
+                // Hold button 3 to set alarm
+                if (buttons.b3_repeat) {
+                    button3_holdcounter++;
+                    buttons.b3_repeat = 0;
+                    suppress_button_sound = true;
+                    
+                    if (button3_holdcounter == 6) {
+                        g_alarm_on = !g_alarm_on;
+                        piezo.play('a');                        
+                    }
+                }
+                                
+                // Enter auto date
+                if (prefs->prefs.auto_date && tm_->tm_sec == 50) {
+                    display.cls();
+                    display.printTimeLong(tm_, rtc.getTenths());
+                    g_clock_state = STATE_AUTO_DATE;
+                }
+                else if (haveEEPROM && prefs->prefs.flw > 0 && tm_->tm_sec == 30) {
+                    g_clock_state = STATE_AUTO_FLW;
+                }
+                else {
+                    display.printTime(tm_, rtc.getTenths());
+                }
+            }
+            break;
+            case STATE_MENU:
+            {
+                // button 1 goes to next menu item
+                if (buttons.b1_keyup) {
+                    display.printf("%s                ", menu.next()); 
+                    menu_countdown = MENU_TIMEOUT;
+                    buttons.b1_keyup = 0;
+                }
+                                
+                // Button 2 selects menu item
+                if (buttons.b2_keyup || buttons.b2_repeat) {
+                    bool setTime, setAlarm;
+                    
+                    display.printf("%8s                ", menu.select(setTime, setAlarm));
+                    
+                    if (setTime) {
+                        menu.leave();
+                        display.setBlinkMode(VFDDisplay::Hours);
+                        display.blink(true);
+                        tm_ = rtc.getTime(); // get time from RTC to use as basis for settings
+                        tm_->tm_sec = 0;                        
+                        g_clock_state = STATE_SET_CLOCK_HH;   
+                    }
+                    else if (setAlarm) {
+                        menu.leave();
+                        display.setBlinkMode(VFDDisplay::Minutes);
+                        display.blink(true);
+                        tm_ = rtc.getAlarm();
+                        g_clock_state = STATE_SET_ALARM_HH;
+                    }
+                    
+                    menu_countdown = MENU_TIMEOUT;
+                    buttons.b2_keyup = 0;
+                }
+                // Button 3 leaves menu
+                else if (buttons.b3_keyup) {
+                    buttons.b3_keyup = 0;
+                    menu.leave();
+                    g_clock_state = STATE_CLOCK;
+                }
+                
+                menu_countdown--;
+                
+                // exit menu if unused for preset time
+                if (menu_countdown == 0) {
+                    menu.leave();
+                    g_clock_state = STATE_CLOCK;
+                }
+                
+                // If g_clock_state has changed, we are leaving the menu, update parameters
+                if (g_clock_state == STATE_CLOCK) {
+                    display.setGPSIndicator(true);
+                    
+                    tm_ = rtc.getTime();
+                    int year, month, day;
+                    
+                    get_extra_prefs(year, month, day);
+                    tm_->tm_year = year - 1900;
+                    tm_->tm_mon  = month-1;
+                    tm_->tm_mday = day;
+                    
+                    tm_->tm_wday = dayOfWeek(year, month, day);
+                    
+                    rtc.setTime(tm_);
+
+                    wait(0.05);
+                    display.setGPSIndicator(false);
+                }
+            }
+            break;
+            case STATE_AUTO_DATE:
+            {
+                // exit scroll if any button is pressed
+                if (buttons.b1_keyup || buttons.b2_keyup || buttons.b3_keyup) {
+                    display.cls();
+                    g_clock_state = STATE_CLOCK;  
+                    
+                    buttons.b1_keyup = 0;
+                    buttons.b2_keyup = 0;
+                    buttons.b3_keyup = 0;
+                }
+                
+                static uint8_t scroll_cnt = 0;
+                
+                if (display.scrollFinished()) {
+                    display.cls();
+                    g_clock_state = STATE_CLOCK;  
+                }
+                else {
+                    if (++scroll_cnt == 2) {
+                        display.scroll();
+                        scroll_cnt = 0;
+                    }
+                }
+            }
+            break;
+            case STATE_SET_CLOCK_HH:
+            {
+                display.printTimeSet(tm_);
+
+                if (buttons.b1_repeat || buttons.b2_repeat) {
+                    display.blink(false);
+                    tm_->tm_hour = handleTimeSetting(tm_->tm_hour, 0, 23, buttons.b1_repeat, buttons.b2_repeat);
+                    buttons.b1_repeat = 0;
+                    buttons.b2_repeat = 0;
+                }
+                if (buttons.b1_keyup) {
+                    display.blink(true);
+                    tm_->tm_hour = handleTimeSetting(tm_->tm_hour, 0, 23, true, false);
+                    buttons.b1_keyup = 0;
+                }
+                else if (buttons.b2_keyup) { // Button 2 
+                    display.blink(true);
+                    tm_->tm_hour = handleTimeSetting(tm_->tm_hour, 0, 23, false, true);
+                    buttons.b2_keyup = 0;
+                }
+                else if (buttons.b3_keyup) { // Button 3 moves to minute setting
+                    display.setBlinkMode(VFDDisplay::Minutes);
+                    g_clock_state = STATE_SET_CLOCK_MM;
+                    buttons.b3_keyup = 0;
+                }
+            }
+            break;
+            case STATE_SET_CLOCK_MM:
+            {
+                display.printTimeSet(tm_);
+
+                if (buttons.b1_repeat || buttons.b2_repeat) {
+                    display.blink(false);
+                    tm_->tm_min = handleTimeSetting(tm_->tm_min, 0, 59, buttons.b1_repeat, buttons.b2_repeat);
+                    buttons.b1_repeat = 0;
+                    buttons.b2_repeat = 0;
+                }
+                if (buttons.b1_keyup) {
+                    display.blink(true);
+                    tm_->tm_min = handleTimeSetting(tm_->tm_min, 0, 59, true, false);
+                    buttons.b1_keyup = 0;
+                }
+                else if (buttons.b2_keyup) { // Button 2 
+                    display.blink(true);
+                    tm_->tm_min = handleTimeSetting(tm_->tm_min, 0, 59, false, true);
+                    buttons.b2_keyup = 0;
+                }
+                else if (buttons.b3_keyup) { // Button 3 moves to second setting
+                    display.setBlinkMode(VFDDisplay::Seconds);
+                    g_clock_state = STATE_SET_CLOCK_SS;
+                    buttons.b3_keyup = 0;
+                }
+            }
+            break;
+            case STATE_SET_CLOCK_SS:
+            {
+                display.printTimeSet(tm_);
+
+                if (buttons.b1_repeat || buttons.b2_repeat) {
+                    display.blink(false);
+                    tm_->tm_sec = handleTimeSetting(tm_->tm_sec, 0, 59, buttons.b1_repeat, buttons.b2_repeat);
+                    buttons.b1_repeat = 0;
+                    buttons.b2_repeat = 0;
+                }
+                if (buttons.b1_keyup) {
+                    display.blink(true);
+                    tm_->tm_sec = handleTimeSetting(tm_->tm_sec, 0, 59, true, false);
+                    buttons.b1_keyup = 0;
+                }
+                else if (buttons.b2_keyup) { // Button 2 
+                    display.blink(true);
+                    tm_->tm_sec = handleTimeSetting(tm_->tm_sec, 0, 59, false, true);
+                    buttons.b2_keyup = 0;
+                }
+                else if (buttons.b3_keyup) { // Button 3 moves to minute setting
+                    display.setBlinkMode(VFDDisplay::Full);
+                    display.blink(false);
+                    rtc.setTime(tm_);
+                    g_clock_state = STATE_CLOCK;
+                    buttons.b3_keyup = 0;
+                }
+            }
+            break;
+            case STATE_SET_ALARM_HH:
+            {
+                display.printTimeSet(tm_, false);
+
+                if (buttons.b1_repeat || buttons.b2_repeat) {
+                    display.blink(false);
+                    tm_->tm_hour = handleTimeSetting(tm_->tm_hour, 0, 23, buttons.b1_repeat, buttons.b2_repeat);
+                    buttons.b1_repeat = 0;
+                    buttons.b2_repeat = 0;
+                }
+                if (buttons.b1_keyup) {
+                    display.blink(true);
+                    tm_->tm_hour = handleTimeSetting(tm_->tm_hour, 0, 23, true, false);
+                    buttons.b1_keyup = 0;
+                }
+                else if (buttons.b2_keyup) { // Button 2 
+                    display.blink(true);
+                    tm_->tm_hour = handleTimeSetting(tm_->tm_hour, 0, 23, false, true);
+                    buttons.b2_keyup = 0;
+                }
+                else if (buttons.b3_keyup) { // Button 3 moves to minute setting
+                    display.setBlinkMode(VFDDisplay::Seconds);
+                    g_clock_state = STATE_SET_ALARM_MM;
+                    buttons.b3_keyup = 0;
+                }
+            }
+            break;
+            case STATE_SET_ALARM_MM:
+            {
+                display.printTimeSet(tm_, false);
+
+                if (buttons.b1_repeat || buttons.b2_repeat) {
+                    display.blink(false);
+                    tm_->tm_min = handleTimeSetting(tm_->tm_min, 0, 59, buttons.b1_repeat, buttons.b2_repeat);
+                    buttons.b1_repeat = 0;
+                    buttons.b2_repeat = 0;
+                }
+                if (buttons.b1_keyup) {
+                    display.blink(true);
+                    tm_->tm_min = handleTimeSetting(tm_->tm_min, 0, 59, true, false);
+                    buttons.b1_keyup = 0;
+                }
+                else if (buttons.b2_keyup) { // Button 2 
+                    display.blink(true);
+                    tm_->tm_min = handleTimeSetting(tm_->tm_min, 0, 59, false, true);
+                    buttons.b2_keyup = 0;
+                }
+                else if (buttons.b3_keyup) { // Button 3 moves to minute setting
+                    display.setBlinkMode(VFDDisplay::Full);
+                    display.blink(false);
+                    rtc.setAlarm(tm_->tm_hour, tm_->tm_min, 0);
+                    g_clock_state = STATE_CLOCK;
+                    buttons.b3_keyup = 0;
+                }
+            }
+            break;
+            case STATE_AUTO_FLW:
+            {
+                tm_ = rtc.getTime();
+                
+                if (tm_->tm_sec >= 37) {
+                    g_clock_state = STATE_CLOCK;
+                }
+            }
+            // fall-through
+            case STATE_FLW:
+            {
+                // exit if any button is pressed
+                if (buttons.b1_keyup || buttons.b2_keyup || buttons.b3_keyup) {
+                    display.cls();
+                    g_clock_state = STATE_CLOCK;  
+                    
+                    buttons.b1_keyup = 0;
+                    buttons.b2_keyup = 0;
+                    buttons.b3_keyup = 0;
+                }
+                
+                if (flwOffset == 0)
+                    display.printf("%s        ", flwWord);
+                else 
+                    display.printf("%*s" "%s        ", flwOffset, " ", flwWord);
+            }
+            break;
+            default:
+                break;  
+        }
+        
+        if (g_alarm_on && rtc.checkAlarm()) {
+            g_alarming = true;
+        }
+        
+        display.setAlarmIndicator(g_alarm_on);
+        display.setGPSIndicator(g_alarming);
+        
+        if (g_alarming) {
+            piezo.play('g'); 
+        }
+
+        wait(0.1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/4fc01daae5a5
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menu.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,215 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#include "global.h"
+#include "menu.h"
+
+char menu_buf[MAX_BUF];
+
+/////////////////////////////////////////////////////////
+// MenuItemValue
+
+MenuItemValue::MenuItemValue(int32_t min, int32_t max)
+: m_min(min)
+, m_max(max)
+, m_value(min)
+, m_activated(false)
+{
+}
+
+int32_t MenuItemValue::getValue()
+{
+    return m_value;
+}
+
+int32_t MenuItemValue::incrementValue()
+{
+    if (m_activated) {
+        m_value++;
+        if (m_value > m_max) m_value = m_min;
+    }
+    else {
+        m_activated = true;    
+    }
+    
+    return m_value;
+}    
+
+void MenuItemValue::resetActive()
+{
+    m_activated = false;
+}
+
+/////////////////////////////////////////////////////////
+// MenuItem
+
+MenuItem::MenuItem(const char* shortName, const char* longName, bool onOff, PREFS pref)
+: m_onOff(onOff)
+, m_pref(pref)
+{
+    strncpy(m_shortName, shortName, 4);
+    strncpy(m_longName, longName, 8);
+    m_menuItemValue = new MenuItemValue(0, 1);
+}
+
+MenuItem::MenuItem(const char* shortName, bool onOff, PREFS pref)
+: m_onOff(onOff)
+, m_pref(pref)
+{
+    strncpy(m_shortName, shortName, 4);
+    m_longName[0] = 0;
+    m_menuItemValue = new MenuItemValue(0, 1);
+}
+
+MenuItem::MenuItem(const char* shortName, const char* longName, int32_t min, int32_t max, PREFS pref)
+: m_onOff(false)
+, m_pref(pref)
+{
+    strncpy(m_shortName, shortName, 4);
+    strncpy(m_longName, longName, 8);    
+    m_menuItemValue = new MenuItemValue(min, max);
+}
+
+MenuItem::MenuItem(const char* shortName, int32_t min, int32_t max, PREFS pref)
+: m_onOff(false)
+, m_pref(pref)
+{
+    strncpy(m_shortName, shortName, 4);
+    m_longName[0] = 0;
+    m_menuItemValue = new MenuItemValue(min, max);
+}
+
+const char* MenuItem::getName(uint8_t digits) const
+{
+    if (m_longName[0] == 0) return m_shortName;
+    return digits <= 4 ? m_shortName : m_longName;
+}
+
+extern DigitalOut led;
+
+const char* MenuItem::selectValue(uint8_t digits) const
+{
+    uint32_t value = m_menuItemValue->incrementValue();
+
+    // special handling
+    if (m_pref == PREF_GPS_TZM) {
+        value *= 15;    
+    }
+    
+    if (m_onOff) {
+        if (value == 1)
+            snprintf(menu_buf, MAX_BUF-1, "%s", "on");
+        else
+            snprintf(menu_buf, MAX_BUF-1, "%s", "off");
+    }
+    else if (m_pref == PREF_FLW) {
+        if (value == 0)
+            snprintf(menu_buf, MAX_BUF-1, "%s", "off");
+        if (value == 1)
+            snprintf(menu_buf, MAX_BUF-1, "%s", "on");
+        else if (value == 2)
+            snprintf(menu_buf, MAX_BUF-1, "%s", "full");            
+    }
+    else {
+        // special handling for year/month/day - these values are not stored in the eeprom
+        // but go directly to the RTC chip
+        if (m_pref == PREF_YEAR) {
+            set_year(value);    
+        }
+        else if (m_pref == PREF_MONTH) {
+            set_month(value);    
+        }
+        else if (m_pref == PREF_DAY) {
+            set_day(value);    
+        }
+        
+        snprintf(menu_buf, MAX_BUF-1, "%d", value);    
+    }
+    
+    // save to prefs
+    if (m_pref != PREF_NULL) {
+        set_pref(m_pref, value);
+    }
+
+    return menu_buf;
+}
+
+void MenuItem::resetActive() const
+{
+    m_menuItemValue->resetActive();
+}
+
+const MenuItem menu1("TIME", "SET TIME", true, PREF_SET_TIME);
+const MenuItem menu2("ALRM", "SET ALR", true, PREF_SET_ALARM);
+const MenuItem menu3("24H", true, PREF_24H);
+const MenuItem menu4("BRIT", "BRITE", 2, 10, PREF_BRIGHTNESS);
+const MenuItem menu5("YEAR", 2014, 2075, PREF_YEAR);
+const MenuItem menu6("MNTH", "MONTH", 1, 12, PREF_MONTH);
+const MenuItem menu7("DAY", 1, 31, PREF_DAY);
+const MenuItem menu8("GPS", true, PREF_GPS);
+const MenuItem menu9("TZH", "GPS TZH", -12, 14, PREF_GPS_TZH);
+const MenuItem menu10("TZM", "GPS TZM", 0, 3, PREF_GPS_TZM);
+const MenuItem menu11("ADTE", "AUTODATE", true, PREF_AUTODATE);
+const MenuItem menu12("FLW", 0, 2, PREF_FLW);
+
+#ifdef HAVE_GPS
+#define ITEMS 12
+const MenuItem* menuItems[] = { &menu1, &menu2, &menu3, &menu4, &menu5, &menu6, &menu7, &menu8, &menu9, &menu10, &menu11, &menu12 };
+#else
+#define ITEMS 8
+const MenuItem* menuItems[] = { &menu1, &menu2, &menu3, &menu4, &menu5, &menu6, &menu7, &menu12 };
+#endif
+
+Menu::Menu()
+    : m_position(0)
+    , m_size(ITEMS)
+    , m_digits(8)
+{
+}
+
+const char* Menu::reset()
+{
+    m_position = 0;
+    return menuItems[m_position]->getName(m_digits);
+}
+
+const char* Menu::next()
+{
+    menuItems[m_position]->resetActive();
+    
+    m_position++;
+    if (m_position >= ITEMS) m_position = 0;
+    
+    return menuItems[m_position]->getName(m_digits);
+}
+
+const char* Menu::select(bool& enterSetTime, bool& enterSetAlarm)
+{
+    enterSetTime = enterSetAlarm = false;
+    
+    if (menuItems[m_position]->isSetTimeTrigger())
+        enterSetTime = true;
+
+    if (menuItems[m_position]->isSetAlarmTrigger())
+        enterSetAlarm = true;
+    
+    return menuItems[m_position]->selectValue(m_digits);
+}
+
+void Menu::leave()
+{
+    menuItems[m_position]->resetActive(); 
+    save_prefs();   
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/menu.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,86 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#ifndef MENU_H_
+#define MENU_H_
+
+// menu type
+//
+// custom routine (set time, set alarm)
+// on-off (24h on, off)
+// array of possible values (flw: off, on, full)
+// range (brite 1-10)
+//
+// values always stored as numbers
+
+#define MAX_BUF 9
+
+#include "prefs.h"
+
+class MenuItemValue {
+private:
+    int32_t m_min;
+    int32_t m_max;
+    int32_t m_value;
+    bool m_activated;
+public:
+    MenuItemValue(int32_t min, int32_t max);
+
+    int32_t getValue();
+    int32_t incrementValue();
+    void resetActive();
+};
+
+class MenuItem {
+private:
+    char m_shortName[5];
+    char m_longName[MAX_BUF];
+    bool m_onOff;
+    PREFS m_pref;
+    
+    MenuItemValue* m_menuItemValue;
+public:
+    MenuItem(const char* shortName, const char* longName, bool onOff, PREFS pref);
+    MenuItem(const char* shortName, bool onOff, PREFS pref);
+
+    MenuItem(const char* shortName, const char* longName, int32_t min, int32_t max, PREFS pref);
+    MenuItem(const char* shortName, int32_t min, int32_t max, PREFS pref);
+    
+    const char* getName(uint8_t digits) const;
+    const char* selectValue(uint8_t digits) const;
+    void resetActive() const;
+    
+    bool isSetTimeTrigger() const { return m_pref == PREF_SET_TIME; }
+    bool isSetAlarmTrigger() const { return m_pref == PREF_SET_ALARM; }
+};
+
+class Menu {
+private:
+    uint8_t m_position;
+    uint8_t m_size;
+    uint8_t m_digits;
+        
+public:
+    Menu();
+    
+    void setDigits(uint8_t digits) { m_digits = digits; }
+    
+    const char* reset();
+    const char* next();
+    const char* select(bool& enterSetTime, bool& enterSetAlarm);
+    void leave();
+};
+
+#endif // MENU_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/prefs.cpp	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,185 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#include "global.h"
+
+#include "prefs.h"
+#include "DipCortex-EEprom.h"
+
+#include "VFDDisplay.h"
+#include "IV18Display.h"
+#include "flw.h"
+
+const uint8_t sig0 = 0x42;
+const uint8_t sig1 = 0x66;
+
+PrefsData prefs_data;
+
+extern IV18Display display;
+extern DigitalOut led;
+extern FourLetterWord flw;
+
+static int s_pref_year;
+static int s_pref_month;
+static int s_pref_day;
+
+uint8_t crc8(const void *vptr, int len)
+{
+    const uint8_t *data = static_cast<const uint8_t *>(vptr);
+    unsigned crc = 0;
+    int i, j;
+    
+    for (j = len; j; j--, data++) {
+        crc ^= (*data << 8);
+        for(i = 8; i; i--) {
+            if (crc & 0x8000)
+                crc ^= (0x1070 << 3);
+            crc <<= 1;
+        }
+    }
+    
+    return (uint8_t)(crc >> 8);
+}
+
+void init_prefs()
+{
+    IAP_Init();
+    
+    IAP_Eeprom_Read(0, prefs_data.buf, PREFS_SIZE);
+    
+    bool initialized = false;
+    
+    // check if eeprom has been initialized
+    if (prefs_data.buf[0] == sig0 && prefs_data.buf[1] == sig1) {
+        // check crc
+        uint8_t calc_crc = crc8(prefs_data.buf, PREFS_SIZE-1);
+        
+        if (calc_crc == prefs_data.prefs.crc)
+            initialized = true;
+    }
+    
+    if (!initialized) {        
+        memset(prefs_data.buf, 0, PREFS_SIZE);
+        prefs_data.prefs.sig0 = sig0;
+        prefs_data.prefs.sig1 = sig1;
+        prefs_data.prefs.disp_24h = 1;
+        prefs_data.prefs.brightness = 10;
+        prefs_data.prefs.dots = 1;
+        prefs_data.prefs.gps = 1;
+        prefs_data.prefs.gps_tzh = 9; // Tokyo, Japan
+        prefs_data.prefs.gps_tzm = 0;
+        prefs_data.prefs.auto_date = 1;
+        prefs_data.prefs.flw = 0;
+        prefs_data.prefs.crc = crc8(prefs_data.buf, PREFS_SIZE-1);
+        
+        IAP_Eeprom_Write(0, prefs_data.buf, PREFS_SIZE);
+    }
+}
+
+void save_prefs()
+{
+    uint8_t calc_crc = crc8(prefs_data.buf, PREFS_SIZE-1);
+    
+    if (calc_crc != prefs_data.prefs.crc) {
+        prefs_data.prefs.crc = calc_crc;
+        IAP_Eeprom_Write(0, prefs_data.buf, PREFS_SIZE);
+    }
+}
+
+PrefsData* get_prefs()
+{
+    if (prefs_data.prefs.flw == 2)
+        flw.setCensored(false);
+    else
+        flw.setCensored(true); 
+
+    return &prefs_data;    
+}
+
+void set_year(int year)
+{
+    s_pref_year = year;
+}
+
+void set_month(int month)
+{
+    s_pref_month = month;
+}
+
+void set_day(int day)
+{
+    s_pref_day = day;
+}
+
+
+void set_extra_prefs(int year, int month, int day)
+{
+    s_pref_year = year;
+    s_pref_month = month;
+    s_pref_day = day;
+}
+
+void get_extra_prefs(int& year, int& month, int& day)
+{
+    year = s_pref_year;
+    month = s_pref_month;
+    day = s_pref_day;
+}
+
+void set_pref(PREFS pref, uint32_t value)
+{
+    switch (pref) {
+    case PREF_24H:
+        prefs_data.prefs.disp_24h = value;
+        break;
+    case PREF_BRIGHTNESS:
+        prefs_data.prefs.brightness = value;
+        display.setBrightness(value);
+        break;
+    case PREF_ALARM:
+        prefs_data.prefs.alarm = value;
+        break;
+    case PREF_YEAR:
+        s_pref_year = value;
+        break;
+    case PREF_MONTH:
+        s_pref_month = value;
+        break;
+    case PREF_DAY:
+        s_pref_day = value;
+        break;
+    case PREF_DOTS:
+        prefs_data.prefs.dots = value;
+        break;
+    case PREF_GPS:
+        prefs_data.prefs.gps = value;
+        break;
+    case PREF_GPS_TZH:
+        prefs_data.prefs.gps_tzh = value;
+        break;
+    case PREF_GPS_TZM:
+        prefs_data.prefs.gps_tzm = value;
+        break;
+    case PREF_AUTODATE:
+        prefs_data.prefs.auto_date = value;
+        break;
+    case PREF_FLW:
+        prefs_data.prefs.flw = value;
+        break;
+    default:
+        break;
+    }        
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/prefs.h	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,74 @@
+/*
+ * VFD Modular Clock - mbed
+ * (C) 2011-14 Akafugu Corporation
+ *
+ * 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 2 of the License, or (at your option) any later
+ * version.
+ *
+ * This program 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.
+ *
+ */
+
+#ifndef PREFS_H_
+#define PREFS_H_
+
+const uint8_t PREFS_SIZE = 12;
+
+enum PREFS {
+    PREF_24H = 0,
+    PREF_BRIGHTNESS,
+    PREF_ALARM,
+    PREF_DOTS,
+    PREF_GPS,
+    PREF_GPS_TZH,
+    PREF_GPS_TZM,
+    PREF_AUTODATE,
+    PREF_FLW,
+    // Prefs that are not saved to eeprom
+    PREF_SET_TIME,
+    PREF_SET_ALARM,
+    PREF_YEAR,
+    PREF_MONTH,
+    PREF_DAY,
+    PREF_NULL // placeholder
+};
+
+struct prefs_t {
+    uint8_t sig0; // expected 0x42
+    uint8_t sig1; // expected 0x66
+    uint8_t disp_24h;
+    uint8_t brightness;
+    uint8_t alarm;
+    uint8_t dots;
+    uint8_t gps;
+    int8_t  gps_tzh;
+    uint8_t gps_tzm;
+    uint8_t auto_date;
+    uint8_t flw;
+    uint8_t crc;
+};
+
+union PrefsData {
+    uint8_t buf[12];
+    prefs_t prefs;
+};
+
+void init_prefs();
+void save_prefs();
+PrefsData* get_prefs();
+
+// prefs that are not saved to EEPROM
+void set_year(int year);
+void set_month(int month);
+void set_day(int day);
+
+void set_extra_prefs(int year, int month, int day);
+void get_extra_prefs(int& year, int& month, int& day);
+
+void set_pref(PREFS pref, uint32_t value);
+
+#endif // PREFS_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vfd_modular_clock.uvopt	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<ProjectOpt xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="project_opt.xsd">
+
+  <SchemaVersion>1.0</SchemaVersion>
+
+  <Header>### uVision Project, (C) Keil Software</Header>
+
+  <Extensions>
+    <cExt>*.c</cExt>
+    <aExt>*.s*; *.src; *.a*</aExt>
+    <oExt>*.obj</oExt>
+    <lExt>*.lib</lExt>
+    <tExt>*.txt; *.h; *.inc</tExt>
+    <pExt>*.plm</pExt>
+    <CppX>*.cpp</CppX>
+  </Extensions>
+
+  <DaveTm>
+    <dwLowDateTime>0</dwLowDateTime>
+    <dwHighDateTime>0</dwHighDateTime>
+  </DaveTm>
+
+  <Target>
+    <TargetName>LPC1347</TargetName>
+    <ToolsetNumber>0x4</ToolsetNumber>
+    <ToolsetName>ARM-ADS</ToolsetName>
+    <TargetOption>
+      <CLKADS>12000000</CLKADS>
+      <OPTTT>
+        <gFlags>1</gFlags>
+        <BeepAtEnd>1</BeepAtEnd>
+        <RunSim>1</RunSim>
+        <RunTarget>0</RunTarget>
+      </OPTTT>
+      <OPTHX>
+        <HexSelection>1</HexSelection>
+        <FlashByte>65535</FlashByte>
+        <HexRangeLowAddress>0</HexRangeLowAddress>
+        <HexRangeHighAddress>0</HexRangeHighAddress>
+        <HexOffset>0</HexOffset>
+      </OPTHX>
+      <OPTLEX>
+        <PageWidth>79</PageWidth>
+        <PageLength>66</PageLength>
+        <TabStop>8</TabStop>
+        <ListingPath>.\build\</ListingPath>
+      </OPTLEX>
+      <ListingPage>
+        <CreateCListing>1</CreateCListing>
+        <CreateAListing>1</CreateAListing>
+        <CreateLListing>1</CreateLListing>
+        <CreateIListing>0</CreateIListing>
+        <AsmCond>1</AsmCond>
+        <AsmSymb>1</AsmSymb>
+        <AsmXref>0</AsmXref>
+        <CCond>1</CCond>
+        <CCode>0</CCode>
+        <CListInc>0</CListInc>
+        <CSymb>0</CSymb>
+        <LinkerCodeListing>0</LinkerCodeListing>
+      </ListingPage>
+      <OPTXL>
+        <LMap>1</LMap>
+        <LComments>1</LComments>
+        <LGenerateSymbols>1</LGenerateSymbols>
+        <LLibSym>1</LLibSym>
+        <LLines>1</LLines>
+        <LLocSym>1</LLocSym>
+        <LPubSym>1</LPubSym>
+        <LXref>0</LXref>
+        <LExpSel>0</LExpSel>
+      </OPTXL>
+      <OPTFL>
+        <tvExp>1</tvExp>
+        <tvExpOptDlg>0</tvExpOptDlg>
+        <IsCurrentTarget>1</IsCurrentTarget>
+      </OPTFL>
+      <CpuCode>8</CpuCode>
+      <Books>
+        <Book>
+          <Number>0</Number>
+          <Title>User Manual</Title>
+          <Path>DATASHTS\PHILIPS\LPC13UXX_15_16_17_45_46_47_UM.pdf</Path>
+        </Book>
+        <Book>
+          <Number>1</Number>
+          <Title>Technical Reference Manual</Title>
+          <Path>datashts\arm\cortex_m3\r2p1\DDI0337I_CORTEXM3_R2P1_TRM.PDF</Path>
+        </Book>
+        <Book>
+          <Number>2</Number>
+          <Title>Generic User Guide</Title>
+          <Path>datashts\arm\cortex_m3\r2p1\DUI0552A_CORTEX_M3_DGUG.PDF</Path>
+        </Book>
+      </Books>
+      <DllOpt>
+        <SimDllName>SARMCM3.DLL</SimDllName>
+        <SimDllArguments></SimDllArguments>
+        <SimDlgDllName>DCM.DLL</SimDlgDllName>
+        <SimDlgDllArguments>-pCM3</SimDlgDllArguments>
+        <TargetDllName>SARMCM3.DLL</TargetDllName>
+        <TargetDllArguments></TargetDllArguments>
+        <TargetDlgDllName>TCM.DLL</TargetDlgDllName>
+        <TargetDlgDllArguments>-pCM3</TargetDlgDllArguments>
+      </DllOpt>
+      <DebugOpt>
+        <uSim>0</uSim>
+        <uTrg>1</uTrg>
+        <sLdApp>1</sLdApp>
+        <sGomain>1</sGomain>
+        <sRbreak>1</sRbreak>
+        <sRwatch>1</sRwatch>
+        <sRmem>1</sRmem>
+        <sRfunc>1</sRfunc>
+        <sRbox>1</sRbox>
+        <tLdApp>1</tLdApp>
+        <tGomain>1</tGomain>
+        <tRbreak>1</tRbreak>
+        <tRwatch>1</tRwatch>
+        <tRmem>1</tRmem>
+        <tRfunc>0</tRfunc>
+        <tRbox>1</tRbox>
+        <tRtrace>0</tRtrace>
+        <sRunDeb>0</sRunDeb>
+        <sLrtime>0</sLrtime>
+        <nTsel>9</nTsel>
+        <sDll></sDll>
+        <sDllPa></sDllPa>
+        <sDlgDll></sDlgDll>
+        <sDlgPa></sDlgPa>
+        <sIfile></sIfile>
+        <tDll></tDll>
+        <tDllPa></tDllPa>
+        <tDlgDll></tDlgDll>
+        <tDlgPa></tDlgPa>
+        <tIfile></tIfile>
+        <pMon>BIN\ULP2CM3.DLL</pMon>
+      </DebugOpt>
+      <TargetDriverDllRegistry>
+        <SetRegEntry>
+          <Number>0</Number>
+          <Key>ULP2CM3</Key>
+          <Name>-UP1048454 -O206 -S0 -C0 -P00 -N00("ARM CoreSight SW-DP") -D00(2BA01477) -L00(0) -TO18 -TC10000000 -TP18 -TDX0 -TDD0 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO15 -FD10000000 -FC800 -FN1 -FF0LPC1xxx_64 -FS00 -FL010000</Name>
+        </SetRegEntry>
+        <SetRegEntry>
+          <Number>0</Number>
+          <Key>CMSIS_AGDI</Key>
+          <Name>-X"MBED CMSIS-DAP" -UA000000001 -O206 -S0 -C0 -N00("ARM CoreSight SW-DP") -D00(0BB11477) -L00(0) -FO15 -FD10000000 -FC800 -FN1 -FF0LPC1xxx_32 -FS00 -FL08000</Name>
+        </SetRegEntry>
+      </TargetDriverDllRegistry>
+      <Breakpoint/>
+      <DebugFlag>
+        <trace>0</trace>
+        <periodic>0</periodic>
+        <aLwin>0</aLwin>
+        <aCover>0</aCover>
+        <aSer1>0</aSer1>
+        <aSer2>0</aSer2>
+        <aPa>0</aPa>
+        <viewmode>0</viewmode>
+        <vrSel>0</vrSel>
+        <aSym>0</aSym>
+        <aTbox>0</aTbox>
+        <AscS1>0</AscS1>
+        <AscS2>0</AscS2>
+        <AscS3>0</AscS3>
+        <aSer3>0</aSer3>
+        <eProf>0</eProf>
+        <aLa>0</aLa>
+        <aPa1>0</aPa1>
+        <AscS4>0</AscS4>
+        <aSer4>0</aSer4>
+        <StkLoc>0</StkLoc>
+        <TrcWin>0</TrcWin>
+        <newCpu>0</newCpu>
+        <uProt>0</uProt>
+      </DebugFlag>
+      <LintExecutable></LintExecutable>
+      <LintConfigFile></LintConfigFile>
+    </TargetOption>
+  </Target>
+
+  <Group>
+    <GroupName>src</GroupName>
+    <tvExp>1</tvExp>
+    <tvExpOptDlg>0</tvExpOptDlg>
+    <cbSel>0</cbSel>
+    <File>
+      <GroupNumber>1</GroupNumber>
+      <FileNumber>1</FileNumber>
+      <FileType>8</FileType>
+      <tvExp>0</tvExp>
+      <Focus>0</Focus>
+      <ColumnNumber>0</ColumnNumber>
+      <tvExpOptDlg>0</tvExpOptDlg>
+      <TopLine>1</TopLine>
+      <CurrentLine>2</CurrentLine>
+      <bDave2>0</bDave2>
+      <PathWithFileName>main.cpp</PathWithFileName>
+      <FilenameWithoutPath>main.cpp</FilenameWithoutPath>
+    </File>
+  </Group>
+
+</ProjectOpt>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vfd_modular_clock.uvproj	Mon Feb 09 13:40:46 2015 +0000
@@ -0,0 +1,506 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<Project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="project_proj.xsd">
+
+  <SchemaVersion>1.1</SchemaVersion>
+
+  <Header>###This file was automagically generated by mbed.org. For more information, see http://mbed.org/handbook/Exporting-To-Uvision </Header>
+
+  <Targets>
+    <Target>
+      <TargetName>LPC1347</TargetName>
+      <ToolsetNumber>0x4</ToolsetNumber>
+      <ToolsetName>ARM-ADS</ToolsetName>
+      <TargetOption>
+        <TargetCommonOption>
+          <Device>LPC1347</Device>
+          <Vendor>NXP (founded by Philips)</Vendor>
+          <Cpu>IRAM(0x10000000-0x10001FFF) IRAM2(0x20000000-0x200007FF) IROM(0-0xFFFF) CLOCK(12000000) CPUTYPE("Cortex-M3")</Cpu>
+          <FlashUtilSpec></FlashUtilSpec>
+          <StartupFile>"STARTUP\NXP\LPC13Uxx\startup_LPC13Uxx.s" ("NXP LPC13Uxx Startup Code")</StartupFile>
+          <FlashDriverDll>UL2CM3(-O4303 -S0 -C0 -FO7 -FD10000000 -FC800 -FN1 -FF0LPC1xxx_64 -FS00 -FL010000)</FlashDriverDll>
+          <DeviceId>6286</DeviceId>
+          <RegisterFile>LPC13Uxx.h</RegisterFile>
+          <MemoryEnv></MemoryEnv>
+          <Cmp></Cmp>
+          <Asm></Asm>
+          <Linker></Linker>
+          <OHString></OHString>
+          <InfinionOptionDll></InfinionOptionDll>
+          <SLE66CMisc></SLE66CMisc>
+          <SLE66AMisc></SLE66AMisc>
+          <SLE66LinkerMisc></SLE66LinkerMisc>
+          <SFDFile>SFD\NXP\LPC13Uxx\LPC13Uxx.sfr</SFDFile>
+          <UseEnv>0</UseEnv>
+          <BinPath></BinPath>
+          <IncludePath></IncludePath>
+          <LibPath></LibPath>
+          <RegisterFilePath>NXP\LPC13Uxx\</RegisterFilePath>
+          <DBRegisterFilePath>NXP\LPC13Uxx\</DBRegisterFilePath>
+          <TargetStatus>
+            <Error>0</Error>
+            <ExitCodeStop>0</ExitCodeStop>
+            <ButtonStop>0</ButtonStop>
+            <NotGenerated>0</NotGenerated>
+            <InvalidFlash>1</InvalidFlash>
+          </TargetStatus>
+          <OutputDirectory>.\build\</OutputDirectory>
+          <OutputName>vfd_modular_clock</OutputName>
+          <CreateExecutable>1</CreateExecutable>
+          <CreateLib>0</CreateLib>
+          <CreateHexFile>0</CreateHexFile>
+          <DebugInformation>1</DebugInformation>
+          <BrowseInformation>1</BrowseInformation>
+          <ListingPath>.\build\</ListingPath>
+          <HexFormatSelection>1</HexFormatSelection>
+          <Merge32K>0</Merge32K>
+          <CreateBatchFile>0</CreateBatchFile>
+          <BeforeCompile>
+            <RunUserProg1>0</RunUserProg1>
+            <RunUserProg2>0</RunUserProg2>
+            <UserProg1Name></UserProg1Name>
+            <UserProg2Name></UserProg2Name>
+            <UserProg1Dos16Mode>0</UserProg1Dos16Mode>
+            <UserProg2Dos16Mode>0</UserProg2Dos16Mode>
+          </BeforeCompile>
+          <BeforeMake>
+            <RunUserProg1>0</RunUserProg1>
+            <RunUserProg2>0</RunUserProg2>
+            <UserProg1Name></UserProg1Name>
+            <UserProg2Name></UserProg2Name>
+            <UserProg1Dos16Mode>0</UserProg1Dos16Mode>
+            <UserProg2Dos16Mode>0</UserProg2Dos16Mode>
+          </BeforeMake>
+          <AfterMake>
+            <RunUserProg1>1</RunUserProg1>
+            <RunUserProg2>0</RunUserProg2>
+            <UserProg1Name>fromelf --bin -o build\vfd_modular_clock_LPC1347.bin build\vfd_modular_clock.axf</UserProg1Name>
+            <UserProg2Name></UserProg2Name>
+            <UserProg1Dos16Mode>0</UserProg1Dos16Mode>
+            <UserProg2Dos16Mode>0</UserProg2Dos16Mode>
+          </AfterMake>
+          <SelectedForBatchBuild>0</SelectedForBatchBuild>
+          <SVCSIdString></SVCSIdString>
+        </TargetCommonOption>
+        <CommonProperty>
+          <UseCPPCompiler>0</UseCPPCompiler>
+          <RVCTCodeConst>0</RVCTCodeConst>
+          <RVCTZI>0</RVCTZI>
+          <RVCTOtherData>0</RVCTOtherData>
+          <ModuleSelection>0</ModuleSelection>
+          <IncludeInBuild>1</IncludeInBuild>
+          <AlwaysBuild>0</AlwaysBuild>
+          <GenerateAssemblyFile>0</GenerateAssemblyFile>
+          <AssembleAssemblyFile>0</AssembleAssemblyFile>
+          <PublicsOnly>0</PublicsOnly>
+          <StopOnExitCode>3</StopOnExitCode>
+          <CustomArgument></CustomArgument>
+          <IncludeLibraryModules></IncludeLibraryModules>
+        </CommonProperty>
+        <DllOption>
+          <SimDllName>SARMCM3.DLL</SimDllName>
+          <SimDllArguments></SimDllArguments>
+          <SimDlgDll>DCM.DLL</SimDlgDll>
+          <SimDlgDllArguments>-pCM3</SimDlgDllArguments>
+          <TargetDllName>SARMCM3.DLL</TargetDllName>
+          <TargetDllArguments></TargetDllArguments>
+          <TargetDlgDll>TCM.DLL</TargetDlgDll>
+          <TargetDlgDllArguments>-pCM3</TargetDlgDllArguments>
+        </DllOption>
+        <DebugOption>
+          <OPTHX>
+            <HexSelection>1</HexSelection>
+            <HexRangeLowAddress>0</HexRangeLowAddress>
+            <HexRangeHighAddress>0</HexRangeHighAddress>
+            <HexOffset>0</HexOffset>
+            <Oh166RecLen>16</Oh166RecLen>
+          </OPTHX>
+          <Simulator>
+            <UseSimulator>0</UseSimulator>
+            <LoadApplicationAtStartup>1</LoadApplicationAtStartup>
+            <RunToMain>1</RunToMain>
+            <RestoreBreakpoints>1</RestoreBreakpoints>
+            <RestoreWatchpoints>1</RestoreWatchpoints>
+            <RestoreMemoryDisplay>1</RestoreMemoryDisplay>
+            <RestoreFunctions>1</RestoreFunctions>
+            <RestoreToolbox>1</RestoreToolbox>
+            <LimitSpeedToRealTime>0</LimitSpeedToRealTime>
+          </Simulator>
+          <Target>
+            <UseTarget>1</UseTarget>
+            <LoadApplicationAtStartup>1</LoadApplicationAtStartup>
+            <RunToMain>1</RunToMain>
+            <RestoreBreakpoints>1</RestoreBreakpoints>
+            <RestoreWatchpoints>1</RestoreWatchpoints>
+            <RestoreMemoryDisplay>1</RestoreMemoryDisplay>
+            <RestoreFunctions>0</RestoreFunctions>
+            <RestoreToolbox>1</RestoreToolbox>
+          </Target>
+          <RunDebugAfterBuild>0</RunDebugAfterBuild>
+          <TargetSelection>9</TargetSelection>
+          <SimDlls>
+            <CpuDll></CpuDll>
+            <CpuDllArguments></CpuDllArguments>
+            <PeripheralDll></PeripheralDll>
+            <PeripheralDllArguments></PeripheralDllArguments>
+            <InitializationFile></InitializationFile>
+          </SimDlls>
+          <TargetDlls>
+            <CpuDll></CpuDll>
+            <CpuDllArguments></CpuDllArguments>
+            <PeripheralDll></PeripheralDll>
+            <PeripheralDllArguments></PeripheralDllArguments>
+            <InitializationFile></InitializationFile>
+            <Driver>BIN\ULP2CM3.DLL</Driver>
+          </TargetDlls>
+        </DebugOption>
+        <Utilities>
+          <Flash1>
+            <UseTargetDll>1</UseTargetDll>
+            <UseExternalTool>0</UseExternalTool>
+            <RunIndependent>0</RunIndependent>
+            <UpdateFlashBeforeDebugging>1</UpdateFlashBeforeDebugging>
+            <Capability>1</Capability>
+            <DriverSelection>4101</DriverSelection>
+          </Flash1>
+          <bUseTDR>0</bUseTDR>
+          <Flash2>BIN\ULP2CM3.DLL</Flash2>
+          <Flash3>"" ()</Flash3>
+          <Flash4></Flash4>
+        </Utilities>
+        <TargetArmAds>
+          <ArmAdsMisc>
+            <GenerateListings>0</GenerateListings>
+            <asHll>1</asHll>
+            <asAsm>1</asAsm>
+            <asMacX>1</asMacX>
+            <asSyms>1</asSyms>
+            <asFals>1</asFals>
+            <asDbgD>1</asDbgD>
+            <asForm>1</asForm>
+            <ldLst>0</ldLst>
+            <ldmm>1</ldmm>
+            <ldXref>1</ldXref>
+            <BigEnd>0</BigEnd>
+            <AdsALst>1</AdsALst>
+            <AdsACrf>1</AdsACrf>
+            <AdsANop>0</AdsANop>
+            <AdsANot>0</AdsANot>
+            <AdsLLst>1</AdsLLst>
+            <AdsLmap>1</AdsLmap>
+            <AdsLcgr>1</AdsLcgr>
+            <AdsLsym>1</AdsLsym>
+            <AdsLszi>1</AdsLszi>
+            <AdsLtoi>1</AdsLtoi>
+            <AdsLsun>1</AdsLsun>
+            <AdsLven>1</AdsLven>
+            <AdsLsxf>1</AdsLsxf>
+            <RvctClst>0</RvctClst>
+            <GenPPlst>0</GenPPlst>
+            <AdsCpuType>"Cortex-M3"</AdsCpuType>
+            <RvctDeviceName></RvctDeviceName>
+            <mOS>0</mOS>
+            <uocRom>0</uocRom>
+            <uocRam>0</uocRam>
+            <hadIROM>1</hadIROM>
+            <hadIRAM>1</hadIRAM>
+            <hadXRAM>0</hadXRAM>
+            <uocXRam>0</uocXRam>
+            <RvdsVP>0</RvdsVP>
+            <hadIRAM2>0</hadIRAM2>
+            <hadIROM2>0</hadIROM2>
+            <StupSel>8</StupSel>
+            <useUlib>0</useUlib>
+            <EndSel>0</EndSel>
+            <uLtcg>0</uLtcg>
+            <RoSelD>3</RoSelD>
+            <RwSelD>3</RwSelD>
+            <CodeSel>0</CodeSel>
+            <OptFeed>0</OptFeed>
+            <NoZi1>0</NoZi1>
+            <NoZi2>0</NoZi2>
+            <NoZi3>0</NoZi3>
+            <NoZi4>0</NoZi4>
+            <NoZi5>0</NoZi5>
+            <Ro1Chk>1</Ro1Chk>
+            <Ro2Chk>0</Ro2Chk>
+            <Ro3Chk>0</Ro3Chk>
+            <Ir1Chk>1</Ir1Chk>
+            <Ir2Chk>0</Ir2Chk>
+            <Ra1Chk>0</Ra1Chk>
+            <Ra2Chk>0</Ra2Chk>
+            <Ra3Chk>0</Ra3Chk>
+            <Im1Chk>1</Im1Chk>
+            <Im2Chk>0</Im2Chk>
+            <OnChipMemories>
+              <Ocm1>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </Ocm1>
+              <Ocm2>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </Ocm2>
+              <Ocm3>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </Ocm3>
+              <Ocm4>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </Ocm4>
+              <Ocm5>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </Ocm5>
+              <Ocm6>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </Ocm6>
+              <IRAM>
+                <Type>0</Type>
+                <StartAddress>0x10000000</StartAddress>
+                <Size>0x1000</Size>
+              </IRAM>
+              <IROM>
+                <Type>1</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x8000</Size>
+              </IROM>
+              <XRAM>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </XRAM>
+              <OCR_RVCT1>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </OCR_RVCT1>
+              <OCR_RVCT2>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </OCR_RVCT2>
+              <OCR_RVCT3>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </OCR_RVCT3>
+              <OCR_RVCT4>
+                <Type>1</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x8000</Size>
+              </OCR_RVCT4>
+              <OCR_RVCT5>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </OCR_RVCT5>
+              <OCR_RVCT6>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </OCR_RVCT6>
+              <OCR_RVCT7>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </OCR_RVCT7>
+              <OCR_RVCT8>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </OCR_RVCT8>
+              <OCR_RVCT9>
+                <Type>0</Type>
+                <StartAddress>0x10000000</StartAddress>
+                <Size>0x1000</Size>
+              </OCR_RVCT9>
+              <OCR_RVCT10>
+                <Type>0</Type>
+                <StartAddress>0x0</StartAddress>
+                <Size>0x0</Size>
+              </OCR_RVCT10>
+            </OnChipMemories>
+            <RvctStartVector></RvctStartVector>
+          </ArmAdsMisc>
+          <Cads>
+            <interw>1</interw>
+            <Optim>1</Optim>
+            <oTime>0</oTime>
+            <SplitLS>0</SplitLS>
+            <OneElfS>0</OneElfS>
+            <Strict>0</Strict>
+            <EnumInt>0</EnumInt>
+            <PlainCh>0</PlainCh>
+            <Ropi>0</Ropi>
+            <Rwpi>0</Rwpi>
+            <wLevel>0</wLevel>
+            <uThumb>0</uThumb>
+            <VariousControls>
+              <MiscControls>--gnu --no_rtti </MiscControls>
+              <Define> TARGET_LPC1347,  TARGET_M3,  TARGET_CORTEX_M,  TARGET_NXP,  TARGET_LPC13XX,  TOOLCHAIN_ARM_STD,  TOOLCHAIN_ARM,  __CORTEX_M3,  ARM_MATH_CM3,  MBED_BUILD_TIMESTAMP=1421281797.28,  __MBED__=1,  __ASSERT_MSG, </Define>
+              <Undefine></Undefine>
+              <IncludePath>  .;  beep;  DipCortex-EEprom;  RTC;  mbed;  mbed/TARGET_LPC1347;  mbed/TARGET_LPC1347/TOOLCHAIN_ARM_STD;  mbed/TARGET_LPC1347/TARGET_NXP;  mbed/TARGET_LPC1347/TARGET_NXP/TARGET_LPC13XX;  </IncludePath>
+            </VariousControls>
+          </Cads>
+          <Aads>
+            <interw>1</interw>
+            <Ropi>0</Ropi>
+            <Rwpi>0</Rwpi>
+            <thumb>0</thumb>
+            <SplitLS>0</SplitLS>
+            <SwStkChk>0</SwStkChk>
+            <NoWarn>0</NoWarn>
+            <VariousControls>
+              <MiscControls></MiscControls>
+              <Define></Define>
+              <Undefine></Undefine>
+              <IncludePath></IncludePath>
+            </VariousControls>
+          </Aads>
+          <LDads>
+            <umfTarg>0</umfTarg>
+            <Ropi>0</Ropi>
+            <Rwpi>0</Rwpi>
+            <noStLib>0</noStLib>
+            <RepFail>1</RepFail>
+            <useFile>0</useFile>
+            <TextAddressRange>0x00000000</TextAddressRange>
+            <DataAddressRange>0x10000000</DataAddressRange>
+            <ScatterFile>mbed/TARGET_LPC1347/TOOLCHAIN_ARM_STD/LPC1347.sct</ScatterFile>
+            <IncludeLibs></IncludeLibs>
+            <IncludeLibsPath></IncludeLibsPath>
+            <Misc>
+            
+              mbed/TARGET_LPC1347/TOOLCHAIN_ARM_STD/retarget.o
+            
+              mbed/TARGET_LPC1347/TOOLCHAIN_ARM_STD/startup_LPC13xx.o
+            
+              mbed/TARGET_LPC1347/TOOLCHAIN_ARM_STD/board.o
+            
+              mbed/TARGET_LPC1347/TOOLCHAIN_ARM_STD/cmsis_nvic.o
+            
+              mbed/TARGET_LPC1347/TOOLCHAIN_ARM_STD/system_LPC13Uxx.o
+            
+              mbed/TARGET_LPC1347/TOOLCHAIN_ARM_STD/sys.o
+            
+              mbed/TARGET_LPC1347/TOOLCHAIN_ARM_STD/mbed.ar
+            
+            </Misc>
+            <LinkerInputFile></LinkerInputFile>
+            <DisabledWarnings></DisabledWarnings>
+          </LDads>
+        </TargetArmAds>
+      </TargetOption>
+      <Groups>
+        
+        <Group>
+          <GroupName>src</GroupName>
+          <Files>
+            
+            <File>
+              <FileName>button.cpp</FileName>
+              <FileType>8</FileType>
+              <FilePath>button.cpp</FilePath>
+              
+            </File>
+          
+            <File>
+              <FileName>prefs.cpp</FileName>
+              <FileType>8</FileType>
+              <FilePath>prefs.cpp</FilePath>
+              
+            </File>
+          
+            <File>
+              <FileName>main.cpp</FileName>
+              <FileType>8</FileType>
+              <FilePath>main.cpp</FilePath>
+              
+            </File>
+          
+            <File>
+              <FileName>gps.cpp</FileName>
+              <FileType>8</FileType>
+              <FilePath>gps.cpp</FilePath>
+              
+            </File>
+          
+            <File>
+              <FileName>VFDDisplay.cpp</FileName>
+              <FileType>8</FileType>
+              <FilePath>VFDDisplay.cpp</FilePath>
+              
+            </File>
+          
+            <File>
+              <FileName>menu.cpp</FileName>
+              <FileType>8</FileType>
+              <FilePath>menu.cpp</FilePath>
+              
+            </File>
+          
+            <File>
+              <FileName>font_7seg.cpp</FileName>
+              <FileType>8</FileType>
+              <FilePath>font_7seg.cpp</FilePath>
+              
+            </File>
+          
+            <File>
+              <FileName>IV18Display.cpp</FileName>
+              <FileType>8</FileType>
+              <FilePath>IV18Display.cpp</FilePath>
+              
+            </File>
+          
+            <File>
+              <FileName>beep.cpp</FileName>
+              <FileType>8</FileType>
+              <FilePath>beep/beep.cpp</FilePath>
+              
+            </File>
+          
+            <File>
+              <FileName>DipCortex-EEprom.cpp</FileName>
+              <FileType>8</FileType>
+              <FilePath>DipCortex-EEprom/DipCortex-EEprom.cpp</FilePath>
+              
+            </File>
+          
+            <File>
+              <FileName>rtc.cpp</FileName>
+              <FileType>8</FileType>
+              <FilePath>RTC/rtc.cpp</FilePath>
+              
+            </File>
+          
+            <File>
+              <FileName>ds3231m.cpp</FileName>
+              <FileType>8</FileType>
+              <FilePath>RTC/ds3231m.cpp</FilePath>
+              
+            </File>
+          
+            <File>
+              <FileName>ds1302.cpp</FileName>
+              <FileType>8</FileType>
+              <FilePath>RTC/ds1302.cpp</FilePath>
+              
+            </File>
+          
+          </Files>
+        </Group>
+        
+      </Groups>
+    </Target>
+  </Targets>
+
+</Project>
\ No newline at end of file