From: Nils Faerber Date: Sun, 21 Apr 2013 14:26:38 +0000 (+0200) Subject: Oh boy... lots of changes, too many to describe X-Git-Url: https://git.karo-electronics.de/?p=oswald.git;a=commitdiff_plain;h=5d0ff002cee35d109f4a60eff415b2db556fb8f4 Oh boy... lots of changes, too many to describe --- diff --git a/ui/Fonts.c b/ui/Fonts.c index 54929ce..f6083db 100644 --- a/ui/Fonts.c +++ b/ui/Fonts.c @@ -20,15 +20,42 @@ /*! The number of printable characters in the font tables */ #define PRINTABLE_CHARACTERS ( 94 ) +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatch5table[PRINTABLE_CHARACTERS][5]; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatch7table[PRINTABLE_CHARACTERS][7]; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const u16t MetaWatch16table[PRINTABLE_CHARACTERS][16]; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const u16t MetaWatchTimeTable[TOTAL_TIME_CHARACTERS][19]; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatchMonospaced10Table[PRINTABLE_CHARACTERS][10]; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatch5width[PRINTABLE_CHARACTERS]; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatch7width[PRINTABLE_CHARACTERS]; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatch16width[PRINTABLE_CHARACTERS]; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatchTimeWidth[TOTAL_TIME_CHARACTERS]; /*! Font Structure @@ -189,6 +216,9 @@ void GetCharacterBitmap(unsigned char Character, u16t *pBitmap) } +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatch5table[PRINTABLE_CHARACTERS][5] = { /* character 0x20 (' '): (width = 2) */ @@ -474,6 +504,9 @@ const unsigned char MetaWatch5table[PRINTABLE_CHARACTERS][5] = 0x00, 0x00, 0x00, 0x00, 0x00,}, }; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatch5width[PRINTABLE_CHARACTERS] = { /* width char hexcode */ @@ -574,6 +607,9 @@ const unsigned char MetaWatch5width[PRINTABLE_CHARACTERS] = 3, /* } 7D */ }; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatch7table[PRINTABLE_CHARACTERS][7] = { @@ -860,6 +896,9 @@ const unsigned char MetaWatch7table[PRINTABLE_CHARACTERS][7] = }; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatch7width[PRINTABLE_CHARACTERS] = { /* width char hexcode */ /* ===== ==== ======= */ @@ -960,6 +999,9 @@ const unsigned char MetaWatch7width[PRINTABLE_CHARACTERS] = { }; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const u16t MetaWatch16table[PRINTABLE_CHARACTERS][16] = { /* character 0x20 (' '): (width=4) */ @@ -1526,6 +1568,9 @@ const u16t MetaWatch16table[PRINTABLE_CHARACTERS][16] = 0x0006, 0x0002, 0x0001, 0x0000}, }; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatch16width[PRINTABLE_CHARACTERS] = { /* width char hexcode */ @@ -1627,6 +1672,9 @@ const unsigned char MetaWatch16width[PRINTABLE_CHARACTERS] = }; /******************************************************************************/ +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const u16t MetaWatchTimeTable[TOTAL_TIME_CHARACTERS][19] = { /* character 0x30 ('0'): (width=11, offset=0) */ @@ -1714,6 +1762,9 @@ const u16t MetaWatchTimeTable[TOTAL_TIME_CHARACTERS][19] = 0x0000, 0x0000, 0x0000}, }; +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatchTimeWidth[TOTAL_TIME_CHARACTERS] = { /* width char hexcode */ @@ -1734,6 +1785,9 @@ const unsigned char MetaWatchTimeWidth[TOTAL_TIME_CHARACTERS] = /******************************************************************************/ +#if defined(__GNUC__) && (__MSP430X__ > 0) +__attribute__((__far__)) +#endif const unsigned char MetaWatchMonospaced10Table[PRINTABLE_CHARACTERS][10] = { {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, diff --git a/ui/LcdDisplay.c b/ui/LcdDisplay.c index dbf775f..f889bbc 100644 --- a/ui/LcdDisplay.c +++ b/ui/LcdDisplay.c @@ -1,4 +1,5 @@ -#include "oswald-ui.h" +#include "oswald.h" +#include "oswald_hal.h" #include "oswald_strings.h" #include "Fonts.h" @@ -32,7 +33,7 @@ void DrawLcdLineBresenham(u8t xstart, u8t ystart, u8t xend, u8t yend) x = xstart; y = ystart; err = el/2; - lcd_set_pixel(x, y, TRUE); + hal_lcd_set_pixel(x, y, TRUE); for (t = 0; t < el; ++t) { err -= es; @@ -44,7 +45,7 @@ void DrawLcdLineBresenham(u8t xstart, u8t ystart, u8t xend, u8t yend) x += pdx; y += pdy; } - lcd_set_pixel(x, y, TRUE); + hal_lcd_set_pixel(x, y, TRUE); } // lcd_update_display(); } @@ -77,12 +78,12 @@ void DrawLcdLineBresenhamWW(u8t xstart, u8t ystart, u8t xend, u8t yend, u8t thic x = xstart; y = ystart; err = el/2; - lcd_set_pixel(x, y, TRUE); + hal_lcd_set_pixel(x, y, TRUE); for (i=1; i= 1) && (uMonat <= 12)) + return arrTageImMonat[uMonat]; + else { + return 0; + } +} + +short getAnzahlTageImJahr(const unsigned int uJahr) +{ + return (is_leap(uJahr)) ? 366 : 365; +} + +short getWochentag(const unsigned int uTag, const unsigned int uMonat, const unsigned int uJahr) +{ + // ungült Jan Feb Mrz Apr Mai Jun Jul Aug Sep Okt Nov Dez + unsigned char arrMonatsOffset[13] = { 0, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}; + short nErgebnis = 0; + + // Monat / Tag - Plausi prüfen: + if ((uTag > 31) || (uMonat > 12) || (uMonat <= 0) + || (uTag <= 0) || (uJahr <= 0)) { + return -1; + } + + unsigned char cbTagesziffer = (uTag % 7); + unsigned char cbMonatsziffer = arrMonatsOffset[uMonat]; + unsigned char cbJahresziffer = ((uJahr % 100) + ((uJahr % 100) / 4)) % 7; + unsigned char cbJahrhundertziffer = (3 - ((uJahr / 100) % 4)) * 2; + + // Schaltjahreskorrektur: + if ((uMonat <= 2) && (is_leap(uJahr))) + cbTagesziffer = cbTagesziffer + 6; + + nErgebnis = (cbTagesziffer + cbMonatsziffer + cbJahresziffer + cbJahrhundertziffer) % 7; + + // Ergebnis: + // 0 = Sonntag + // 1 = Montag + // 2 = Dienstag + // 3 = Mittwoch + // 4 = Donnerstag + // 5 = Freitag + // 6 = Samstag + return nErgebnis; +} + +short getTagDesJahres(const unsigned int uTag, const unsigned int uMonat, const unsigned int uJahr) +{ + // Der wievielte Tag des Jahres ist dieser Tag + if ((uMonat == 0) || (uMonat > 12)) { + return -1; + } + + unsigned int uLokalTag = uTag; + unsigned int uLokalMonat = uMonat; + + while (uLokalMonat > 1) { + uLokalMonat--; + uLokalTag += days_of_month(uLokalMonat, uJahr); + } + + return uLokalTag; +} + +short getKalenderwoche(short uTag, short uMonat, short uJahr) +{ + // Berechnung erfolgt analog DIN 1355, welche besagt: + // Der erste Donnerstag im neuen Jahr liegt immer in der KW 1. + // "Woche" ist dabei definiert als [Mo, ..., So]. + short nTagDesJahres = getTagDesJahres(uTag, uMonat, uJahr); + + // Berechnen des Wochentags des 1. Januar: + short nWochentag1Jan = getWochentag(1, 1, uJahr); + + // Sonderfälle Freitag und Samstag + if (nWochentag1Jan >= 5) + nWochentag1Jan = nWochentag1Jan - 7; + + // Sonderfälle "Jahresanfang mit KW - Nummer aus dem Vorjahr" + if ( (nTagDesJahres + nWochentag1Jan) <= 1) { + return getKalenderwoche(31, 12, uJahr - 1); + } + + short nKalenderWoche = ((nTagDesJahres + nWochentag1Jan + 5) / 7); + + // 53 Kalenderwochen hat grundsätzlich nur ein Jahr, + // welches mit einem Donnerstag anfängt ! + // In Schaltjahren ist es auch mit einem Mittwoch möglich, z.B. 1992 + // Andernfalls ist diese KW schon die KW1 des Folgejahres. + if (nKalenderWoche == 53) { + boolean bIstSchaltjahr = is_leap(uJahr); + + if ((nWochentag1Jan == 4) // Donnerstag + || (nWochentag1Jan == -3) // auch Donnerstag + || ((nWochentag1Jan == 3) && bIstSchaltjahr) + || ((nWochentag1Jan == -4) && bIstSchaltjahr)) { + ; // Das ist korrekt und erlaubt + } else + nKalenderWoche = 1; // Korrektur des Wertes + } + + return nKalenderWoche; +} + +void getOsterdatum(const unsigned int uJahr, unsigned int *uTag, unsigned int *uMonat) +{ + // Berechnet für ein beliebiges Jahr das Osterdatum. + + // Quelle des Gauss - Algorithmus: Stefan Gerth, + // "Die Gauß'sche Osterregel", Nürnberg, Februar 2003. + // http://krapfen.org/content/paper/Schule/Facharbeit/Berechnung_des_Osterfestes.pdf + + unsigned int a = uJahr % 19; + unsigned int b = uJahr % 4; + unsigned int c = uJahr % 7; + + int k = uJahr / 100; + int q = k / 4; + int p = ((8 * k) + 13) / 25; + unsigned int Egz = (38 - (k - q) + p) % 30; // Die Jahrhundertepakte + unsigned int M = (53 - Egz) % 30; + unsigned int N = (4 + k - q) % 7; + + unsigned int d = ((19 * a) + M) % 30; + unsigned int e = ((2 * b) + (4 * c) + (6 * d) + N) % 7; + + // Ausrechnen des Ostertermins: + if ((22 + d + e) <= 31) { + *uTag = 22 + d + e; + *uMonat = 3; + } else { + *uTag = d + e - 9; + *uMonat = 4; + + // Zwei Ausnahmen berücksichtigen: + if (*uTag == 26) + *uTag = 19; + else if ((*uTag == 25) && (d == 28) && (a > 10)) + *uTag = 18; + } + + // Offsets für andere Feiertage: + + // Schwerdonnerstag / Weiberfastnacht -52 + // Rosenmontag -48 + // Fastnachtsdienstag -47 + // Aschermittwoch -46 + // Gründonnerstag -3 + // Karfreitag -2 + // Ostersonntag 0 + // Ostermontag +1 + // Christi Himmelfahrt +39 + // Pfingstsonntag +49 + // Pfingstmontag +50 + // Fronleichnam +60 + + // Mariä Himmelfahrt ist stets am 15. August (Danke an Michael Plugge!) +} + +void getViertenAdvent(const unsigned int uJahr, unsigned int *uTag, unsigned int *uMonat) +{ + // Berechnet für ein beliebiges Jahr das Datum des 4. Advents-Sonntags. + // Der 4. Adventssonntag ist stets der Sonntag vor dem 1. Weihnachtsfeiertag, + // muß also stets in der Periode [18. - 24.12.] liegen: + + *uMonat = 12; // Das steht jedes Jahr fest :-) + + short nWoTag = getWochentag(24, 12, uJahr); // Wochentag des 24.12. ermitteln + + *uTag = 24 - nWoTag; + + // Offsets: Der Buß- und Bettag liegt stets 32 Tage vor dem 4. Advent +} + + diff --git a/ui/calendar.h b/ui/calendar.h new file mode 100644 index 0000000..636085f --- /dev/null +++ b/ui/calendar.h @@ -0,0 +1,21 @@ +#ifndef _CALENDAR_H +#define _CALENDAR_H + +unsigned char is_leap(const unsigned int year); + +unsigned short days_of_month(const unsigned int uMonat, const unsigned int uJahr); + +short getAnzahlTageImJahr(const unsigned int uJahr); + +short getWochentag(const unsigned int uTag, const unsigned int uMonat, const unsigned int uJahr); + +short getTagDesJahres(const unsigned int uTag, const unsigned int uMonat, const unsigned int uJahr); + +short getKalenderwoche(short uTag, short uMonat, short uJahr); + +void getOsterdatum(const unsigned int uJahr, unsigned int *uTag, unsigned int *uMonat); + +void getViertenAdvent(const unsigned int uJahr, unsigned int *uTag, unsigned int *uMonat); + +#endif + diff --git a/ui/oswald-ui.c b/ui/oswald-ui.c index ff88ff9..e86f0e1 100644 --- a/ui/oswald-ui.c +++ b/ui/oswald-ui.c @@ -23,7 +23,7 @@ static oswald_ui *ui_g; -void lcd_set_pixel(gint x, gint y, gboolean state) +void hal_lcd_set_pixel(gint x, gint y, gboolean state) { gint ix, iy; @@ -39,12 +39,12 @@ void lcd_set_pixel(gint x, gint y, gboolean state) } /* updates the actual LCD so that drawing becomes visible */ -void lcd_update_display(void) +void hal_lcd_update_display(void) { gtk_widget_queue_draw(ui_g->darea); } -void lcd_clear_display(void) +void hal_lcd_clear_display(void) { gdk_draw_rectangle (ui_g->pixmap, ui_g->darea->style->white_gc, @@ -219,19 +219,19 @@ static void create_mainwin(oswald_ui *ui) vb = gtk_vbox_new(FALSE, 5); gtk_box_pack_start (GTK_BOX(hb), vb, FALSE, FALSE, 5); - btn = gtk_button_new_with_label(" D "); + btn = gtk_button_new_with_label(" F "); gtk_box_pack_start (GTK_BOX(vb), btn, FALSE, FALSE, 10); - g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(button_D_clicked), ui); + g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(button_F_clicked), ui); + g_signal_connect(G_OBJECT(btn), "button-press-event", G_CALLBACK(button_F_pr), ui); + g_signal_connect(G_OBJECT(btn), "button-release-event", G_CALLBACK(button_F_pr), ui); btn = gtk_button_new_with_label(" E "); gtk_box_pack_start (GTK_BOX(vb), btn, FALSE, FALSE, 10); g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(button_E_clicked), ui); - btn = gtk_button_new_with_label(" F "); + btn = gtk_button_new_with_label(" D "); gtk_box_pack_start (GTK_BOX(vb), btn, FALSE, FALSE, 10); - g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(button_F_clicked), ui); - g_signal_connect(G_OBJECT(btn), "button-press-event", G_CALLBACK(button_F_pr), ui); - g_signal_connect(G_OBJECT(btn), "button-release-event", G_CALLBACK(button_F_pr), ui); + g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(button_D_clicked), ui); ui->darea = gtk_drawing_area_new (); gtk_box_pack_start (GTK_BOX(hb), GTK_WIDGET(ui->darea), FALSE, FALSE, 5); @@ -323,13 +323,13 @@ static gboolean centisecond_tmo_handler (gpointer userdata) return TRUE; } -void enable_centisecond_timer(void) +void hal_enable_centisecond_timer(void) { ui_g->centisecond_active = TRUE; g_timeout_add(10, centisecond_tmo_handler, ui_g); } -void disable_centisecond_timer(void) +void hal_disable_centisecond_timer(void) { ui_g->centisecond_active = FALSE; } @@ -346,17 +346,67 @@ static gboolean halfsecond_tmo_handler (gpointer userdata) return TRUE; } -void enable_halfsecond_timer(void) +void hal_enable_halfsecond_timer(void) { ui_g->halfsecond_active = TRUE; g_timeout_add(500, halfsecond_tmo_handler, ui_g); } -void disable_halfsecond_timer(void) +void hal_disable_halfsecond_timer(void) { ui_g->halfsecond_active = FALSE; } +void hal_get_rtc(clock_state *rtc) +{ + time_t mt; + struct tm mtime; + + mt = time(NULL); + localtime_r(&mt, &mtime); + + rtc->hour = mtime.tm_hour; + rtc->minute = mtime.tm_min; + rtc->second = mtime.tm_sec; + rtc->day = mtime.tm_mday; + rtc->month = (mtime.tm_mon + 1); + rtc->year = (mtime.tm_year + 1900); +} + +void hal_set_rtc(const clock_state *rtc, boolean set_set) +{ +} + +void hal_get_power_state(power_state *pwr) +{ +} + +static boolean BacklightState = FALSE; + +/* sets the backlight on/off, on=TRUE, off=FALSE */ +void hal_lcd_set_backlight(boolean state) +{ + g_print("turn LCD backlight %s\n", state ? "on" : "off"); + BacklightState = state; +} + +boolean hal_lcd_get_backlight(void) +{ + return BacklightState; +} + + +/* sets the vibration motor on/off, on=TRUE, off=FALSE */ +void hal_vibration_set_state(boolean state) +{ +} + +boolean hal_vibration_get_state(void) +{ + return FALSE; +} + + int main(int argc , char ** argv) { oswald_ui ui; diff --git a/ui/oswald.h b/ui/oswald.h index 9a341e3..31ee5cd 100644 --- a/ui/oswald.h +++ b/ui/oswald.h @@ -1,5 +1,6 @@ #ifndef _OSWALD_H #define _OSWALD_H +#include //#define DEBUG 1 #ifdef DEBUG @@ -30,20 +31,36 @@ typedef struct { u8t minute; u8t second; u8t day; + u8t wday; // day in week, 0=sunday, 1=monday,... u8t month; u16t year; boolean clk24hr; boolean day_first; } clock_state; +#define WDAY_SUNDAY (1 << 0) +#define WDAY_MONDAY (1 << 1) +#define WDAY_TUESDAY (1 << 2) +#define WDAY_WEDNESDAY (1 << 3) +#define WDAY_THURSDAY (1 << 4) +#define WDAY_FRIDAY (1 << 5) +#define WDAY_SATURDAY (1 << 6) +typedef struct { + u8t hour; + u8t minute; + u8t wday; // bitfield 0 to 6, 1=sunday, 2=monday, 4=tuesday... +} alarm_clk; + typedef enum { IDLE_SCREEN = 0, + ALARM_SETUP_SCREEN, + STOP_WATCH_SCREEN, ACCEL_DISPLAY_SCREEN, MENU_TEST_SCREEN, - STOP_WATCH_SCREEN, // APPLICATION_SCREEN, LAST_SCREEN, // a marker for the last (not valid) screen) DATETIME_SETTING_SCREEN, + ALARM_SCREEN, SCREENS_END, } screen_number; @@ -66,6 +83,8 @@ typedef enum { #define EVENT_AMBIENTLIGHT_UPDATE (1<<7) // ambient light sensor updates #define EVENT_POWER_CHANGE (1<<8) // power source status change #define EVENT_COMMS (1<<9) // communication, like Bluetooth I/O +#define EVENT_POWER_STATE (1<<10) // power source changed or similar + typedef struct { u16t event_mask; // the event the screen wants to receive @@ -85,5 +104,26 @@ typedef struct { u8t z; } accel_data_t; -#endif +#define POWER_SOURCE_BATTERY 0 +#define POWER_SOURCE_EXTERNAL 1 + +#define POWER_CHARGER_DONE 0 +#define POWER_CHARGER_PRECHARGE 1 +#define POWER_CHARGER_CHARGING 2 +#define POWER_CHARGER_UNK 3 + +typedef struct { + u8t source; + u8t charge_state; + u8t percent; + u16t level; +} power_state; +typedef enum { + BLUETOOTH_OFF = 0, + BLUETOOTH_ON, + BLUETOOTH_CONNECTED, + BLUETOOTH_ILL +} bluetooth_state; + +#endif diff --git a/ui/oswald_graphics.c b/ui/oswald_graphics.c index 36894ab..a6eb14f 100644 --- a/ui/oswald_graphics.c +++ b/ui/oswald_graphics.c @@ -5,7 +5,19 @@ #include "oswald_graphics.h" -void oswald_draw_Line(u8t xstart, u8t ystart, u8t xend, u8t yend) +void oswald_draw_bitmap(const uint8_t xstart, const uint8_t ystart, const uint8_t width, const uint8_t height, const void *bmp) +{ + uint8_t x, y; + + // we only draw set pixel, unset pixel remain as they are + for (y=0; y 59) { - OswaldClk.second = 0; - OswaldClk.minute += 1; - } else - return; - if (OswaldClk.minute > 59) { - OswaldClk.minute = 0; - OswaldClk.hour += 1; - } else - return; - if (OswaldClk.hour > 23) { - OswaldClk.hour = 0; - // day++ - } else - return; + hal_get_rtc(&OswaldClk); + + /* check for pending alarm once per minute */ + if (OswaldClk.second == 0) { + if (OswaldClk.hour == OswaldAlarm.hour && + OswaldClk.minute == OswaldAlarm.minute && + ((1 << OswaldClk.wday) & OswaldAlarm.wday)) { + OswaldState.screen->event_func(EVENT_SCREEN_DESTROY, NULL); + OswaldState.screen_id = ALARM_SCREEN; + OswaldState.screen = &OswaldScreens[OswaldState.screen_id]; + OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL); + } + } } void oswald_one_second_tick(void) { - /* update our 'RTC' */ + /* update clock - should use RTC if available */ update_clock_state(); + hal_get_power_state(&OswaldPowerState); + if (backlight_safety_off) { + backlight_safety_off--; + if (!backlight_safety_off) + hal_lcd_set_backlight(FALSE); + } + /* wake-up screen if interested in the one-second-event */ if (OswaldState.screen->event_func != NULL && (OswaldState.screen->event_mask & EVENT_ONE_SEC_TIMER)) @@ -91,10 +98,20 @@ void oswald_halfsecond_tick(void) void oswald_handle_button_press(watch_button button) { switch (button) { + case BUTTON_D: + // backlight on/off + if (hal_lcd_get_backlight()) { + hal_lcd_set_backlight(FALSE); + backlight_safety_off = 0; + } else { + hal_lcd_set_backlight(TRUE); + backlight_safety_off = 2; + } + break; case BUTTON_A: case BUTTON_B: - case BUTTON_D: case BUTTON_E: + case BUTTON_F: if (OswaldState.screen->event_func != NULL && (OswaldState.screen->event_mask & EVENT_USER_BUTTONS)) OswaldState.screen->event_func(EVENT_USER_BUTTONS, &button); @@ -109,9 +126,6 @@ void oswald_handle_button_press(watch_button button) OswaldState.screen = &OswaldScreens[OswaldState.screen_id]; OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL); break; - case BUTTON_F: - // backlight on/off - break; default: // should never get here break; @@ -149,16 +163,26 @@ void oswald_init(void) OswaldScreens[DATETIME_SETTING_SCREEN].event_mask = EVENT_USER_BUTTONS | EVENT_HALF_SEC_TIMER; OswaldScreens[DATETIME_SETTING_SCREEN].event_func = datetime_setup_events; + OswaldScreens[ALARM_SETUP_SCREEN].event_mask = EVENT_USER_BUTTONS | EVENT_HALF_SEC_TIMER; + OswaldScreens[ALARM_SETUP_SCREEN].event_func = alarm_setup_events; + OswaldScreens[MENU_TEST_SCREEN].event_mask = EVENT_USER_BUTTONS; OswaldScreens[MENU_TEST_SCREEN].event_func = test_menu_handle_events; OswaldScreens[STOP_WATCH_SCREEN].event_mask = EVENT_USER_BUTTONS | EVENT_CS_TIMER; OswaldScreens[STOP_WATCH_SCREEN].event_func = stop_watch_handle_events; + OswaldScreens[ALARM_SCREEN].event_mask = EVENT_USER_BUTTONS | EVENT_HALF_SEC_TIMER; + OswaldScreens[ALARM_SCREEN].event_func = alarm_handle_events; + OswaldState.screen_id = IDLE_SCREEN; OswaldState.screen = &OswaldScreens[OswaldState.screen_id]; if (OswaldState.screen->event_func != NULL) OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL); + + OswaldAlarm.hour = 12; + OswaldAlarm.minute = 0; + OswaldAlarm.wday = 0x00; } diff --git a/ui/oswald_main.h b/ui/oswald_main.h index 28c5691..57e8008 100644 --- a/ui/oswald_main.h +++ b/ui/oswald_main.h @@ -4,6 +4,8 @@ #include "oswald.h" extern clock_state OswaldClk; +extern alarm_clk OswaldAlarm; +extern power_state OswaldPowerState; extern watch_state OswaldState; extern watch_screen OswaldScreens[]; @@ -24,4 +26,3 @@ void oswald_centisecond_tick(void); void oswald_init(void); #endif - diff --git a/ui/oswald_screens.c b/ui/oswald_screens.c index cbe2956..c09958f 100644 --- a/ui/oswald_screens.c +++ b/ui/oswald_screens.c @@ -1,8 +1,11 @@ +#include + #include "oswald.h" #include "oswald_main.h" #include "oswald_watch_faces.h" #include "Fonts.h" #include "LcdDisplay.h" +#include "oswald_hal.h" #include "oswald_screens.h" @@ -14,7 +17,7 @@ typedef struct { } idle_data_t; static idle_data_t idle_screen = { DrawLcdDigitalClock, - FALSE, + TRUE, FALSE, }; @@ -36,7 +39,7 @@ void idle_handle_user_buttons(watch_button button) idle_screen.screendraw_func = DrawLcdAnaClock; }; break; - case BUTTON_D: + case BUTTON_F: OswaldState.screen_id = DATETIME_SETTING_SCREEN; OswaldState.screen = &OswaldScreens[OswaldState.screen_id]; OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL); @@ -74,7 +77,7 @@ static accelscreen_data_t accel_screen = { void draw_accel_screen(accel_data_t *accel_data) { - lcd_clear_display(); + hal_lcd_clear_display(); SetFont(MetaWatch16); WriteLcdString(2, 2, "X:"); WriteLcdNumber(20, 2, accel_data->x); @@ -82,7 +85,7 @@ void draw_accel_screen(accel_data_t *accel_data) WriteLcdNumber(20, 18, accel_data->y); WriteLcdString(2, 34, "Z:"); WriteLcdNumber(20, 34, accel_data->z); - lcd_update_display(); + hal_lcd_update_display(); } void accel_handle_events(u16t event, void *data) @@ -119,7 +122,7 @@ static datetime_setup_data_t dt_setup_screen = { void draw_datetime_setup_screen(datetime_setup_data_t *sdata) { - lcd_clear_display(); + hal_lcd_clear_display(); SetFont(MetaWatch16); WriteLcdString(2, 2, "Set"); @@ -172,7 +175,7 @@ void draw_datetime_setup_screen(datetime_setup_data_t *sdata) } WriteLcdString(15, 79, "dd.mm. mm/dd"); - lcd_update_display(); + hal_lcd_update_display(); } void datetime_handle_updown(u8t pos, s8t incr) @@ -235,6 +238,10 @@ void datetime_handle_updown(u8t pos, s8t incr) default: break; }; + if (pos == 2) + hal_set_rtc(&OswaldClk, TRUE); + else + hal_set_rtc(&OswaldClk, FALSE); } void handle_setup_datetime_buttons(watch_button button, datetime_setup_data_t *sdata) @@ -246,7 +253,7 @@ void handle_setup_datetime_buttons(watch_button button, datetime_setup_data_t *s case BUTTON_B: datetime_handle_updown(sdata->pos, -1); break; - case BUTTON_D: + case BUTTON_F: sdata->pos++; sdata->pos %= 8; break; @@ -260,11 +267,12 @@ void datetime_setup_events(u16t event, void *data) { switch (event) { case EVENT_SCREEN_VISIBLE: + dt_setup_screen.pos = 0; draw_datetime_setup_screen(&dt_setup_screen); - enable_halfsecond_timer(); + hal_enable_halfsecond_timer(); break; case EVENT_SCREEN_DESTROY: - disable_halfsecond_timer(); + hal_disable_halfsecond_timer(); break; case EVENT_USER_BUTTONS: dbg_out("button event %d\n", *(int *)data); @@ -282,6 +290,172 @@ void datetime_setup_events(u16t event, void *data) }; } +typedef struct { + u8t pos; + boolean on; +} alarm_setup_data_t; +static alarm_setup_data_t alarm_setup_screen = { + 0, + TRUE +}; + +void draw_alarm_setup_screen(alarm_setup_data_t *sdata) +{ + hal_lcd_clear_display(); + + SetFont(MetaWatch16); + WriteLcdString(2, 2, "Alarm"); + + SetFont(MetaWatchTime); + if ((sdata->pos == 0 && sdata->on) || sdata->pos != 0) { + WriteLcdCharacter(2, 20, (OswaldAlarm.hour / 10)); + WriteLcdCharacter(14, 20, (OswaldAlarm.hour % 10)); + } + WriteLcdCharacter(26, 20, TIME_CHARACTER_COLON_INDEX); + + if ((sdata->pos == 1 && sdata->on) || sdata->pos != 1) { + WriteLcdCharacter(31, 20, (OswaldAlarm.minute / 10)); + WriteLcdCharacter(43, 20, (OswaldAlarm.minute % 10)); + } + + SetFont(MetaWatchMonospaced10); + WriteLcdCharacter(3, 45, 'S'); + WriteLcdCharacter(15, 45, 'M'); + WriteLcdCharacter(27, 45, 'T'); + WriteLcdCharacter(39, 45, 'W'); + WriteLcdCharacter(51, 45, 'T'); + WriteLcdCharacter(63, 45, 'F'); + WriteLcdCharacter(75, 45, 'S'); + + if ((sdata->pos == 2 && sdata->on) || sdata->pos != 2) + WriteLcdCharacter(3, 55, (OswaldAlarm.wday & WDAY_SUNDAY) ? 'x' : '_'); + if ((sdata->pos == 3 && sdata->on) || sdata->pos != 3) + WriteLcdCharacter(15, 55, (OswaldAlarm.wday & WDAY_MONDAY) ? 'x' : '_'); + if ((sdata->pos == 4 && sdata->on) || sdata->pos != 4) + WriteLcdCharacter(27, 55, (OswaldAlarm.wday & WDAY_TUESDAY) ? 'x' : '_'); + if ((sdata->pos == 5 && sdata->on) || sdata->pos != 5) + WriteLcdCharacter(39, 55, (OswaldAlarm.wday & WDAY_WEDNESDAY) ? 'x' : '_'); + if ((sdata->pos == 6 && sdata->on) || sdata->pos != 6) + WriteLcdCharacter(51, 55, (OswaldAlarm.wday & WDAY_THURSDAY) ? 'x' : '_'); + if ((sdata->pos == 7 && sdata->on) || sdata->pos != 7) + WriteLcdCharacter(63, 55, (OswaldAlarm.wday & WDAY_FRIDAY) ? 'x' : '_'); + if ((sdata->pos == 8 && sdata->on) || sdata->pos != 8) + WriteLcdCharacter(75, 55, (OswaldAlarm.wday & WDAY_SATURDAY) ? 'x' : '_'); + +#if 0 + SetFont(MetaWatch7); + if ((sdata->pos == 6 && sdata->on) || sdata->pos != 6) { + if (OswaldClk.clk24hr) + WriteLcdString(2, 66, "x"); + else + WriteLcdString(2, 66, "_"); + } + WriteLcdString(15, 66, "24hr"); + + if ((sdata->pos == 7 && sdata->on) || sdata->pos != 7) { + if (OswaldClk.day_first) + WriteLcdString(2, 79, "x"); + else + WriteLcdString(2, 79, "_"); + } + WriteLcdString(15, 79, "dd.mm. mm/dd"); +#endif + hal_lcd_update_display(); +} + +void alarm_handle_updown(u8t pos, s8t incr) +{ + switch (pos) { + case 0: // hour + if (OswaldAlarm.hour == 0 && incr == -1) { + OswaldAlarm.hour = 23; + break; + }; + OswaldAlarm.hour += incr; + if (OswaldAlarm.hour > 23) + OswaldAlarm.hour = 0; + break; + case 1: // minute + if (OswaldAlarm.minute == 0 && incr == -1) { + OswaldAlarm.minute = 59; + break; + }; + OswaldAlarm.minute += incr; + if (OswaldAlarm.minute > 59) + OswaldAlarm.minute = 0; + break; + case 2: // sunday + OswaldAlarm.wday ^= WDAY_SUNDAY; + break; + case 3: // monday + OswaldAlarm.wday ^= WDAY_MONDAY; + break; + case 4: // tuesday + OswaldAlarm.wday ^= WDAY_TUESDAY; + break; + case 5: // wednesday + OswaldAlarm.wday ^= WDAY_WEDNESDAY; + break; + case 6: // thursday + OswaldAlarm.wday ^= WDAY_THURSDAY; + break; + case 7: // friday + OswaldAlarm.wday ^= WDAY_FRIDAY; + break; + case 8: // saturday + OswaldAlarm.wday ^= WDAY_SATURDAY; + break; + default: + break; + }; +} + +void handle_setup_alarm_buttons(watch_button button, alarm_setup_data_t *sdata) +{ + switch (button) { + case BUTTON_A: + alarm_handle_updown(sdata->pos, 1); + break; + case BUTTON_B: + alarm_handle_updown(sdata->pos, -1); + break; + case BUTTON_F: + sdata->pos++; + sdata->pos %= 9; + break; + default: + break; + } + draw_alarm_setup_screen(sdata); +} + +void alarm_setup_events(u16t event, void *data) +{ + switch (event) { + case EVENT_SCREEN_VISIBLE: + alarm_setup_screen.pos = 0; + draw_alarm_setup_screen(&alarm_setup_screen); + hal_enable_halfsecond_timer(); + break; + case EVENT_SCREEN_DESTROY: + hal_disable_halfsecond_timer(); + break; + case EVENT_USER_BUTTONS: + dbg_out("button event %d\n", *(int *)data); + handle_setup_alarm_buttons(*(watch_button *)data, &alarm_setup_screen); + break; + case EVENT_HALF_SEC_TIMER: + if (alarm_setup_screen.on) + alarm_setup_screen.on = FALSE; + else + alarm_setup_screen.on = TRUE; + draw_alarm_setup_screen(&alarm_setup_screen); + break; + default: + break; + }; +} + typedef struct { u8t menu_pos; @@ -290,7 +464,7 @@ static test_menu_t test_menu = { 0 }; void draw_menu_test_screen(void) { - lcd_clear_display(); + hal_lcd_clear_display(); SetFont(MetaWatch16); WriteLcdString(2, 2, "Menu"); SetFont(MetaWatch7); @@ -301,7 +475,7 @@ void draw_menu_test_screen(void) WriteLcdString(2, 56, "Item 5"); WriteLcdString(50, 20+(9*test_menu.menu_pos), "*"); - lcd_update_display(); + hal_lcd_update_display(); } static void handle_menu_user_buttons(watch_button button) @@ -354,8 +528,10 @@ static stopwatch_data_t stopwatch_screen = { 0, 0, 0, 0, 0, 0, 0, 0, FALSE }; static void update_stop_watch_screen(stopwatch_data_t *sdata) { + char tstr[16]; SetFont(MetaWatchMonospaced10); +#if 0 WriteLcdNumber(0, 30, sdata->hr); WriteLcdCharacter(14, 30, ':'); WriteLcdNumber(19, 30, sdata->min); @@ -371,8 +547,14 @@ static void update_stop_watch_screen(stopwatch_data_t *sdata) WriteLcdNumber(38, 50, sdata->lapse_sec); WriteLcdCharacter(52, 50, '.'); WriteLcdNumber(57, 50, sdata->lapse_csec / 10); - - lcd_update_display(); +#else + snprintf(tstr, 16, "%02d:%02d:%02d.%1d", sdata->hr, sdata->min, sdata->sec, sdata->csec / 10); + WriteLcdString(0, 30, tstr); + snprintf(tstr, 16, "%02d:%02d:%02d.%02d", sdata->lapse_hr, sdata->lapse_min, sdata->lapse_sec, sdata->lapse_csec); + WriteLcdString(0, 50, tstr); +#endif + + hal_lcd_update_display(); } static void draw_stop_watch_screen(stopwatch_data_t *sdata) @@ -388,10 +570,10 @@ static void handle_stop_watch_buttons(watch_button button) switch (button) { case BUTTON_A: // start/stop if (stopwatch_screen.running) { - disable_centisecond_timer(); + hal_disable_centisecond_timer(); stopwatch_screen.running = FALSE; } else { - enable_centisecond_timer(); + hal_enable_centisecond_timer(); stopwatch_screen.running = TRUE; } break; @@ -401,7 +583,7 @@ static void handle_stop_watch_buttons(watch_button button) stopwatch_screen.lapse_sec = stopwatch_screen.sec; stopwatch_screen.lapse_csec = stopwatch_screen.csec; break; - case BUTTON_D: // reset + case BUTTON_F: // reset stopwatch_screen.hr = 0; stopwatch_screen.min = 0; stopwatch_screen.sec = 0; @@ -425,11 +607,11 @@ void stop_watch_handle_events(u16t event, void *data) update_stop_watch_screen(&stopwatch_screen); break; case EVENT_SCREEN_VISIBLE: - lcd_clear_display(); + hal_lcd_clear_display(); draw_stop_watch_screen(&stopwatch_screen); break; case EVENT_SCREEN_DESTROY: - disable_centisecond_timer(); + hal_disable_centisecond_timer(); stopwatch_screen.running = FALSE; break; case EVENT_CS_TIMER: @@ -456,3 +638,42 @@ void stop_watch_handle_events(u16t event, void *data) break; }; } + + +void draw_alarm_screen(void) +{ + hal_lcd_clear_display(); + + SetFont(MetaWatch16); + WriteLcdString(2, 2, "ALARM !"); + + hal_lcd_update_display(); +} + +void alarm_handle_events(u16t event, void *data) +{ + switch (event) { + case EVENT_SCREEN_VISIBLE: + draw_alarm_screen(); + hal_enable_halfsecond_timer(); + hal_vibration_set_state(TRUE); + break; + case EVENT_SCREEN_DESTROY: + hal_disable_halfsecond_timer(); + hal_lcd_set_backlight(FALSE); + hal_vibration_set_state(FALSE); + break; + case EVENT_USER_BUTTONS: + dbg_out("button event %d\n", *(int *)data); + // hal_lcd_set_backlight(FALSE); + break; + case EVENT_HALF_SEC_TIMER: + hal_lcd_set_backlight(!hal_lcd_get_backlight()); + hal_vibration_set_state(!hal_vibration_get_state()); + dbg_out("timer\n"); + break; + default: + break; + }; +} + diff --git a/ui/oswald_screens.h b/ui/oswald_screens.h index 0cca47c..005b0bb 100644 --- a/ui/oswald_screens.h +++ b/ui/oswald_screens.h @@ -8,9 +8,13 @@ void accel_handle_events(u16t event, void *data); void datetime_setup_events(u16t event, void *data); +void alarm_setup_events(u16t event, void *data); + void test_menu_handle_events(u16t event, void *data); void stop_watch_handle_events(u16t event, void *data); +void alarm_handle_events(u16t event, void *data); + #endif diff --git a/ui/oswald_watch_faces.c b/ui/oswald_watch_faces.c index 548a6bb..6db3196 100644 --- a/ui/oswald_watch_faces.c +++ b/ui/oswald_watch_faces.c @@ -1,89 +1,203 @@ -#include +#include +#include #include "oswald.h" #include "oswald_main.h" -#include "oswald-ui.h" #include "Fonts.h" #include "LcdDisplay.h" +#include "oswald_hal.h" #include "oswald_watch_faces.h" +int16_t sintab[]={ + 0, 2, 3, 5, 7, 9, 10, 12, 14, 16, + 17, 19, 21, 22, 24, 26, 28, 29, 31, 33, + 34, 36, 37, 39, 41, 42, 44, 45, 47, 48, + 50, 52, 53, 54, 56, 57, 59, 60, 62, 63, + 64, 66, 67, 68, 69, 71, 72, 73, 74, 75, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 87, 88, 89, 90, 91, 91, 92, 93, 93, + 94, 95, 95, 96, 96, 97, 97, 97, 98, 98, + 98, 99, 99, 99, 99, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 99, 99, 99, 99, + 98, 98, 98, 97, 97, 97, 96, 96, 95, 95, + 94, 93, 93, 92, 91, 91, 90, 89, 88, 87, + 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, + 77, 75, 74, 73, 72, 71, 69, 68, 67, 66, + 64, 63, 62, 60, 59, 57, 56, 54, 53, 52, + 50, 48, 47, 45, 44, 42, 41, 39, 37, 36, + 34, 33, 31, 29, 28, 26, 24, 22, 21, 19, + 17, 16, 14, 12, 10, 9, 7, 5, 3, 2, + 0, -2, -3, -5, -7, -9, -10, -12, -14, -16, + -17, -19, -21, -22, -24, -26, -28, -29, -31, -33, + -34, -36, -37, -39, -41, -42, -44, -45, -47, -48, + -50, -52, -53, -54, -56, -57, -59, -60, -62, -63, + -64, -66, -67, -68, -69, -71, -72, -73, -74, -75, + -77, -78, -79, -80, -81, -82, -83, -84, -85, -86, + -87, -87, -88, -89, -90, -91, -91, -92, -93, -93, + -94, -95, -95, -96, -96, -97, -97, -97, -98, -98, + -98, -99, -99, -99, -99,-100,-100,-100,-100,-100, + -100,-100,-100,-100,-100,-100, -99, -99, -99, -99, + -98, -98, -98, -97, -97, -97, -96, -96, -95, -95, + -94, -93, -93, -92, -91, -91, -90, -89, -88, -87, + -87, -86, -85, -84, -83, -82, -81, -80, -79, -78, + -77, -75, -74, -73, -72, -71, -69, -68, -67, -66, + -64, -63, -62, -60, -59, -57, -56, -54, -53, -52, + -50, -48, -47, -45, -44, -42, -41, -39, -37, -36, + -34, -33, -31, -29, -28, -26, -24, -22, -21, -19, + -17, -16, -14, -12, -10, -9, -7, -5, -3, -2 +}; + +int16_t f_sin(int16_t v) +{ + v %= 360; + return sintab[v]; +} + +int16_t f_cos(int16_t v) +{ + v += 90; + v %= 360; + return sintab[v]; +} + void DrawLcdAnaClock(boolean show_seconds) { - //unsigned char *bbuf; - //char daystr[5]; - //int len; - int i, x, y, x2, y2; - double tmp, mf; - s8t hour, minute, seconds; + int16_t i, x, y, x2, y2; + int16_t tmp; + int8_t hour, minute, seconds; + char tstr[16]; hour = OswaldClk.hour; minute = OswaldClk.minute; seconds = OswaldClk.second; hour -= 3; - mf = (1. / 59.) * (double)minute; + if (hour < 0) + hour += 12; + // mf = (1. / 59.) * (double)minute; minute -= 15; + if (minute < 0) + minute += 60; seconds -= 15; + if (seconds < 0) + seconds += 60; - lcd_clear_display(); + hal_lcd_clear_display(); + + SetFont(MetaWatch16); + snprintf(tstr, 16, "%02d", OswaldClk.day); + WriteLcdString(70, 40, tstr); // plot(R*cos(360° * i/N), R*sin(360° * i/N)) for (i=0; i<12; i++) { - tmp = 48. + (43. * cos(((2. * M_PI) / 12.) * (double)i)); + tmp = 48 + ((43 * f_cos((360 / 12) * i)) / 100); x = tmp; - tmp = 48 + (43. * sin(((2. * M_PI) / 12.) * (double)i)); + tmp = 48 + ((43 * f_sin((360 / 12) * i)) / 100); y = tmp; - tmp = 48. + (48. * cos(((2. * M_PI) / 12.) * (double)i)); + tmp = 48 + ((48 * f_cos((360 / 12) * i)) / 100); x2 = tmp; - tmp = 48 + (48. * sin(((2. * M_PI) / 12.) * (double)i)); + tmp = 48 + ((48 * f_sin((360 / 12) * i)) / 100); y2 = tmp; DrawLcdLineBresenhamWW(x, y, x2, y2, 2); }; + // Hour - tmp = 48. + (30. * cos(((2. * M_PI) / 12.) * ((double)hour + mf))); + tmp = 48 + (30 * f_cos(((360 / 12) * hour) + ((OswaldClk.minute * 360) /12 / 60)) / 100); x = tmp; - tmp = 48 + (30. * sin(((2. * M_PI) / 12.) * ((double)hour + mf))); + tmp = 48 + (30 * f_sin(((360 / 12) * hour) + ((OswaldClk.minute * 360) /12 / 60)) / 100); y = tmp; DrawLcdLineBresenhamWW(48, 48, x, y, 2); // Minute - tmp = 48. + (40. * cos(((2. * M_PI) / 60.) * (double)minute)); + tmp = 48 + ((40 * f_cos((360 / 60) * minute)) / 100); x = tmp; - tmp = 48 + (40. * sin(((2. * M_PI) / 60.) * (double)minute)); + tmp = 48 + ((40 * f_sin((360 / 60) * minute)) / 100); y = tmp; DrawLcdLineBresenhamWW(48, 48, x, y, 2); if (show_seconds) { // Seconds - tmp = 48. + (40. * cos(((2. * M_PI) / 60.) * (double)seconds)); + tmp = 48 + ((40 * f_cos((360 / 60) * seconds)) / 100); x = tmp; - tmp = 48 + (40. * sin(((2. * M_PI) / 60.) * (double)seconds)); + tmp = 48 + ((40 * f_sin((360 / 60) * seconds)) / 100); y = tmp; DrawLcdLineBresenham(48, 48, x, y); }; - //snprintf(daystr, 5, "%d", day); - // mw_buf_print(mwbuf, 74, 45, daystr, 0, MW_WHITE, MW_BLACK); - lcd_update_display(); + hal_lcd_update_display(); } void DrawLcdDigitalClock(boolean show_seconds) { int gRow = 3; - int gColumn = 4; + int gColumn = 3; + char tstr[16]; SetFont(MetaWatchTime); - lcd_clear_display(); + hal_lcd_clear_display(); //gRow += WriteLcdCharacter(ui, gRow, gColumn, TIME_CHARACTER_SPACE_INDEX); - gRow += WriteLcdCharacter(gRow, gColumn, (OswaldClk.hour / 10)); - gRow += WriteLcdCharacter(gRow, gColumn, (OswaldClk.hour % 10)); + if (OswaldClk.clk24hr) { + gRow += WriteLcdCharacter(gRow, gColumn, (OswaldClk.hour / 10)); + gRow += WriteLcdCharacter(gRow, gColumn, (OswaldClk.hour % 10)); + } else { + unsigned char val = OswaldClk.hour; + if (val > 12) + val -= 12; + gRow += WriteLcdCharacter(gRow, gColumn, (val / 10)); + gRow += WriteLcdCharacter(gRow, gColumn, (val % 10)); + } gRow += WriteLcdCharacter(gRow, gColumn, TIME_CHARACTER_COLON_INDEX); gRow += WriteLcdCharacter(gRow, gColumn, (OswaldClk.minute / 10)); gRow += WriteLcdCharacter(gRow, gColumn, (OswaldClk.minute % 10)); + + gRow += 3; if (show_seconds) { - gRow += WriteLcdCharacter(gRow, gColumn, TIME_CHARACTER_COLON_INDEX); - gRow += WriteLcdCharacter(gRow, gColumn, (OswaldClk.second / 10)); - gRow += WriteLcdCharacter(gRow, gColumn, (OswaldClk.second % 10)); + SetFont(MetaWatch16); + snprintf(tstr, 16, "%02d", OswaldClk.second); + WriteLcdString(gRow, 9, tstr); }; - lcd_update_display(); + + SetFont(MetaWatch7); + + if (!OswaldClk.clk24hr) { + if (OswaldClk.hour > 12) { + WriteLcdString(gRow, 3, "PM"); + } else { + WriteLcdString(gRow, 3, "AM"); + } + } + + SetFont(MetaWatch16); + + if (OswaldClk.day_first) + snprintf(tstr, 16, "%d.%d.%d", OswaldClk.day, OswaldClk.month, OswaldClk.year); + else + snprintf(tstr, 16, "%d/%d %d", OswaldClk.month, OswaldClk.day, OswaldClk.year); + WriteLcdString(3, 25, tstr); + + snprintf(tstr, 16, "%d%% (%dmV)", OswaldPowerState.percent, OswaldPowerState.level); + WriteLcdString(2, 48, tstr); + WriteLcdString(2, 64, OswaldPowerState.source ? "ext" : "bat"); + + /* this makes only sense when the charger is active */ + if (OswaldPowerState.source) { + switch (OswaldPowerState.charge_state) { + case POWER_CHARGER_DONE: + WriteLcdString(2, 80, "charge done"); + break; + case POWER_CHARGER_PRECHARGE: + WriteLcdString(2, 80, "precharging"); + break; + case POWER_CHARGER_CHARGING: + WriteLcdString(2, 80, "charging"); + break; + case POWER_CHARGER_UNK: + WriteLcdString(2, 80, "charge unkn."); + break; + default: + break; + }; + }; + hal_lcd_update_display(); } +