Yoshiyuki Uehara / Mbed 2 deprecated Maple

Dependencies:   mbed

Revision:
1:aefa1992ce0f
Parent:
0:0be38b583cf7
Child:
2:299a1c9a5795
--- a/Maple_alarm_clock.cpp	Sun Sep 25 11:37:21 2011 +0000
+++ b/Maple_alarm_clock.cpp	Mon Oct 10 11:45:51 2011 +0000
@@ -1,6 +1,13 @@
+//copyright 2011 Uehara Yoshiyuki
+//====================================================================
+//The author provide the programs without any guarantees or warranty.
+//The author is not responsible for any damage or losses of any kind 
+//caused by using or misusing of the programs.
+//The author is under no obligation to provide support, service, 
+//corrections, or upgrades to the programs.
+//====================================================================
 // MAPLE board[MARM01-BASE]
-// sample application - clock
-//
+// alarm clock
 #include "Maple_alarm_clock.h"
 #include "Maple_RTC.h"
 #include "Maple_I2C.h"
@@ -12,279 +19,426 @@
 Ticker alarm_clock_refresh_tick;
 
 // global variables
-int BTN_count[6];
-int BTN_status[6];
-int display_mode ;
-int cursor_position;
-const int cursor_position_date_time_max = 6;
+int alarm_clock_mode;
+int alarm_clock_cursor;
+int button_count[6];
+int button_status[6];
 
 // alarm_clock_initialize
 void alarm_clock_initialize() {
     alarm_clock_refresh_tick.attach(&alarm_clock_refresh, ALARM_CLOCK_REFRESH_RATE);
+    alarm_clock_mode = MODE_NORMAL;
+    alarm_clock_cursor = CURSOR_NORMAL_ALARM_FLAG;
+    for (int i = 0; i < 6; ++i) {
+        button_count[i] = 0;
+        button_status[i] = BUTTON_IDLE;
+    }
 }
 
 // refresh display, called by a ticker
 void alarm_clock_refresh() {
-    char format_date[15];   // "yyyy.mm.dd www"
-    char format_time[9];    // "hh:mm:ss"
-    const int cursor_date_time_row[7]    = {0, 0, 0, 0, 1, 1, 1};
-    const int cursor_date_time_column[7] = {1, 3, 6, 9, 1, 4, 7};
-
-    if(display_mode == DISPLAY_MODE_DATE_TIME) {
-        LCD_cursor(LCD_CURSOR_OFF);
-        LCD_locate(1, 10);  LCD_print_string("      ");
-
-        RTC_read_format(format_date, format_time);
-        LCD_locate(0,  0);  LCD_print_string(format_date);
-        LCD_locate(1,  0);  LCD_print_string(format_time);
-    }
-    
-    if(display_mode == DISPLAY_MODE_DATE_TIME_ADJUST) {
-        LCD_cursor(LCD_CURSOR_OFF);
-        LCD_locate(1, 10);  LCD_print_string("adjust");
-
-        RTC_read_format(format_date, format_time);
-        LCD_locate(0,  0);  LCD_print_string(format_date);
-        LCD_locate(1,  0);  LCD_print_string(format_time);
-
-        LCD_locate(cursor_date_time_row[cursor_position], cursor_date_time_column[cursor_position]);
-        LCD_cursor(LCD_CURSOR_ON);
-    }
-
-    BTN_check(BTN_count, BTN_status);
+    alarm_clock_refresh_display();
+    button_check();
 }
 
