}
}
-
u8t WriteLcdCharacter(u8t x, u8t y, u8t Character)
{
u8t CharacterHeight = GetCharacterHeight();
}
}
+
+void WriteLcdNumber(u8t x, u8t y, s16t number)
+{
+ register lx, i, strl;
+ u8t str[8];
+
+ itoa(number, str, 10);
+ strl = oswald_strlen(str);
+ if (strl == 0)
+ return;
+
+ lx = x;
+ for (i=0; i<strl; i++) {
+ lx += WriteLcdCharacter(lx, y, str[i]);
+ }
+}
+
return FALSE;
}
+void ambientlight_value_changed (GtkRange *range, gpointer user_data)
+{
+ oswald_ui *ui = (oswald_ui *)user_data;
+ double val;
+
+ val = gtk_range_get_value(range);
+ oswald_handle_ambientlight_event((u8t) val);
+}
+
+void accelX_value_changed (GtkRange *range, gpointer user_data)
+{
+ oswald_ui *ui = (oswald_ui *)user_data;
+ double val;
+
+ val = gtk_range_get_value(range);
+ ui->accel_x = (u8t)val;
+ oswald_handle_accel_event(ui->accel_x, ui->accel_y, ui->accel_z);
+}
+
+void accelY_value_changed (GtkRange *range, gpointer user_data)
+{
+ oswald_ui *ui = (oswald_ui *)user_data;
+ double val;
+
+ val = gtk_range_get_value(range);
+ ui->accel_y = (u8t)val;
+ oswald_handle_accel_event(ui->accel_x, ui->accel_y, ui->accel_z);
+}
+
+void accelZ_value_changed (GtkRange *range, gpointer user_data)
+{
+ oswald_ui *ui = (oswald_ui *)user_data;
+ double val;
+
+ val = gtk_range_get_value(range);
+ ui->accel_z = (u8t)val;
+ oswald_handle_accel_event(ui->accel_x, ui->accel_y, ui->accel_z);
+}
+
static void create_mainwin(oswald_ui *ui)
{
GtkWidget *mvb, *hb, *vb, *btn, *sc, *l;
gtk_box_pack_start (GTK_BOX(vb), btn, FALSE, FALSE, 10);
g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(button_C_clicked), ui);
+ // ambient light sensor
sc = gtk_vscale_new_with_range (0, 255, 1);
gtk_box_pack_start (GTK_BOX(hb), sc, FALSE, FALSE, 5);
+ g_signal_connect(G_OBJECT(sc), "value-changed", G_CALLBACK(ambientlight_value_changed), ui);
hb = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start (GTK_BOX(mvb), hb, FALSE, FALSE, 5);
gtk_box_pack_start (GTK_BOX(hb), l, FALSE, FALSE, 5);
sc = gtk_hscale_new_with_range (0, 255, 1);
gtk_box_pack_start (GTK_BOX(hb), sc, TRUE, TRUE, 5);
+ g_signal_connect(G_OBJECT(sc), "value-changed", G_CALLBACK(accelX_value_changed), ui);
l = gtk_label_new("Y:");
gtk_box_pack_start (GTK_BOX(hb), l, FALSE, FALSE, 5);
sc = gtk_hscale_new_with_range (0, 255, 1);
gtk_box_pack_start (GTK_BOX(hb), sc, TRUE, TRUE, 5);
+ g_signal_connect(G_OBJECT(sc), "value-changed", G_CALLBACK(accelY_value_changed), ui);
l = gtk_label_new("Z:");
gtk_box_pack_start (GTK_BOX(hb), l, FALSE, FALSE, 5);
sc = gtk_hscale_new_with_range (0, 255, 1);
gtk_box_pack_start (GTK_BOX(hb), sc, TRUE, TRUE, 5);
+ g_signal_connect(G_OBJECT(sc), "value-changed", G_CALLBACK(accelZ_value_changed), ui);
gtk_widget_show_all(ui->mainwin);
}
-gboolean one_second_tmo_handler (gpointer userdata)
+static gboolean one_second_tmo_handler (gpointer userdata)
{
oswald_ui *ui = (oswald_ui *)userdata;
return TRUE;
}
-gboolean app_idle_handler (gpointer user_data)
+static gboolean app_idle_handler (gpointer user_data)
{
g_print("i");
if (OswaldState.pending_idle) {
return FALSE;
}
+static gboolean centisecond_tmo_handler (gpointer userdata)
+{
+ oswald_ui *ui = (oswald_ui *)userdata;
+
+ if (ui->centisecond_active)
+ oswald_centisecond_tick();
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+void enable_centisecond_timer(void)
+{
+ ui_g->centisecond_active = TRUE;
+ g_timeout_add(10, centisecond_tmo_handler, ui_g);
+}
+
+void disable_centisecond_timer(void)
+{
+ ui_g->centisecond_active = FALSE;
+}
+
+static gboolean halfsecond_tmo_handler (gpointer userdata)
+{
+ oswald_ui *ui = (oswald_ui *)userdata;
+
+ if (ui->halfsecond_active)
+ oswald_halfsecond_tick();
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+void enable_halfsecond_timer(void)
+{
+ ui_g->halfsecond_active = TRUE;
+ g_timeout_add(500, halfsecond_tmo_handler, ui_g);
+}
+
+void disable_halfsecond_timer(void)
+{
+ ui_g->halfsecond_active = FALSE;
+}
+
int main(int argc , char ** argv)
{
oswald_ui ui;
ui_g = &ui;
+ ui.accel_x = 0;
+ ui.accel_y = 0;
+ ui.accel_z = 0;
+ ui.halfsecond_active = FALSE;
+ ui.centisecond_active = FALSE;
+
mt = time(NULL);
localtime_r(&mt, &mtime);
create_mainwin(&ui);
gtk_widget_realize(ui.mainwin);
- oswald_set_time(mtime.tm_hour, mtime.tm_min, mtime.tm_sec);
+ oswald_set_time(mtime.tm_hour, mtime.tm_min, mtime.tm_sec, TRUE);
+ oswald_set_date(mtime.tm_mday, (mtime.tm_mon + 1), (mtime.tm_year + 1900), TRUE);
oswald_init();
g_timeout_add_seconds(1, one_second_tmo_handler, &ui);
GtkWidget *mainwin;
GtkWidget *darea;
GdkPixmap *pixmap;
+ u8t accel_x;
+ u8t accel_y;
+ u8t accel_z;
+ gboolean halfsecond_active;
+ gboolean centisecond_active;
} oswald_ui;
void lcd_set_pixel(gint x, gint y, gboolean state);
void lcd_clear_display(void);
+void enable_centisecond_timer(void);
+void disable_centisecond_timer(void);
+
+void enable_halfsecond_timer(void);
+void disable_halfsecond_timer(void);
+
#endif
u8t second;
u8t day;
u8t month;
- u8t year;
+ u16t year;
+ boolean clk24hr;
+ boolean day_first;
} clock_state;
typedef enum {
IDLE_SCREEN = 0,
ACCEL_DISPLAY_SCREEN,
- DATETIME_SETTING_SCREEN,
MENU_TEST_SCREEN,
// SCREEN2_SCREEN,
// SCREEN3_SCREEN,
// APPLICATION_SCREEN,
LAST_SCREEN, // a marker for the last (not valid) screen)
+ DATETIME_SETTING_SCREEN,
} screen_number;
typedef enum {
#define EVENT_SCREEN_VISIBLE (1<<0) // screen just became visible
#define EVENT_SCREEN_DESTROY (1<<1) // screen is destroyed
-#define EVENT_ONE_SEC_TIMER (1<<2)
-#define EVENT_MS_TIMER (1<<3)
-#define EVENT_USER_BUTTONS (1<<4)
-#define EVENT_ACCEL_UPDATE (1<<5)
-#define EVENT_AMBIENTLIGHT_UPDATE (1<<6)
-#define EVENT_POWER_CHANGE (1<<7)
-#define EVENT_COMMS (1<<8)
+#define EVENT_ONE_SEC_TIMER (1<<2) // one second timer for reguler clock
+#define EVENT_HALF_SEC_TIMER (1<<3) // half second timer for blinking displays
+#define EVENT_CS_TIMER (1<<4) // centisecond timer, e.g. for stop watch
+#define EVENT_USER_BUTTONS (1<<5) // button presses
+#define EVENT_ACCEL_UPDATE (1<<6) // accelerometer updates
+#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
typedef struct {
u16t event_mask; // the event the screen wants to receive
boolean pending_idle;
} watch_state;
+typedef struct {
+ u8t x;
+ u8t y;
+ u8t z;
+} accel_data_t;
+
#endif
}
}
-void oswald_set_time(u8t hour, u8t minute, u8t second)
+void oswald_set_time(u8t hour, u8t minute, u8t second, boolean clk24hr)
{
OswaldClk.hour = hour;
OswaldClk.minute = minute;
OswaldClk.second = second;
+ OswaldClk.clk24hr = clk24hr;
+}
+
+void oswald_set_date(u8t day, u8t month, u16t year, boolean day_first)
+{
+ OswaldClk.day = day;
+ OswaldClk.month = month;
+ OswaldClk.year = year;
+ OswaldClk.day_first = day_first;
}
static void update_clock_state (void)
if (OswaldState.screen->event_func != NULL &&
(OswaldState.screen->event_mask & EVENT_ONE_SEC_TIMER))
OswaldState.screen->event_func(EVENT_ONE_SEC_TIMER, NULL);
- // oswald_update_screen();
+}
+
+void oswald_centisecond_tick(void)
+{
+ if (OswaldState.screen->event_func != NULL &&
+ (OswaldState.screen->event_mask & EVENT_CS_TIMER))
+ OswaldState.screen->event_func(EVENT_CS_TIMER, NULL);
+}
+
+void oswald_halfsecond_tick(void)
+{
+ if (OswaldState.screen->event_func != NULL &&
+ (OswaldState.screen->event_mask & EVENT_HALF_SEC_TIMER))
+ OswaldState.screen->event_func(EVENT_HALF_SEC_TIMER, NULL);
}
void oswald_handle_button_press(watch_button button)
OswaldState.screen->event_func(EVENT_USER_BUTTONS, &button);
break;
case BUTTON_C:
+ OswaldState.screen->event_func(EVENT_SCREEN_DESTROY, NULL);
// next screen
OswaldState.screen_id++;
if (OswaldState.screen_id >= LAST_SCREEN) {
};
}
+void oswald_handle_accel_event(u8t x, u8t y, u8t z)
+{
+ accel_data_t accel_data;
+
+ accel_data.x = x;
+ accel_data.y = y;
+ accel_data.z = z;
+
+ if (OswaldState.screen->event_func != NULL &&
+ (OswaldState.screen->event_mask & EVENT_ACCEL_UPDATE))
+ OswaldState.screen->event_func(EVENT_ACCEL_UPDATE, &accel_data);
+}
+
+void oswald_handle_ambientlight_event(u8t light_level)
+{
+ if (OswaldState.screen->event_func != NULL &&
+ (OswaldState.screen->event_mask & EVENT_AMBIENTLIGHT_UPDATE))
+ OswaldState.screen->event_func(EVENT_AMBIENTLIGHT_UPDATE, &light_level);
+}
+
void oswald_init(void)
{
OswaldScreens[IDLE_SCREEN].event_mask = EVENT_USER_BUTTONS | EVENT_ONE_SEC_TIMER;
OswaldScreens[IDLE_SCREEN].event_func = idle_handle_events;
- OswaldScreens[ACCEL_DISPLAY_SCREEN].event_mask = EVENT_USER_BUTTONS;
+ OswaldScreens[ACCEL_DISPLAY_SCREEN].event_mask = EVENT_USER_BUTTONS | EVENT_ACCEL_UPDATE;
OswaldScreens[ACCEL_DISPLAY_SCREEN].event_func = accel_handle_events;
-
- OswaldScreens[DATETIME_SETTING_SCREEN].event_mask = EVENT_USER_BUTTONS | EVENT_ONE_SEC_TIMER;
+ OswaldScreens[DATETIME_SETTING_SCREEN].event_mask = EVENT_USER_BUTTONS | EVENT_HALF_SEC_TIMER;
OswaldScreens[DATETIME_SETTING_SCREEN].event_func = datetime_setup_events;
OswaldScreens[MENU_TEST_SCREEN].event_mask = EVENT_USER_BUTTONS;
void oswald_one_second_tick();
/* sets internal 'RTC' time */
-void oswald_set_time(u8t hour, u8t minute, u8t second);
+void oswald_set_time(u8t hour, u8t minute, u8t second, boolean clk24hr);
+void oswald_set_date(u8t day, u8t month, u16t year, boolean day_first);
void oswald_handle_button_press(watch_button button);
void oswald_handle_accel_event(u8t x, u8t y, u8t z);
void oswald_handle_ambientlight_event(u8t light_level);
void oswald_handle_idle_event(void);
+void oswald_one_second_tick(void);
+void oswald_halfsecond_tick(void);
+void oswald_centisecond_tick(void);
void oswald_init(void);
#endif
#include "oswald.h"
+#include "oswald_main.h"
#include "oswald_watch_faces.h"
#include "Fonts.h"
#include "LcdDisplay.h"
#include "oswald_screens.h"
+
typedef struct {
- void (*screendraw_func)(boolean shoq_seconds);
+ void (*screendraw_func)(boolean show_seconds);
boolean show_seconds;
boolean analogue;
} idle_data_t;
void idle_handle_user_buttons(watch_button button)
{
switch (button) {
- case BUTTON_D:
+ case BUTTON_A:
if (idle_screen.show_seconds)
idle_screen.show_seconds = FALSE;
else
idle_screen.show_seconds = TRUE;
break;
- case BUTTON_E:
+ case BUTTON_B:
if (idle_screen.analogue == TRUE) {
idle_screen.analogue = FALSE;
idle_screen.screendraw_func = DrawLcdDigitalClock;
idle_screen.screendraw_func = DrawLcdAnaClock;
};
break;
+ case BUTTON_D:
+ OswaldState.screen_id = DATETIME_SETTING_SCREEN;
+ OswaldState.screen = &OswaldScreens[OswaldState.screen_id];
+ OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL);
+ return;
+ break;
default:
break;
};
}
-void draw_accel_screen(void)
+typedef struct {
+ accel_data_t accdata;
+} accelscreen_data_t;
+static accelscreen_data_t accel_screen = {
+ { 0, 0, 0},
+};
+
+void draw_accel_screen(accel_data_t *accel_data)
{
lcd_clear_display();
SetFont(MetaWatch16);
WriteLcdString(2, 2, "X:");
- WriteLcdString(20, 2, "123");
- WriteLcdString(2, 18, "Z:");
- WriteLcdString(20, 18, "123");
- WriteLcdString(2, 34, "Y:");
- WriteLcdString(20, 34, "123");
+ WriteLcdNumber(20, 2, accel_data->x);
+ WriteLcdString(2, 18, "Y:");
+ WriteLcdNumber(20, 18, accel_data->y);
+ WriteLcdString(2, 34, "Z:");
+ WriteLcdNumber(20, 34, accel_data->z);
}
void accel_handle_events(u16t event, void *data)
{
switch (event) {
case EVENT_SCREEN_VISIBLE:
- draw_accel_screen();
+ draw_accel_screen(&accel_screen.accdata);
+ break;
+ case EVENT_ACCEL_UPDATE: {
+ accel_data_t *accel_data = (accel_data_t *)data;
+ accel_screen.accdata.x = accel_data->x;
+ accel_screen.accdata.y = accel_data->y;
+ accel_screen.accdata.z = accel_data->z;
+ draw_accel_screen(&accel_screen.accdata);
+ };
break;
case EVENT_USER_BUTTONS:
dbg_out("button event %d\n", *(int *)data);
}
-void draw_datetime_setup_screen(void)
+typedef struct {
+ u8t pos;
+ boolean on;
+} datetime_setup_data_t;
+static datetime_setup_data_t dt_setup_screen = {
+ 0,
+ TRUE
+};
+
+void draw_datetime_setup_screen(datetime_setup_data_t *sdata)
{
lcd_clear_display();
SetFont(MetaWatch16);
- WriteLcdString(2, 2, "Date / Time");
- WriteLcdString(2, 18, "Setting");
- WriteLcdString(2, 34, "22:39");
- WriteLcdString(2, 50, "07.08.2012");
+ WriteLcdString(2, 2, "Set");
+
+ SetFont(MetaWatchTime);
+ if ((sdata->pos == 0 && sdata->on) || sdata->pos != 0) {
+ WriteLcdCharacter(2, 20, (OswaldClk.hour / 10));
+ WriteLcdCharacter(14, 20, (OswaldClk.hour % 10));
+ }
+ WriteLcdCharacter(26, 20, TIME_CHARACTER_COLON_INDEX);
+
+ if ((sdata->pos == 1 && sdata->on) || sdata->pos != 1) {
+ WriteLcdCharacter(31, 20, (OswaldClk.minute / 10));
+ WriteLcdCharacter(43, 20, (OswaldClk.minute % 10));
+ }
+
+ WriteLcdCharacter(55, 20, TIME_CHARACTER_COLON_INDEX);
+
+ if ((sdata->pos == 2 && sdata->on) || sdata->pos != 2) {
+ WriteLcdCharacter(60, 20, (OswaldClk.second / 10));
+ WriteLcdCharacter(72, 20, (OswaldClk.second % 10));
+ }
+
+ SetFont(MetaWatch16);
+ if ((sdata->pos == 3 && sdata->on) || sdata->pos != 3) {
+ WriteLcdNumber(2, 45, OswaldClk.day);
+ }
+ WriteLcdString(18, 45, ".");
+ if ((sdata->pos == 4 && sdata->on) || sdata->pos != 4) {
+ WriteLcdNumber(22, 45, OswaldClk.month);
+ }
+ WriteLcdString(38, 45, ".");
+ if ((sdata->pos == 5 && sdata->on) || sdata->pos != 5) {
+ WriteLcdNumber(42, 45, OswaldClk.year);
+ }
+
+ 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");
+}
+
+void datetime_handle_updown(u8t pos, s8t incr)
+{
+ switch (pos) {
+ case 0: // hour
+ if (OswaldClk.hour == 0 && incr == -1) {
+ OswaldClk.hour = 23;
+ break;
+ };
+ OswaldClk.hour += incr;
+ if (OswaldClk.hour > 23)
+ OswaldClk.hour = 0;
+ break;
+ case 1: // minute
+ if (OswaldClk.minute == 0 && incr == -1) {
+ OswaldClk.minute = 59;
+ break;
+ };
+ OswaldClk.minute += incr;
+ if (OswaldClk.minute > 59)
+ OswaldClk.minute = 0;
+ break;
+ case 2: // second
+ OswaldClk.second = 0;
+ break;
+ case 3: // day
+ if (OswaldClk.day == 1 && incr == -1) {
+ OswaldClk.day = 31;
+ break;
+ };
+ OswaldClk.day += incr;
+ if (OswaldClk.day > 31)
+ OswaldClk.day = 1;
+ break;
+ case 4: // month
+ if (OswaldClk.month == 1 && incr == -1) {
+ OswaldClk.month = 12;
+ break;
+ };
+ OswaldClk.month += incr;
+ if (OswaldClk.month > 12)
+ OswaldClk.month = 1;
+ break;
+ case 5: // year
+ OswaldClk.year += incr;
+ break;
+ case 6: // 24hr / 12hr
+ if (OswaldClk.clk24hr)
+ OswaldClk.clk24hr = FALSE;
+ else
+ OswaldClk.clk24hr = TRUE;
+ break;
+ case 7: // dd.mm. / mm/dd
+ if (OswaldClk.day_first)
+ OswaldClk.day_first = FALSE;
+ else
+ OswaldClk.day_first = TRUE;
+ break;
+ default:
+ break;
+ };
+}
+
+void handle_setup_datetime_buttons(watch_button button, datetime_setup_data_t *sdata)
+{
+ switch (button) {
+ case BUTTON_A:
+ datetime_handle_updown(sdata->pos, 1);
+ break;
+ case BUTTON_B:
+ datetime_handle_updown(sdata->pos, -1);
+ break;
+ case BUTTON_D:
+ sdata->pos++;
+ sdata->pos %= 8;
+ break;
+ default:
+ break;
+ }
+ draw_datetime_setup_screen(sdata);
}
void datetime_setup_events(u16t event, void *data)
{
switch (event) {
case EVENT_SCREEN_VISIBLE:
- draw_datetime_setup_screen();
+ draw_datetime_setup_screen(&dt_setup_screen);
+ enable_halfsecond_timer();
+ break;
+ case EVENT_SCREEN_DESTROY:
+ disable_halfsecond_timer();
break;
case EVENT_USER_BUTTONS:
dbg_out("button event %d\n", *(int *)data);
+ handle_setup_datetime_buttons(*(watch_button *)data, &dt_setup_screen);
+ break;
+ case EVENT_HALF_SEC_TIMER:
+ if (dt_setup_screen.on)
+ dt_setup_screen.on = FALSE;
+ else
+ dt_setup_screen.on = TRUE;
+ draw_datetime_setup_screen(&dt_setup_screen);
break;
default:
break;
return i;
}
+char* itoa(s16t value, char* result, int base)
+{
+ char* ptr = result, *ptr1 = result, tmp_char;
+ s16t tmp_value;
+
+ if (result == NULL)
+ return NULL;
+
+ // check that the base if valid
+ if (base < 2 || base > 36) {
+ *result = '\0';
+ return result;
+ }
+
+ do {
+ tmp_value = value;
+ value /= base;
+ *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
+ } while ( value );
+
+ // Apply negative sign
+ if (tmp_value < 0)
+ *ptr++ = '-';
+ *ptr-- = '\0';
+ while (ptr1 < ptr) {
+ tmp_char = *ptr;
+ *ptr--= *ptr1;
+ *ptr1++ = tmp_char;
+ }
+ return result;
+}
+
#define _OSWALD_STRINGS_H
u16t oswald_strlen(u8t *string);
+char* itoa(s16t value, char* result, int base);
#endif