-// read BTN and update BTN_on_count[i]
-//   called by timer tick interrupt
-static void BTN_check(int count[], int status[]) {
-    char b;
+// read RTC and print to LCD
+static void alarm_clock_refresh_display() {
+    const int cursor_row[4][10] = {
+        { 1,  1, 16, 16, 16, 16, 16, 16, 16, 16},   // MODE_NORMAL
+        { 0,  0,  0,  0,  1,  1,  1, 16, 16, 16},   // MODE_ADJUST
+        { 0,  0,  0,  0,  0,  0,  1,  1,  1,  1},   // MODE_ALARM
+        { 0,  0,  0,  0,  0,  0,  0,  1, 16, 16},   // MODE_TIMER
+    };
+    const int cursor_column[4][10] = {
+        {12, 15, 16, 16, 16, 16, 16, 16, 16, 16},   // NODE_NORMAL
+        { 1,  3,  6,  9,  1,  4,  7, 16, 16, 16},   // MODE_ADJUST
+        { 4,  6,  8, 11, 14, 15,  0,  2,  4,  6},   // MODE_ALARM
+        { 3,  8, 11, 12, 13, 14, 15,  6, 16, 16},   // MODE_TIMER
+    };
+    const char frequency_select[4][6] = { "32768", " 1024", "   32", "    1" };
+    const char timer_select[4][5] = { "4096", "  64", "   1", "1/60" };
+    char row0[17], row1[17], d[17], s[4];
+
+    i2c_RTC_read(RTC_REG_CONTROL1, d, 16);
 
-    b = i2c_BTN_read();
-    if((b & BTN_MASK_A    ) == BTN_ON) { ++count[BTN_A    ]; } else { count[BTN_A    ] = 0; status[BTN_A    ] = BTN_IDLE; }
-    if((b & BTN_MASK_B    ) == BTN_ON) { ++count[BTN_B    ]; } else { count[BTN_B    ] = 0; status[BTN_B    ] = BTN_IDLE; }
-    if((b & BTN_MASK_LEFT ) == BTN_ON) { ++count[BTN_LEFT ]; } else { count[BTN_LEFT ] = 0; status[BTN_LEFT ] = BTN_IDLE; }
-    if((b & BTN_MASK_DOWN ) == BTN_ON) { ++count[BTN_DOWN ]; } else { count[BTN_DOWN ] = 0; status[BTN_DOWN ] = BTN_IDLE; }
-    if((b & BTN_MASK_RIGHT) == BTN_ON) { ++count[BTN_RIGHT]; } else { count[BTN_RIGHT] = 0; status[BTN_RIGHT] = BTN_IDLE; }
-    if((b & BTN_MASK_UP   ) == BTN_ON) { ++count[BTN_UP   ]; } else { count[BTN_UP   ] = 0; status[BTN_UP   ] = BTN_IDLE; }
+    switch(alarm_clock_mode) {
+    case MODE_NORMAL:
+        copy_string(row0, 0, 17, "XXXX.XX.XX XXX  ");
+        copy_string(row1, 0, 17, "XX:XX:XX XXXXXXX");
+        if((d[RTC_REG_SECOND] & RTC_VOLTAGE_LOW) == 0) {    // when RTC registers are valid: 
+            copy_string(row0, 0, 2, "20");
+            if((d[RTC_REG_MONTH_CENTURY   ] & RTC_CENTURY               ) != 0) { row0[ 1] = '1'; }
+            copy_string(row0,  2, 2, int_to_hex2(d[RTC_REG_YEAR         ]       , s));
+            copy_string(row0,  5, 2, int_to_hex2(d[RTC_REG_MONTH_CENTURY] & 0x1f, s));
+            copy_string(row0,  8, 2, int_to_hex2(d[RTC_REG_DAY          ] & 0x3f, s));
+            copy_string(row0, 11, 3, weekday_to_string(d[RTC_REG_WEEKDAY] & 0x07, s));
+            copy_string(row1,  0, 2, int_to_hex2(d[RTC_REG_HOUR         ] & 0x3f, s));
+            copy_string(row1,  3, 2, int_to_hex2(d[RTC_REG_MINUTE       ] & 0x7f, s));
+            copy_string(row1,  6, 2, int_to_hex2(d[RTC_REG_SECOND       ] & 0x7f, s));
+            copy_string(row1, 10, 6, "------");
+            if((d[RTC_REG_CONTROL2        ] & RTC_TIMER_PERIODIC        ) != 0) { row1[ 9] = 'p'; }
+            if((d[RTC_REG_TIMER_CONTROL   ] & RTC_TIMER_ENABLE          ) != 0) { row1[10] = 't'; }
+            if((d[RTC_REG_CONTROL2        ] & RTC_TIMER_INTERRUPT_ENABLE) != 0) { row1[11] = 'i'; }
+            if((d[RTC_REG_CONTROL2        ] & RTC_TIMER_FLAG            ) != 0) { row1[12] = 'T'; }
+            if((d[RTC_REG_ALARM_MINUTE    ] & RTC_ALARM_DISABLE         ) == 0) { row1[13] = 'a'; }
+            if((d[RTC_REG_ALARM_HOUR      ] & RTC_ALARM_DISABLE         ) == 0) { row1[13] = 'a'; }
+            if((d[RTC_REG_ALARM_DAY       ] & RTC_ALARM_DISABLE         ) == 0) { row1[13] = 'a'; }
+            if((d[RTC_REG_ALARM_WEEKDAY   ] & RTC_ALARM_DISABLE         ) == 0) { row1[13] = 'a'; }
+            if((d[RTC_REG_CONTROL2        ] & RTC_ALARM_INTERRUPT_ENABLE) != 0) { row1[14] = 'i'; }
+            if((d[RTC_REG_CONTROL2        ] & RTC_ALARM_FLAG            ) != 0) { row1[15] = 'A'; }
+        }
+        break;
+
+    case MODE_ADJUST:
+        copy_string(row0, 0, 17, "XXXX.XX.XX XXX  ");
+        copy_string(row1, 0, 17, "XX:XX:XX  adjust");
+        if((d[RTC_REG_SECOND] & RTC_VOLTAGE_LOW) == 0) {    // when RTC registers are valid: 
+            copy_string(row0, 0, 2, "20");
+            if((d[RTC_REG_MONTH_CENTURY   ] & RTC_CENTURY               ) != 0) { row0[ 1] = '1'; }
+            copy_string(row0,  2, 2, int_to_hex2(d[RTC_REG_YEAR         ]       , s));
+            copy_string(row0,  5, 2, int_to_hex2(d[RTC_REG_MONTH_CENTURY] & 0x1f, s));
+            copy_string(row0,  8, 2, int_to_hex2(d[RTC_REG_DAY          ] & 0x3f, s));
+            copy_string(row0, 11, 3, weekday_to_string(d[RTC_REG_WEEKDAY] & 0x07, s));
+            copy_string(row1,  0, 2, int_to_hex2(d[RTC_REG_HOUR         ] & 0x3f, s));
+            copy_string(row1,  3, 2, int_to_hex2(d[RTC_REG_MINUTE       ] & 0x7f, s));
+            copy_string(row1,  6, 2, int_to_hex2(d[RTC_REG_SECOND       ] & 0x7f, s));
+        }
+        break;
 
-    if((status[BTN_A] == BTN_IDLE) && (count[BTN_A] > BTN_THRESHOLD)) {
-        status[BTN_A] = BTN_BUSY;
-        BTN_A_action();     // one shot
-    }
+    case MODE_ALARM:
+        copy_string(row0, 0, 17, "day:XXX XXXX XXX");
+        copy_string(row1, 0, 17, "XXX:XXX    alarm");
+        if((d[RTC_REG_SECOND] & RTC_VOLTAGE_LOW) == 0) {    // when RTC registers are valid: 
+            row0[ 4] = '-';
+            row0[ 8] = '-';
+            copy_string(row0, 13, 3, "---");
+            row1[ 0] = '-';
+            row1[ 4] = '-';
+            copy_string(row0, 5, 2, int_to_hex2(d[RTC_REG_ALARM_DAY          ] & 0x3f, s));
+            copy_string(row0, 9, 3, weekday_to_string(d[RTC_REG_ALARM_WEEKDAY] & 0x07, s));
+            copy_string(row1, 1, 2, int_to_hex2(d[RTC_REG_ALARM_HOUR         ] & 0x3f, s));
+            copy_string(row1, 5, 2, int_to_hex2(d[RTC_REG_ALARM_MINUTE       ] & 0x7f, s));
+            if((d[RTC_REG_ALARM_DAY    ] & RTC_ALARM_DISABLE         ) == 0) { row0[13] = 'a';  row0[ 4] = '*'; }
+            if((d[RTC_REG_ALARM_WEEKDAY] & RTC_ALARM_DISABLE         ) == 0) { row0[13] = 'a';  row0[ 8] = '*'; }
+            if((d[RTC_REG_ALARM_HOUR   ] & RTC_ALARM_DISABLE         ) == 0) { row0[13] = 'a';  row1[ 0] = '*'; }
+            if((d[RTC_REG_ALARM_MINUTE ] & RTC_ALARM_DISABLE         ) == 0) { row0[13] = 'a';  row1[ 4] = '*'; }
+            if((d[RTC_REG_CONTROL2     ] & RTC_ALARM_INTERRUPT_ENABLE) != 0) { row0[14] = 'i'; }
+            if((d[RTC_REG_CONTROL2     ] & RTC_ALARM_FLAG            ) != 0) { row0[15] = 'A'; }
+        }
+        break;
 
-    if((status[BTN_B] == BTN_IDLE) && (count[BTN_B] > BTN_THRESHOLD)) {
-        status[BTN_B] = BTN_BUSY;
-        BTN_B_action();     // one shot
-    }
+    case MODE_TIMER:
+        copy_string(row0, 0, 17, "XXXXHz XX  XXXXX");
+        copy_string(row1, 0, 17, "f=XXXXXHz  timer");
+        if((d[RTC_REG_SECOND] & RTC_VOLTAGE_LOW) == 0) {    // when RTC registers are valid: 
+            copy_string(row0,  0, 4, timer_select[d[RTC_REG_TIMER_CONTROL] & 0x03]);
+            copy_string(row0,  7, 2, int_to_hex2(d[RTC_REG_TIMER], s));
+            copy_string(row1,  2, 5, frequency_select[d[RTC_REG_CLKOUT_FREQUENCY] & 0x03]);
+            copy_string(row0, 11, 5, "-----");
+            if((d[RTC_REG_CLKOUT_FREQUENCY] & RTC_CLKOUT_ENABLE         ) != 0) { row0[11] = 'f'; }
+            if((d[RTC_REG_CONTROL2        ] & RTC_TIMER_PERIODIC        ) != 0) { row0[12] = 'p'; }
+            if((d[RTC_REG_TIMER_CONTROL   ] & RTC_TIMER_ENABLE          ) != 0) { row0[13] = 't'; }
+            if((d[RTC_REG_CONTROL2        ] & RTC_TIMER_INTERRUPT_ENABLE) != 0) { row0[14] = 'i'; }
+            if((d[RTC_REG_CONTROL2        ] & RTC_TIMER_FLAG            ) != 0) { row0[15] = 'T'; }
+        }
+        break;
+    }    
 
-    if((status[BTN_LEFT] == BTN_IDLE) && (count[BTN_LEFT] > BTN_THRESHOLD)) {
-        status[BTN_LEFT] = BTN_BUSY;
-        BTN_LEFT_action();  // one shot
-    }
-    else if((count[BTN_LEFT] > BTN_REPEAT) && (count[BTN_LEFT] % BTN_REPEAT_PERIOD == 0)) {
-        BTN_LEFT_action();  // auto repeat
+    LCD_cursor(LCD_CURSOR_OFF);
+    LCD_locate(0, 0);
+    LCD_print_string(row0);
+    LCD_locate(1, 0);
+    LCD_print_string(row1);
+    LCD_locate(cursor_row[alarm_clock_mode][alarm_clock_cursor], cursor_column[alarm_clock_mode][alarm_clock_cursor]);
+    LCD_cursor(LCD_CURSOR_ON);
+}
+
+// read button and update button_on_count[i]
+//   called by timer tick interrupt
+static void button_check() {
+    char r = i2c_BTN_read();
+    button_on_check(r, BUTTON_A    );
+    button_on_check(r, BUTTON_B    );
+    button_on_check(r, BUTTON_LEFT );
+    button_on_check(r, BUTTON_DOWN );
+    button_on_check(r, BUTTON_RIGHT);
+    button_on_check(r, BUTTON_UP   );
+    if(button_trigger(BUTTON_A,     0, 0)) { button_exit();         }
+    if(button_trigger(BUTTON_B,     0, 0)) { button_function();     }
+    if(button_trigger(BUTTON_LEFT,  1, 0)) { button_cursor_move(0); }
+    if(button_trigger(BUTTON_RIGHT, 1, 0)) { button_cursor_move(1); }
+    if(button_trigger(BUTTON_DOWN,  1, 1)) { button_xxcrement(0);   }
+    if(button_trigger(BUTTON_UP,    1, 1)) { button_xxcrement(1);   }
+}
+
+// button on check
+static void button_on_check(int read_data, int button_number) {
+    if((read_data & (0x01 << button_number)) == BUTTON_ON) {
+        ++button_count[button_number];
     }
-
-    if((status[BTN_DOWN] == BTN_IDLE) && (count[BTN_DOWN] > BTN_THRESHOLD)) {
-        status[BTN_DOWN] = BTN_BUSY;
-        BTN_DOWN_action();  // one shot
-    }
-    else if((count[BTN_DOWN] > BTN_REPEAT_FAST) && (count[BTN_DOWN] % BTN_REPEAT_PERIOD_FAST == 0)) {
-        BTN_DOWN_action();  // auto repeat fast
-    }
-    else if((count[BTN_DOWN] > BTN_REPEAT) && (count[BTN_DOWN] % BTN_REPEAT_PERIOD == 0)) {
-        BTN_DOWN_action();  // auto repeat
-    }
-
-    if((status[BTN_RIGHT] == BTN_IDLE) && (count[BTN_RIGHT] > BTN_THRESHOLD)) {
-        status[BTN_RIGHT] = BTN_BUSY;
-        BTN_RIGHT_action(); // one shot
-    }
-    else if((count[BTN_RIGHT] > BTN_REPEAT) && (count[BTN_RIGHT] % BTN_REPEAT_PERIOD == 0)) {
-        BTN_RIGHT_action(); // auto repeat
-    }
-
-    if((status[BTN_UP] == BTN_IDLE) && (count[BTN_UP] > BTN_THRESHOLD)) {
-        status[BTN_UP] = BTN_BUSY;
-        BTN_UP_action();    // one shot
-    }
-    else if((count[BTN_UP] > BTN_REPEAT_FAST) && (count[BTN_UP] % BTN_REPEAT_PERIOD_FAST == 0)) {
-        BTN_UP_action();    // auto repeat fast
-    }
-    else if((count[BTN_UP] > BTN_REPEAT) && (count[BTN_UP] % BTN_REPEAT_PERIOD == 0)) {
-        BTN_UP_action();    // auto repeat
+    else {
+        button_count[button_number] = 0;
+        button_status[button_number] = BUTTON_IDLE;
     }
 }
 
-// BTN_A: enter function mode
-static void BTN_A_action() {
-    if(display_mode == DISPLAY_MODE_DATE_TIME) {
-        display_mode = DISPLAY_MODE_DATE_TIME_ADJUST;
-        cursor_position = CURSOR_DATE_TIME_SECOND;
+// button action trigger check
+//   b: button number
+//   r: repeat enable
+//   f: fast-repeat enable
+static bool button_trigger(int b, int r, int f) {
+    if((button_status[b] == BUTTON_IDLE) && (button_count[b] > BUTTON_THRESHOLD)) {
+        button_status[b] = BUTTON_BUSY;
+        return true;    // one shot
+    }
+    else if((f != 0) && (button_count[b] > BUTTON_FAST) && (button_count[b] % BUTTON_PERIOD_FAST == 0)) {
+        return true;    // repeat fast
+    }
+    else if((r != 0) && (button_count[b] > BUTTON_REPEAT) && (button_count[b] % BUTTON_PERIOD_REPEAT == 0)) {
+        return true;    // repeat
+    }
+    else {
+        return false;
     }
 }
 
-// BTN_A: exit to date-time mode
-static void BTN_B_action() {
-    display_mode = DISPLAY_MODE_DATE_TIME;
+// exit to normal mode
+static void button_exit() {
+    alarm_clock_mode = MODE_NORMAL;
+    alarm_clock_cursor = CURSOR_NORMAL_ALARM_FLAG;
 }
 
-// BTN_RIGHT: move cursor backward
-static void BTN_LEFT_action() {
-    if(display_mode == DISPLAY_MODE_DATE_TIME_ADJUST) {
-        if(cursor_position > 0) {
-            --cursor_position;
-        }
-        else {
-            cursor_position = cursor_position_date_time_max;
-        }
+// select a function
+static void button_function() {
+    switch(alarm_clock_mode) {
+    case MODE_NORMAL:
+        alarm_clock_mode = MODE_ADJUST;
+        alarm_clock_cursor = CURSOR_ADJUST_SECOND;
+        break;
+    case MODE_ADJUST:
+        alarm_clock_mode = MODE_ALARM;
+        alarm_clock_cursor = CURSOR_ALARM_FLAG;
+        break;
+    case MODE_ALARM:
+        alarm_clock_mode = MODE_TIMER;
+        alarm_clock_cursor = CURSOR_TIMER_FLAG;
+        break;
+    case MODE_TIMER:
+        alarm_clock_mode = MODE_NORMAL;
+        alarm_clock_cursor = CURSOR_NORMAL_ALARM_FLAG;
+        break;
     }
 }
 
-// decrement date/time
-static void BTN_DOWN_action() {
-    char century, bcd_year, bcd_month, bcd_day, weekday, d, t;
-
-    if(display_mode == DISPLAY_MODE_DATE_TIME_ADJUST) {
-
-        switch(cursor_position) {
+// move cursor
+//   flag  0:left, 1:right
+static void button_cursor_move(int flag) {
+    const int max[4] = { CURSOR_NORMAL_MAX, CURSOR_ADJUST_MAX, CURSOR_ALARM_MAX, CURSOR_TIMER_MAX };
 
-        case CURSOR_DATE_TIME_CENTURY:
-            RTC_stop_and_read_date(century, bcd_year, bcd_month, bcd_day);
-            century = decrement_bcd(century, 0x00, 0x01);
-            d = bcd_days_in_month(century, bcd_year, bcd_month);
-            if(bcd_day > d) {
-                bcd_day = d;
-            }
-            weekday = bcd_date_to_weekday(century, bcd_year, bcd_month, bcd_day);
-            RTC_write_date_and_start(century, bcd_year, bcd_month, bcd_day, weekday);
-            break;
-
-        case CURSOR_DATE_TIME_YEAR:
-            RTC_stop_and_read_date(century, bcd_year, bcd_month, bcd_day);
-            bcd_year = decrement_bcd(bcd_year, 0x00, 0x99);
-            d = bcd_days_in_month(century, bcd_year, bcd_month);
-            if(bcd_day > d) {
-                bcd_day = d;
-            }
-            weekday = bcd_date_to_weekday(century, bcd_year, bcd_month, bcd_day);
-            RTC_write_date_and_start(century, bcd_year, bcd_month, bcd_day, weekday);
-            break;
+    switch(flag) {
+    case 0:  // move left .. decrement
+        if(alarm_clock_cursor > 0) {
+            --alarm_clock_cursor;
+        }
+        else {
+            alarm_clock_cursor = max[alarm_clock_mode];
+        }
+        break;
+    case 1:  // move right .. increment
+        ++alarm_clock_cursor;
+        if(alarm_clock_cursor > max[alarm_clock_mode]) {
+            alarm_clock_cursor = 0;
+        }
+        break;
+    }
+}
 
-        case CURSOR_DATE_TIME_MONTH:
-            RTC_stop_and_read_date(century, bcd_year, bcd_month, bcd_day);
-            bcd_month = decrement_bcd(bcd_month, 0x01, 0x12);
-            d = bcd_days_in_month(century, bcd_year, bcd_month);
-            if(bcd_day > d) {
-                bcd_day = d;
-            }
-            weekday = bcd_date_to_weekday(century, bcd_year, bcd_month, bcd_day);
-            RTC_write_date_and_start(century, bcd_year, bcd_month, bcd_day, weekday);
-            break;
+// increment/decrement
+//   flag 0:decrement, 1:increment
+static void button_xxcrement(int flag) {
+    switch(alarm_clock_mode) {
+    case MODE_NORMAL:
+        button_xxcrement_normal(flag);
+        break;
+    case MODE_ADJUST:
+        button_xxcrement_adjust(flag);
+        break;
+    case MODE_ALARM:
+        button_xxcrement_alarm(flag);
+        break;
+    case MODE_TIMER:
+        button_xxcrement_timer(flag);
+        break;
+    }
+}
 
-        case CURSOR_DATE_TIME_DAY:
-            RTC_stop_and_read_date(century, bcd_year, bcd_month, bcd_day);
-            bcd_day = decrement_bcd(bcd_day, 0x01, bcd_days_in_month(century, bcd_year, bcd_month));
-            weekday = bcd_date_to_weekday(century, bcd_year, bcd_month, bcd_day);
-            RTC_write_date_and_start(century, bcd_year, bcd_month, bcd_day, weekday);
-           break;
+// increment/decrement for NORMAL
+//   flag  0:decrement, 1:increment
+static void button_xxcrement_normal(int flag) {
+    char d;
 
-        case CURSOR_DATE_TIME_HOUR:
-            t = RTC_stop_and_read1(RTC_REG_HOUR) & 0x3F;
-            t = decrement_bcd(t, 0x00, 0x23);
-            RTC_write1_and_start(RTC_REG_HOUR, t);
-            break;
+    d = RTC_read1(RTC_REG_CONTROL2);
+    switch(alarm_clock_cursor) {
+    case CURSOR_NORMAL_TIMER_FLAG:
+        d = d & 0x1b | (flag == 0 ? 0x00 : 0x04);
+        break;
+    case CURSOR_NORMAL_ALARM_FLAG:
+        d = d & 0x17 | (flag == 0 ? 0x00 : 0x08);
+        break;
+    }
+    RTC_write1(RTC_REG_CONTROL2, d);
+}
+
+// increment/decrement for ADJUST
+//   flag  0:decrement, 1:increment
+static void button_xxcrement_adjust(int flag) {
+    char d;
 
-        case CURSOR_DATE_TIME_MINUTE:
-            t = RTC_stop_and_read1(RTC_REG_MINUTE) & 0x7F;
-            t = decrement_bcd(t, 0x00, 0x59);
-            RTC_write1_and_start(RTC_REG_MINUTE, t);
-            break;
-
-        case CURSOR_DATE_TIME_SECOND:
-            t = RTC_stop_and_read1(RTC_REG_SECOND) & 0x7f;
-            t = 0x30;
-            RTC_write1_and_start(RTC_REG_SECOND, t);
-            break;
-        }
+    switch(alarm_clock_cursor) {
+    case CURSOR_ADJUST_HOUR:
+        d = RTC_stop_read1(RTC_REG_HOUR) & 0x3F;
+        d = xxcrement_bcd(flag, d, 0x00, 0x23);
+        RTC_write1_start(RTC_REG_HOUR, d);
+        break;
+    case CURSOR_ADJUST_MINUTE:
+        d = RTC_stop_read1(RTC_REG_MINUTE) & 0x7F;
+        d = xxcrement_bcd(flag, d, 0x00, 0x59);
+        RTC_write1_start(RTC_REG_MINUTE, d);
+        break;
+    case CURSOR_ADJUST_SECOND:
+        d = RTC_stop_read1(RTC_REG_SECOND) & 0x7f;
+        d = (flag == 0 ? 0x30 : 0x00);
+        RTC_write1_start(RTC_REG_SECOND, d);
+        break;
+    default:
+        button_xxcrement_adjust_date(flag);
     }
 }
 
-// BTN_RIGHT: move cursor forward
-static void BTN_RIGHT_action() {
-    if(display_mode == DISPLAY_MODE_DATE_TIME_ADJUST) {
-        ++cursor_position;
-        if(cursor_position > cursor_position_date_time_max) {
-            cursor_position = 0;
-        }
+// increment/decrement century, year, month, day
+//   flag  0:decrement, 1:increment
+static void button_xxcrement_adjust_date(int flag) {
+    char century, bcd_year, bcd_month, bcd_day, weekday, d;
+
+    RTC_stop_read_date(century, bcd_year, bcd_month, bcd_day);
+    switch(alarm_clock_cursor) {
+    case CURSOR_ADJUST_CENTURY:
+        century = xxcrement_bcd(flag, century, 0x00, 0x01);
+        break;    
+    case CURSOR_ADJUST_YEAR:
+        bcd_year = xxcrement_bcd(flag, bcd_year, 0x00, 0x99);
+        break;
+    case CURSOR_ADJUST_MONTH:
+        bcd_month = xxcrement_bcd(flag, bcd_month, 0x01, 0x12);
+        break;
+    case CURSOR_ADJUST_DAY:
+        bcd_day = xxcrement_bcd(flag, bcd_day, 0x01, bcd_days_in_month(century, bcd_year, bcd_month));
+        break;
+    }
+    d = bcd_days_in_month(century, bcd_year, bcd_month);
+    if(bcd_day > d) {
+        bcd_day = d;
+    }
+    weekday = bcd_date_to_weekday(century, bcd_year, bcd_month, bcd_day);
+    RTC_write_date_start(century, bcd_year, bcd_month, bcd_day, weekday);
+}
+
+// increment/decrement for ALARM
+//   flag  0:decrement, 1:increment
+static void button_xxcrement_alarm(int flag) {
+    char d;
+
+    switch(alarm_clock_cursor) {
+    case CURSOR_ALARM_DAY_DISABLE:
+        d = RTC_read1(RTC_REG_ALARM_DAY) & 0x3f | (flag == 0 ? 0x80 : 0x00);
+        RTC_write1(RTC_REG_ALARM_DAY, d);
+        break;
+    case CURSOR_ALARM_DAY:
+        d = RTC_read1(RTC_REG_ALARM_DAY);
+        d = xxcrement_bcd(flag, d & 0x3f, 0x00, 0x31) | d & 0x80;
+        RTC_write1(RTC_REG_ALARM_DAY, d);
+        break;
+    case CURSOR_ALARM_WEEKDAY_DISABLE:
+        d = RTC_read1(RTC_REG_ALARM_WEEKDAY) & 0x07 | (flag == 0 ? 0x80 : 0x00);
+        RTC_write1(RTC_REG_ALARM_WEEKDAY, d);
+        break;
+    case CURSOR_ALARM_WEEKDAY:
+        d = RTC_read1(RTC_REG_ALARM_WEEKDAY);
+        d = xxcrement_bcd(flag, d & 0x07, 0x00, 0x06) | d & 0x80;
+        RTC_write1(RTC_REG_ALARM_WEEKDAY, d);
+        break;
+    case CURSOR_ALARM_INTERRUPT:
+        d = RTC_read1(RTC_REG_CONTROL2) & 0x1d | (flag == 0 ? 0x00 : 0x02);
+        RTC_write1(RTC_REG_CONTROL2, d);
+        break;
+    case CURSOR_ALARM_FLAG:
+        d = RTC_read1(RTC_REG_CONTROL2) & 0x17 | (flag == 0 ? 0x00 : 0x08);
+        RTC_write1(RTC_REG_CONTROL2, d);
+        break;
+    case CURSOR_ALARM_HOUR_DISABLE:
+        d = RTC_read1(RTC_REG_ALARM_HOUR) & 0x3f | (flag == 0 ? 0x80 : 0x00);
+        RTC_write1(RTC_REG_ALARM_HOUR, d);
+        break;
+    case CURSOR_ALARM_HOUR:
+        d = RTC_read1(RTC_REG_ALARM_HOUR);
+        d = xxcrement_bcd(flag, d & 0x3f, 0x00, 0x23) | d & 0x80;
+        RTC_write1(RTC_REG_ALARM_HOUR, d);
+        break;
+    case CURSOR_ALARM_MINUTE_DISABLE:
+        d = RTC_read1(RTC_REG_ALARM_MINUTE) & 0x7f | (flag == 0 ? 0x80 : 0x00);
+        RTC_write1(RTC_REG_ALARM_MINUTE, d);
+        break;
+    case CURSOR_ALARM_MINUTE:
+        d = RTC_read1(RTC_REG_ALARM_MINUTE);
+        d = xxcrement_bcd(flag, d & 0x7f, 0x00, 0x59) | d & 0x80;
+        RTC_write1(RTC_REG_ALARM_MINUTE, d);
+        break;
     }
 }
 
-// increment date/time
-static void BTN_UP_action() {
-    char century, bcd_year, bcd_month, bcd_day, weekday, d, t;
-
-    if(display_mode == DISPLAY_MODE_DATE_TIME_ADJUST) {
-
-        switch(cursor_position) {
-
-        case CURSOR_DATE_TIME_CENTURY:
-            RTC_stop_and_read_date(century, bcd_year, bcd_month, bcd_day);
-            century = increment_bcd(century, 0x00, 0x01);
-            d = bcd_days_in_month(century, bcd_year, bcd_month);
-            if(bcd_day > d) {
-                bcd_day = d;
-            }
-            weekday = bcd_date_to_weekday(century, bcd_year, bcd_month, bcd_day);
-            RTC_write_date_and_start(century, bcd_year, bcd_month, bcd_day, weekday);
-            break;
-
-        case CURSOR_DATE_TIME_YEAR:
-            RTC_stop_and_read_date(century, bcd_year, bcd_month, bcd_day);
-            bcd_year = increment_bcd(bcd_year, 0x00, 0x99);
-            d = bcd_days_in_month(century, bcd_year, bcd_month);
-            if(bcd_day > d) {
-                bcd_day = d;
-            }
-            weekday = bcd_date_to_weekday(century, bcd_year, bcd_month, bcd_day);
-            RTC_write_date_and_start(century, bcd_year, bcd_month, bcd_day, weekday);
-            break;
+// increment/decrement for TIMER
+//   flag  0:decrement, 1:increment
+static void button_xxcrement_timer(int flag) {
+    char d;
 
-        case CURSOR_DATE_TIME_MONTH:
-            RTC_stop_and_read_date(century, bcd_year, bcd_month, bcd_day);
-            bcd_month = increment_bcd(bcd_month, 0x01, 0x12);
-            d = bcd_days_in_month(century, bcd_year, bcd_month);
-            if(bcd_day > d) {
-                bcd_day = d;
-            }
-            weekday = bcd_date_to_weekday(century, bcd_year, bcd_month, bcd_day);
-            RTC_write_date_and_start(century, bcd_year, bcd_month, bcd_day, weekday);
-            break;
-
-        case CURSOR_DATE_TIME_DAY:
-            RTC_stop_and_read_date(century, bcd_year, bcd_month, bcd_day);
-            bcd_day = increment_bcd(bcd_day, 0x01, bcd_days_in_month(century, bcd_year, bcd_month));
-            weekday = bcd_date_to_weekday(century, bcd_year, bcd_month, bcd_day);
-            RTC_write_date_and_start(century, bcd_year, bcd_month, bcd_day, weekday);
-           break;
-
-        case CURSOR_DATE_TIME_HOUR:
-            t = RTC_stop_and_read1(RTC_REG_HOUR) & 0x3F;
-            t = increment_bcd(t, 0x00, 0x23);
-            RTC_write1_and_start(RTC_REG_HOUR, t);
-            break;
-
-        case CURSOR_DATE_TIME_MINUTE:
-            t = RTC_stop_and_read1(RTC_REG_MINUTE) & 0x7F;
-            t = increment_bcd(t, 0x00, 0x59);
-            RTC_write1_and_start(RTC_REG_MINUTE, t);
-            break;
-
-        case CURSOR_DATE_TIME_SECOND:
-            t = RTC_stop_and_read1(RTC_REG_SECOND) & 0x7f;
-            t = 0x00;
-            RTC_write1_and_start(RTC_REG_SECOND, t);
-            break;
+    switch(alarm_clock_cursor) {
+    case CURSOR_TIMER_SELECT:
+        d = RTC_read1(RTC_REG_TIMER_CONTROL);
+        d = xxcrement_bcd(flag, d & 0x03, 0x00, 0x03) | d & 0x80;
+        RTC_write1(RTC_REG_TIMER_CONTROL, d);
+        break;
+    case CURSOR_TIMER_COUNT:
+        d = RTC_read1(RTC_REG_TIMER);
+        switch(flag) {
+        case 0: --d; break;
+        case 1: ++d; break;
         }
+        RTC_write1(RTC_REG_TIMER, d);
+        break;
+    case CURSOR_CLKOUT_ENABLE:
+        d = RTC_read1(RTC_REG_CLKOUT_FREQUENCY) & 0x03 | (flag == 0 ? 0x00 : 0x80);
+        RTC_write1(RTC_REG_CLKOUT_FREQUENCY, d);
+        break;
+    case CURSOR_TIMER_PERIODIC:
+        d = RTC_read1(RTC_REG_CONTROL2) & 0x0f | (flag == 0 ? 0x00 : 0x10);
+        RTC_write1(RTC_REG_CONTROL2, d);
+        break;
+    case CURSOR_TIMER_ENABLE:
+        d = RTC_read1(RTC_REG_TIMER_CONTROL) & 0x03 | (flag == 0 ? 0x00 : 0x80);
+        RTC_write1(RTC_REG_TIMER_CONTROL, d);
+        break;
+    case CURSOR_TIMER_INTERRUPT:
+        d = RTC_read1(RTC_REG_CONTROL2) & 0x1e | (flag == 0 ? 0x00 : 0x01);
+        RTC_write1(RTC_REG_CONTROL2, d);
+        break;
+    case CURSOR_TIMER_FLAG:
+        d = RTC_read1(RTC_REG_CONTROL2) & 0x1b | (flag == 0 ? 0x00 : 0x04);
+        RTC_write1(RTC_REG_CONTROL2, d);
+        break;
+    case CURSOR_CLKOUT_FREQUENCY:
+        d = RTC_read1(RTC_REG_CLKOUT_FREQUENCY);
+        d = xxcrement_bcd(flag, d & 0x03, 0x00, 0x03) | d & 0x80;
+        RTC_write1(RTC_REG_CLKOUT_FREQUENCY, d);
+        break;
     }
 }