]> git.karo-electronics.de Git - oswald.git/blob - ui/oswald_screens.c
Some minor improvements.
[oswald.git] / ui / oswald_screens.c
1 #include <stdio.h>
2
3 #include "oswald.h"
4 #include "oswald_main.h"
5 #include "oswald_watch_faces.h"
6 #include "oswald_graphics.h"
7 #include "oswald_hal.h"
8
9 #include "oswald_screens.h"
10
11 #if defined(__GNUC__) && (__MSP430X__ > 0)
12 __attribute__((__far__))
13 #endif
14 #include "bitmaps/startstopbutton_icon.xbm"
15
16 #if defined(__GNUC__) && (__MSP430X__ > 0)
17 __attribute__((__far__))
18 #endif
19 #include "bitmaps/lapsebutton_icon.xbm"
20
21 #if defined(__GNUC__) && (__MSP430X__ > 0)
22 __attribute__((__far__))
23 #endif
24 #include "bitmaps/upbutton_icon.xbm"
25
26 #if defined(__GNUC__) && (__MSP430X__ > 0)
27 __attribute__((__far__))
28 #endif
29 #include "bitmaps/downbutton_icon.xbm"
30
31 #if defined(__GNUC__) && (__MSP430X__ > 0)
32 __attribute__((__far__))
33 #endif
34 #include "bitmaps/leftbutton_icon.xbm"
35
36 #if defined(__GNUC__) && (__MSP430X__ > 0)
37 __attribute__((__far__))
38 #endif
39 #include "bitmaps/rightbutton_icon.xbm"
40
41 #if defined(__GNUC__) && (__MSP430X__ > 0)
42 __attribute__((__far__))
43 #endif
44 #include "bitmaps/enterbutton_icon.xbm"
45
46 #if defined(__GNUC__) && (__MSP430X__ > 0)
47 __attribute__((__far__))
48 #endif
49 #include "bitmaps/checked_icon.xbm"
50
51 #if defined(__GNUC__) && (__MSP430X__ > 0)
52 __attribute__((__far__))
53 #endif
54 #include "bitmaps/unchecked_icon.xbm"
55
56 #if defined(__GNUC__) && (__MSP430X__ > 0)
57 __attribute__((__far__))
58 #endif
59 #include "bitmaps/main_menu_icon.xbm"
60
61 #if defined(__GNUC__) && (__MSP430X__ > 0)
62 __attribute__((__far__))
63 #endif
64 #include "bitmaps/timesetup_icon.xbm"
65
66 #if defined(__GNUC__) && (__MSP430X__ > 0)
67 __attribute__((__far__))
68 #endif
69 #include "bitmaps/stopwatch_icon.xbm"
70
71 #if defined(__GNUC__) && (__MSP430X__ > 0)
72 __attribute__((__far__))
73 #endif
74 #include "bitmaps/alarm_icon.xbm"
75
76 #if defined(__GNUC__) && (__MSP430X__ > 0)
77 __attribute__((__far__))
78 #endif
79 #include "bitmaps/Bluetooth_icon.xbm"
80
81 #if defined(__GNUC__) && (__MSP430X__ > 0)
82 __attribute__((__far__))
83 #endif
84 #include "bitmaps/info_icon.xbm"
85
86 #if defined(__GNUC__) && (__MSP430X__ > 0)
87 __attribute__((__far__))
88 #endif
89 #include "bitmaps/acc_icon.xbm"
90
91 #if defined(__GNUC__) && (__MSP430X__ > 0)
92 __attribute__((__far__))
93 #endif
94 #include "bitmaps/Message_icon.xbm"
95
96 #if defined(__GNUC__) && (__MSP430X__ > 0)
97 __attribute__((__far__))
98 #endif
99 #include "bitmaps/Exit_icon.xbm"
100
101
102 /*
103  * Common event handler part of the watch faces
104  */
105 typedef struct {
106         void (*screendraw_func)(boolean show_seconds);
107         boolean show_seconds;
108         boolean analogue;
109 } idle_data_t;
110 static idle_data_t idle_screen = {
111         DrawLcdDigitalClock,
112         TRUE,
113         FALSE,
114 };
115  
116 event_ret_t idle_handle_user_buttons(watch_button button)
117 {
118         switch (button) {
119                 case BUTTON_A:
120                         if (idle_screen.show_seconds)
121                                 idle_screen.show_seconds = FALSE;
122                         else
123                                 idle_screen.show_seconds = TRUE;
124                         break;
125                 case BUTTON_B:
126                         if (idle_screen.analogue == TRUE) {
127                                 idle_screen.analogue = FALSE;
128                                 idle_screen.screendraw_func = DrawLcdDigitalClock;
129                         } else {
130                                 idle_screen.analogue = TRUE;
131                                 idle_screen.screendraw_func = DrawLcdAnaClock;
132                         };
133                         break;
134                 case BUTTON_C:
135                         OswaldState.screen_id = MAIN_MENU_SCREEN;
136                         OswaldState.screen = &OswaldScreens[OswaldState.screen_id];
137                         OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL);
138                         return EVENT_RET_HANDLED;
139                         break;
140                 case BUTTON_F:
141                         OswaldState.screen_id = DATETIME_SETTING_SCREEN;
142                         OswaldState.screen = &OswaldScreens[OswaldState.screen_id];
143                         OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL);
144                         return EVENT_RET_HANDLED;
145                         break;
146                 default:
147                         return EVENT_RET_UNHANDLED;
148                         break;
149         };
150
151         idle_screen.screendraw_func(idle_screen.show_seconds);
152
153         return EVENT_RET_HANDLED;
154 }
155
156 event_ret_t idle_handle_events(uint16_t event, void *data)
157 {
158         switch (event) {
159                 case EVENT_ONE_SEC_TIMER:
160                 case EVENT_SCREEN_VISIBLE:
161                         idle_screen.screendraw_func(idle_screen.show_seconds);
162                         return EVENT_RET_HANDLED;
163                         break;
164                 case EVENT_USER_BUTTONS:
165                         dbg_out("button event %d\n", *(int *)data);
166                         return idle_handle_user_buttons(*(watch_button *)data);
167                         break;
168                 default:
169                         return EVENT_RET_UNHANDLED;
170                         break;
171         };
172         return EVENT_RET_UNHANDLED;
173 }
174
175
176 /*
177  * Main Menu Screen
178  */
179 typedef struct {
180         int8_t pos;
181         uint8_t tmo;
182 } main_menu_data_t;
183 static main_menu_data_t main_menu_screen = {
184         ALARM_SETUP_SCREEN,
185         0,
186 };
187
188 #define MAIN_MENU_GRID_PIXEL    84
189 #define MAIN_MENU_GRID_X        3
190 // GRID_Y is +1 since there is one empty row for title icon
191 #define MAIN_MENU_GRID_Y        3
192 #define MAIN_MENU_GRID_SPACING  0
193 #define MAIN_MENU_OFFSET_X      6
194 #define MAIN_MENU_OFFSET_Y      8
195
196 void draw_main_menu_screen(main_menu_data_t *sdata)
197 {
198         uint8_t pf = sdata->pos - 2;
199
200         hal_lcd_clear_display();
201
202 //      oswald_draw_bitmap(36, 0, main_menu_icon_width, main_menu_icon_height, main_menu_icon_bits);
203
204         oswald_draw_bitmap(81, 6, rightbutton_icon_width, rightbutton_icon_height, rightbutton_icon_bits);
205         oswald_draw_bitmap(81, 38, leftbutton_icon_width, leftbutton_icon_height, leftbutton_icon_bits);
206         oswald_draw_bitmap(81, 70, enterbutton_icon_width, enterbutton_icon_height, enterbutton_icon_bits);
207
208         oswald_draw_bitmpa_invert_opt(MAIN_MENU_OFFSET_X+((0+1) * MAIN_MENU_GRID_SPACING) + (0 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)),
209                 MAIN_MENU_OFFSET_Y+(0 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)),
210                 alarm_icon_width, alarm_icon_height, alarm_icon_bits, (sdata->pos == ALARM_SETUP_SCREEN));
211         oswald_draw_bitmpa_invert_opt(MAIN_MENU_OFFSET_X+((1+1) * MAIN_MENU_GRID_SPACING) + (1 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)),
212                 MAIN_MENU_OFFSET_Y+(0 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)),
213                 stopwatch_icon_width, stopwatch_icon_height, stopwatch_icon_bits, (sdata->pos == STOP_WATCH_SCREEN));
214         oswald_draw_bitmpa_invert_opt(MAIN_MENU_OFFSET_X+((2+1) * MAIN_MENU_GRID_SPACING) + (2 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)),
215                 MAIN_MENU_OFFSET_Y+(0 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)),
216                 Bluetooth_icon_width, Bluetooth_icon_height, Bluetooth_icon_bits, (sdata->pos == BLUETOOTH_SCREEN));
217         oswald_draw_bitmpa_invert_opt(MAIN_MENU_OFFSET_X+((0+1) * MAIN_MENU_GRID_SPACING) + (0 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)),
218                 MAIN_MENU_OFFSET_Y+(1 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)),
219                 acc_icon_width, acc_icon_height, acc_icon_bits, (sdata->pos == ACCEL_DISPLAY_SCREEN));
220         oswald_draw_bitmpa_invert_opt(MAIN_MENU_OFFSET_X+((1+1) * MAIN_MENU_GRID_SPACING) + (1 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)),
221                 MAIN_MENU_OFFSET_Y+(1 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)),
222                 Message_icon_width, Message_icon_height, Message_icon_bits, (sdata->pos == MESSAGES_SCREEN));
223         oswald_draw_bitmpa_invert_opt(MAIN_MENU_OFFSET_X+((2+1) * MAIN_MENU_GRID_SPACING) + (2 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)),
224                 MAIN_MENU_OFFSET_Y+(1 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)),
225                 info_icon_width, info_icon_height, info_icon_bits, (sdata->pos == INFO_SCREEN));
226         oswald_draw_bitmpa_invert_opt(MAIN_MENU_OFFSET_X+((0+1) * MAIN_MENU_GRID_SPACING) + (0 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)),
227                 MAIN_MENU_OFFSET_Y+(2 * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)),
228                 Exit_icon_width, Exit_icon_height, Exit_icon_bits, (sdata->pos == LAST_SCREEN));
229
230         // round the corners of the inverted icon a little
231         hal_lcd_set_pixel(MAIN_MENU_OFFSET_X+((pf%MAIN_MENU_GRID_X) * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)) % (MAIN_MENU_GRID_X*(MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)),
232                 MAIN_MENU_OFFSET_Y+((pf/MAIN_MENU_GRID_X) * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)) % (MAIN_MENU_GRID_Y*(MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)), FALSE);
233         hal_lcd_set_pixel(MAIN_MENU_OFFSET_X+23+((pf%MAIN_MENU_GRID_X) * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)) % (MAIN_MENU_GRID_X*(MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)),
234                 MAIN_MENU_OFFSET_Y+((pf/MAIN_MENU_GRID_X) * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)) % (MAIN_MENU_GRID_Y*(MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)), FALSE);
235         hal_lcd_set_pixel(MAIN_MENU_OFFSET_X+((pf%MAIN_MENU_GRID_X) * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)) % (MAIN_MENU_GRID_X*(MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)),
236                 MAIN_MENU_OFFSET_Y+23+((pf/MAIN_MENU_GRID_X) * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)) % (MAIN_MENU_GRID_Y*(MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)), FALSE);
237         hal_lcd_set_pixel(MAIN_MENU_OFFSET_X+23+((pf%MAIN_MENU_GRID_X) * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)) % (MAIN_MENU_GRID_X*(MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_X)),
238                 MAIN_MENU_OFFSET_Y+23+((pf/MAIN_MENU_GRID_X) * (MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)) % (MAIN_MENU_GRID_Y*(MAIN_MENU_GRID_PIXEL / MAIN_MENU_GRID_Y)), FALSE);
239
240
241         // finally a nice border
242         oswald_draw_line(3, 0, 95, 0);
243         oswald_draw_line(2, 1, 95, 1);
244         oswald_draw_line(1, 2, 95, 2);
245
246         oswald_draw_line(0, 3, 0, 92);
247         oswald_draw_line(1, 3, 1, 93);
248         oswald_draw_line(2, 3, 2, 94);
249
250         oswald_draw_line(1, 93, 95, 93);
251         oswald_draw_line(2, 94, 95, 94);
252         oswald_draw_line(3, 95, 95, 95);
253
254         hal_lcd_update_display();
255 }
256
257 event_ret_t handle_main_menu_buttons(watch_button button, main_menu_data_t *sdata)
258 {
259         switch (button) {
260                 case BUTTON_A:
261                         sdata->pos++;
262                         if (sdata->pos > LAST_SCREEN)
263                                 sdata->pos = 2;
264                         draw_main_menu_screen(&main_menu_screen);
265                         return EVENT_RET_HANDLED;
266                         break;
267                 case BUTTON_B:
268                         sdata->pos--;
269                         if (sdata->pos < 2)
270                                 sdata->pos = LAST_SCREEN;
271                         draw_main_menu_screen(&main_menu_screen);
272                         return EVENT_RET_HANDLED;
273                         break;
274                 case BUTTON_C:
275                         if (sdata->pos < LAST_SCREEN) {
276                                 OswaldState.screen_id = sdata->pos;
277                                 OswaldState.screen = &OswaldScreens[OswaldState.screen_id];
278                                 OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL);
279                         } else {
280                                 OswaldState.screen_id = IDLE_SCREEN;
281                                 OswaldState.screen = &OswaldScreens[OswaldState.screen_id];
282                                 OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL);
283                         }
284                         return EVENT_RET_HANDLED;
285                         break;
286                 default:
287                         break;
288         }
289
290         return EVENT_RET_UNHANDLED;
291 }
292
293 /* after MAIN_MENU_TIMEOUT seconds return to IDLE_SCREEN */
294 #define MAIN_MENU_TIMEOUT       10
295
296 event_ret_t main_menu_handle_events(uint16_t event, void *data)
297 {
298         switch (event) {
299                 case EVENT_SCREEN_VISIBLE:
300                         main_menu_screen.tmo = 0;
301                         main_menu_screen.pos = 2;
302                         draw_main_menu_screen(&main_menu_screen);
303                         return EVENT_RET_HANDLED;
304                         break;
305                 case EVENT_USER_BUTTONS:
306                         dbg_out("button event %d\n", *(int *)data);
307                         main_menu_screen.tmo = 0;
308                         return handle_main_menu_buttons(*(watch_button *)data, &main_menu_screen);
309                         break;
310                 case EVENT_ONE_SEC_TIMER:
311                         main_menu_screen.tmo++;
312                         if (main_menu_screen.tmo > MAIN_MENU_TIMEOUT) {
313                                 OswaldState.screen_id = IDLE_SCREEN;
314                                 OswaldState.screen = &OswaldScreens[OswaldState.screen_id];
315                                 OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL);
316                         }
317                         return EVENT_RET_HANDLED;
318                 default:
319                         break;
320         };
321         return EVENT_RET_UNHANDLED;
322 }
323
324
325 /*
326  * Accelerometer and sensor display screen
327  */
328 typedef struct {
329         accel_data_t accdata;
330 } accelscreen_data_t;
331 static accelscreen_data_t accel_screen = {
332         { 0, 0, 0},
333 };
334
335 void draw_accel_screen(accel_data_t *accel_data)
336 {
337         uint8_t x,y;
338
339         hal_lcd_clear_display();
340
341         oswald_draw_bitmap(36, 0, acc_icon_width, acc_icon_height, acc_icon_bits);
342
343         oswald_draw_bitmap(81, 79, enterbutton_icon_width, enterbutton_icon_height, enterbutton_icon_bits);
344
345         oswald_write_string(1, 40, FONT_6x9, FALSE, "X:");
346         oswald_write_number(15, 40, FONT_6x9, FALSE, accel_data->x);
347         oswald_write_string(1, 52, FONT_6x9, FALSE, "Y:");
348         oswald_write_number(15, 52, FONT_6x9, FALSE, accel_data->y);
349         oswald_write_string(1, 64, FONT_6x9, FALSE, "Z:");
350         oswald_write_number(15, 64, FONT_6x9, FALSE, accel_data->z);
351
352         oswald_write_string(1, 85, FONT_6x9, FALSE, "Light:");
353         oswald_write_number(50, 85, FONT_6x9, FALSE, 0);
354
355         oswald_draw_line(40, 30, 92, 30);
356         oswald_draw_line(92, 30, 92, 82);
357         oswald_draw_line(40, 82, 92, 82);
358         oswald_draw_line(40, 82, 40, 30);
359
360         x = 41+25+((accel_data->x * 50) / (254));
361         y = 31+25-((accel_data->y * 50) / (254));
362         oswald_draw_pixel(x, y, TRUE);
363         oswald_draw_pixel(x+1, y, TRUE);
364         oswald_draw_pixel(x-1, y, TRUE);
365         oswald_draw_pixel(x, y+1, TRUE);
366         oswald_draw_pixel(x, y-1, TRUE);
367
368         hal_lcd_update_display();
369 }
370
371 event_ret_t accel_handle_events(uint16_t event, void *data)
372 {
373         switch (event) {
374                 case EVENT_SCREEN_VISIBLE:
375                         draw_accel_screen(&accel_screen.accdata);
376                         hal_accelerometer_enable();
377                         return EVENT_RET_HANDLED;
378                         break;
379                 case EVENT_SCREEN_DESTROY:
380                         hal_accelerometer_disable();
381                         return EVENT_RET_HANDLED;
382                         break;
383                 case EVENT_ACCEL_UPDATE: {
384                         accel_data_t *accel_data = (accel_data_t *)data;
385                         accel_screen.accdata.x = accel_data->x;
386                         accel_screen.accdata.y = accel_data->y;
387                         accel_screen.accdata.z = accel_data->z;
388                         draw_accel_screen(&accel_screen.accdata);
389                         };
390                         return EVENT_RET_HANDLED;
391                         break;
392                 case EVENT_USER_BUTTONS:
393                         dbg_out("button event %d\n", *(int *)data);
394                         break;
395                 default:
396                         return EVENT_RET_UNHANDLED;
397                         break;
398         };
399         return EVENT_RET_UNHANDLED;
400 }
401
402
403 /*
404  * Date / time setup screen
405  */
406 typedef struct {
407         uint8_t pos;
408         boolean set_mode;
409         boolean on;
410 } datetime_setup_data_t;
411 static datetime_setup_data_t dt_setup_screen = {
412         0,
413         FALSE,
414         TRUE
415 };
416
417 void draw_datetime_setup_screen(datetime_setup_data_t *sdata)
418 {
419         hal_lcd_clear_display();
420
421         oswald_draw_bitmap(36, 0, timesetup_icon_width, timesetup_icon_height, timesetup_icon_bits);
422
423         oswald_draw_bitmap(81, 6, upbutton_icon_width, upbutton_icon_height, upbutton_icon_bits);
424         oswald_draw_bitmap(81, 38, downbutton_icon_width, downbutton_icon_height, downbutton_icon_bits);
425         oswald_draw_bitmap(81, 70, rightbutton_icon_width, rightbutton_icon_height, rightbutton_icon_bits);
426
427         if ((sdata->pos == 0 && sdata->on) || sdata->pos != 0) {
428                 oswald_write_character(2, 30, FONT_LCD13x21, FALSE, (OswaldClk.hour / 10));
429                 oswald_write_character(15, 30, FONT_LCD13x21, FALSE, (OswaldClk.hour % 10));
430         }
431         oswald_write_character(25, 30, FONT_LCD13x21, FALSE, 10);
432
433         if ((sdata->pos == 1 && sdata->on) || sdata->pos != 1) {
434                 oswald_write_character(34, 30, FONT_LCD13x21, FALSE, (OswaldClk.minute / 10));
435                 oswald_write_character(47, 30, FONT_LCD13x21, FALSE, (OswaldClk.minute % 10));
436         }
437
438         if ((sdata->pos == 2 && sdata->on) || sdata->pos != 2) {
439                 oswald_write_character(61, 38, FONT_LCD8x13, FALSE, (OswaldClk.second / 10));
440                 oswald_write_character(69, 38, FONT_LCD8x13, FALSE, (OswaldClk.second % 10));
441         }
442
443
444         if ((sdata->pos == 3 && sdata->on) || sdata->pos != 3) {
445                 oswald_write_number(2, 55, FONT_DROID8x12, FALSE, OswaldClk.day);
446         }
447         oswald_write_character(15, 55, FONT_DROID8x12, FALSE, '.');
448         if ((sdata->pos == 4 && sdata->on) || sdata->pos != 4) {
449                 oswald_write_number(21, 55, FONT_DROID8x12, FALSE, OswaldClk.month);
450         }
451         oswald_write_character(36, 55, FONT_DROID8x12, FALSE, '.');
452         if ((sdata->pos == 5 && sdata->on) || sdata->pos != 5) {
453                 oswald_write_number(43, 55, FONT_DROID8x12, FALSE, OswaldClk.year);
454         }
455
456         if ((sdata->pos == 6 && sdata->on) || sdata->pos != 6) {
457                 if (OswaldClk.clk24hr) {
458                         oswald_draw_bitmap(2, 76, checked_icon_width, checked_icon_height, checked_icon_bits);
459                 } else {
460                         oswald_draw_bitmap(2, 76, unchecked_icon_width, unchecked_icon_height, unchecked_icon_bits);
461                 }
462         }
463         oswald_write_string(15, 73, FONT_DROID8x12, FALSE, "24hr");
464
465         if ((sdata->pos == 7 && sdata->on) || sdata->pos != 7) {
466                 if (OswaldClk.day_first) {
467                         oswald_draw_bitmap(2, 86, checked_icon_width, checked_icon_height, checked_icon_bits);
468                 } else {
469                         oswald_draw_bitmap(2, 86, unchecked_icon_width, unchecked_icon_height, unchecked_icon_bits);
470                 }
471         }
472         oswald_write_string(15, 83, FONT_DROID8x12, FALSE, "dd.mm.  mm/dd");
473
474         hal_lcd_update_display();
475 }
476
477 void datetime_handle_updown(uint8_t pos, int8_t incr)
478 {
479         switch (pos) {
480                 case 0: // hour
481                         if (OswaldClk.hour == 0 && incr == -1) {
482                                 OswaldClk.hour = 23;
483                                 break;
484                         };
485                         OswaldClk.hour += incr;
486                         if (OswaldClk.hour > 23)
487                                 OswaldClk.hour = 0;
488                         break;
489                 case 1: // minute
490                         if (OswaldClk.minute == 0 && incr == -1) {
491                                 OswaldClk.minute = 59;
492                                 break;
493                         };
494                         OswaldClk.minute += incr;
495                         if (OswaldClk.minute > 59)
496                                 OswaldClk.minute = 0;
497                         break;
498                 case 2: // second
499                         OswaldClk.second = 0;
500                         break;
501                 case 3: // day
502                         if (OswaldClk.day == 1 && incr == -1) {
503                                 OswaldClk.day = 31;
504                                 break;
505                         };
506                         OswaldClk.day += incr;
507                         if (OswaldClk.day > 31)
508                                 OswaldClk.day = 1;
509                         break;
510                 case 4: // month
511                         if (OswaldClk.month == 1 && incr == -1) {
512                                 OswaldClk.month = 12;
513                                 break;
514                         };
515                         OswaldClk.month += incr;
516                         if (OswaldClk.month > 12)
517                                 OswaldClk.month = 1;
518                         break;
519                 case 5: // year
520                         OswaldClk.year += incr;
521                         break;
522                 case 6: // 24hr / 12hr
523                         if (OswaldClk.clk24hr)
524                                 OswaldClk.clk24hr = FALSE;
525                         else
526                                 OswaldClk.clk24hr = TRUE;
527                         break;
528                 case 7: // dd.mm. / mm/dd
529                         if (OswaldClk.day_first)
530                                 OswaldClk.day_first = FALSE;
531                         else
532                                 OswaldClk.day_first = TRUE;
533                         break;
534                 default:
535                         break;
536         };
537         if (pos == 2)
538                 hal_set_rtc(&OswaldClk, TRUE);
539         else
540                 hal_set_rtc(&OswaldClk, FALSE);
541 }
542
543 event_ret_t handle_setup_datetime_buttons(watch_button button, datetime_setup_data_t *sdata)
544 {
545         switch (button) {
546                 case BUTTON_A:
547                         datetime_handle_updown(sdata->pos, 1);
548                         break;
549                 case BUTTON_B:
550                         datetime_handle_updown(sdata->pos, -1);
551                         break;
552                 case BUTTON_C:
553                         sdata->pos++;
554                         sdata->pos %= 8;
555                         break;
556                 case BUTTON_F:
557                         OswaldState.screen->event_func(EVENT_SCREEN_DESTROY, NULL);
558                         OswaldState.screen_id = IDLE_SCREEN;
559                         OswaldState.screen = &OswaldScreens[OswaldState.screen_id];
560                         OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL);
561                         return EVENT_RET_HANDLED;
562                         break;
563                 default:
564                         return EVENT_RET_UNHANDLED;
565                         break;
566         }
567         draw_datetime_setup_screen(sdata);
568         return EVENT_RET_HANDLED;
569 }
570
571 event_ret_t datetime_setup_events(uint16_t event, void *data)
572 {
573         switch (event) {
574                 case EVENT_SCREEN_VISIBLE:
575                         dt_setup_screen.pos = 0;
576                         draw_datetime_setup_screen(&dt_setup_screen);
577                         hal_enable_halfsecond_timer();
578                         return EVENT_RET_HANDLED;
579                         break;
580                 case EVENT_SCREEN_DESTROY:
581                         hal_disable_halfsecond_timer();
582                         return EVENT_RET_HANDLED;
583                         break;
584                 case EVENT_USER_BUTTONS:
585                         dbg_out("button event %d\n", *(int *)data);
586                         return handle_setup_datetime_buttons(*(watch_button *)data, &dt_setup_screen);
587                         break;
588                 case EVENT_HALF_SEC_TIMER:
589                         if (dt_setup_screen.on)
590                                 dt_setup_screen.on = FALSE;
591                         else
592                                 dt_setup_screen.on = TRUE;
593                         draw_datetime_setup_screen(&dt_setup_screen);
594                         return EVENT_RET_HANDLED;
595                         break;
596                 default:
597                         return EVENT_RET_UNHANDLED;
598                         break;
599         };
600         return EVENT_RET_UNHANDLED;
601 }
602
603
604 /*
605  * Alarm setup screen
606  */
607 typedef struct {
608         uint8_t pos;
609         boolean set_mode;
610         boolean on;
611 } alarm_setup_data_t;
612 static alarm_setup_data_t alarm_setup_screen = {
613         0,
614         FALSE,
615         TRUE
616 };
617
618 void draw_alarm_setup_screen(alarm_setup_data_t *sdata)
619 {
620         hal_lcd_clear_display();
621
622         oswald_draw_bitmap(36, 0, alarm_icon_width, alarm_icon_height, alarm_icon_bits);
623
624         if (sdata->set_mode) {
625                 oswald_draw_bitmap(81, 6, upbutton_icon_width, upbutton_icon_height, upbutton_icon_bits);
626                 oswald_draw_bitmap(81, 38, downbutton_icon_width, downbutton_icon_height, downbutton_icon_bits);
627                 oswald_draw_bitmap(81, 70, rightbutton_icon_width, rightbutton_icon_height, rightbutton_icon_bits);
628         } else {
629                 oswald_draw_bitmap(81, 70, enterbutton_icon_width, enterbutton_icon_height, enterbutton_icon_bits);
630         }
631
632         if ((sdata->pos == 0 && sdata->on) || sdata->pos != 0) {
633                 oswald_write_character(18, 30, FONT_LCD13x21, FALSE, (OswaldAlarm.hour / 10));
634                 oswald_write_character(32, 30, FONT_LCD13x21, FALSE, (OswaldAlarm.hour % 10));
635         }
636         oswald_write_character(42, 30, FONT_LCD13x21, FALSE, 10);
637
638         if ((sdata->pos == 1 && sdata->on) || sdata->pos != 1) {
639                 oswald_write_character(53, 30, FONT_LCD13x21, FALSE, (OswaldAlarm.minute / 10));
640                 oswald_write_character(67, 30, FONT_LCD13x21, FALSE, (OswaldAlarm.minute % 10));
641         }
642
643         oswald_write_character(3, 55, FONT_6x9, FALSE, 'S');
644         oswald_write_character(15, 55, FONT_6x9, FALSE, 'M');
645         oswald_write_character(27, 55, FONT_6x9, FALSE, 'T');
646         oswald_write_character(39, 55, FONT_6x9, FALSE, 'W');
647         oswald_write_character(51, 55, FONT_6x9, FALSE, 'T');
648         oswald_write_character(63, 55, FONT_6x9, FALSE, 'F');
649         oswald_write_character(75, 55, FONT_6x9, FALSE, 'S');
650
651         if ((sdata->pos == 2 && sdata->on) || sdata->pos != 2) {
652                 // oswald_write_character(3, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_SUNDAY) ? 'x' : '_');
653                 if ((OswaldAlarm.wday & WDAY_SUNDAY))
654                         oswald_draw_bitmap(3, 66, checked_icon_width, checked_icon_height, checked_icon_bits);
655                 else
656                         oswald_draw_bitmap(3, 66, unchecked_icon_width, unchecked_icon_height, unchecked_icon_bits);
657         }
658         if ((sdata->pos == 3 && sdata->on) || sdata->pos != 3) {
659                 // oswald_write_character(15, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_MONDAY) ? 'x' : '_');
660                 if ((OswaldAlarm.wday & WDAY_MONDAY))
661                         oswald_draw_bitmap(15, 66, checked_icon_width, checked_icon_height, checked_icon_bits);
662                 else
663                         oswald_draw_bitmap(15, 66, unchecked_icon_width, unchecked_icon_height, unchecked_icon_bits);
664         }
665         if ((sdata->pos == 4 && sdata->on) || sdata->pos != 4) {
666                 // oswald_write_character(27, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_TUESDAY) ? 'x' : '_');
667                 if ((OswaldAlarm.wday & WDAY_TUESDAY))
668                         oswald_draw_bitmap(27, 66, checked_icon_width, checked_icon_height, checked_icon_bits);
669                 else
670                         oswald_draw_bitmap(27, 66, unchecked_icon_width, unchecked_icon_height, unchecked_icon_bits);
671         }
672         if ((sdata->pos == 5 && sdata->on) || sdata->pos != 5) {
673                 // oswald_write_character(39, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_WEDNESDAY) ? 'x' : '_');
674                 if ((OswaldAlarm.wday & WDAY_WEDNESDAY))
675                         oswald_draw_bitmap(39, 66, checked_icon_width, checked_icon_height, checked_icon_bits);
676                 else
677                         oswald_draw_bitmap(39, 66, unchecked_icon_width, unchecked_icon_height, unchecked_icon_bits);
678         }
679         if ((sdata->pos == 6 && sdata->on) || sdata->pos != 6) {
680                 // oswald_write_character(51, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_THURSDAY) ? 'x' : '_');
681                 if ((OswaldAlarm.wday & WDAY_THURSDAY))
682                         oswald_draw_bitmap(51, 66, checked_icon_width, checked_icon_height, checked_icon_bits);
683                 else
684                         oswald_draw_bitmap(51, 66, unchecked_icon_width, unchecked_icon_height, unchecked_icon_bits);
685         }
686         if ((sdata->pos == 7 && sdata->on) || sdata->pos != 7) {
687                 // oswald_write_character(63, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_FRIDAY) ? 'x' : '_');
688                 if ((OswaldAlarm.wday & WDAY_FRIDAY))
689                         oswald_draw_bitmap(63, 66, checked_icon_width, checked_icon_height, checked_icon_bits);
690                 else
691                         oswald_draw_bitmap(63, 66, unchecked_icon_width, unchecked_icon_height, unchecked_icon_bits);
692         }
693         if ((sdata->pos == 8 && sdata->on) || sdata->pos != 8) {
694                 // oswald_write_character(75, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_SATURDAY) ? 'x' : '_');
695                 if ((OswaldAlarm.wday & WDAY_SATURDAY))
696                         oswald_draw_bitmap(75, 66, checked_icon_width, checked_icon_height, checked_icon_bits);
697                 else
698                         oswald_draw_bitmap(75, 66, unchecked_icon_width, unchecked_icon_height, unchecked_icon_bits);
699         }
700
701         hal_lcd_update_display();
702 }
703
704 void alarm_handle_updown(uint8_t pos, int8_t incr)
705 {
706         switch (pos) {
707                 case 0: // hour
708                         if (OswaldAlarm.hour == 0 && incr == -1) {
709                                 OswaldAlarm.hour = 23;
710                                 break;
711                         };
712                         OswaldAlarm.hour += incr;
713                         if (OswaldAlarm.hour > 23)
714                                 OswaldAlarm.hour = 0;
715                         break;
716                 case 1: // minute
717                         if (OswaldAlarm.minute == 0 && incr == -1) {
718                                 OswaldAlarm.minute = 59;
719                                 break;
720                         };
721                         OswaldAlarm.minute += incr;
722                         if (OswaldAlarm.minute > 59)
723                                 OswaldAlarm.minute = 0;
724                         break;
725                 case 2: // sunday
726                         OswaldAlarm.wday ^= WDAY_SUNDAY;
727                         break;
728                 case 3: // monday
729                         OswaldAlarm.wday ^= WDAY_MONDAY;
730                         break;
731                 case 4: // tuesday
732                         OswaldAlarm.wday ^= WDAY_TUESDAY;
733                         break;
734                 case 5: // wednesday
735                         OswaldAlarm.wday ^= WDAY_WEDNESDAY;
736                         break;
737                 case 6: // thursday
738                         OswaldAlarm.wday ^= WDAY_THURSDAY;
739                         break;
740                 case 7: // friday
741                         OswaldAlarm.wday ^= WDAY_FRIDAY;
742                         break;
743                 case 8: // saturday
744                         OswaldAlarm.wday ^= WDAY_SATURDAY;
745                         break;
746                 default:
747                         break;
748         };
749 }
750
751 event_ret_t handle_setup_alarm_buttons(watch_button button, alarm_setup_data_t *sdata)
752 {
753         if (alarm_setup_screen.set_mode) {
754                 switch (button) {
755                         case BUTTON_A:
756                                 alarm_handle_updown(sdata->pos, 1);
757                                 break;
758                         case BUTTON_B:
759                                 alarm_handle_updown(sdata->pos, -1);
760                                 break;
761                         case BUTTON_C:
762                                 sdata->pos++;
763                                 sdata->pos %= 9;
764                                 break;
765                         case BUTTON_F:
766                                 alarm_setup_screen.set_mode = FALSE;
767                                 break;
768                         default:
769                                 return EVENT_RET_UNHANDLED;
770                                 break;
771                 }
772         } else {
773                 switch (button) {
774                         case BUTTON_F:
775                                 alarm_setup_screen.set_mode = TRUE;
776                                 break;
777                         default:
778                                 return EVENT_RET_UNHANDLED;
779                                 break;
780                 }
781         }
782         draw_alarm_setup_screen(sdata);
783
784         return EVENT_RET_HANDLED;
785 }
786
787 event_ret_t alarm_setup_events(uint16_t event, void *data)
788 {
789         switch (event) {
790                 case EVENT_SCREEN_VISIBLE:
791                         alarm_setup_screen.pos = 0;
792                         alarm_setup_screen.on = TRUE;
793                         alarm_setup_screen.set_mode = FALSE;
794                         draw_alarm_setup_screen(&alarm_setup_screen);
795                         hal_enable_halfsecond_timer();
796                         return EVENT_RET_HANDLED;
797                         break;
798                 case EVENT_SCREEN_DESTROY:
799                         hal_disable_halfsecond_timer();
800                         return EVENT_RET_HANDLED;
801                         break;
802                 case EVENT_USER_BUTTONS:
803                         dbg_out("button event %d\n", *(int *)data);
804                         return handle_setup_alarm_buttons(*(watch_button *)data, &alarm_setup_screen);
805                         break;
806                 case EVENT_HALF_SEC_TIMER:
807                         if (alarm_setup_screen.set_mode) {
808                                 if (alarm_setup_screen.on)
809                                         alarm_setup_screen.on = FALSE;
810                                 else
811                                         alarm_setup_screen.on = TRUE;
812                         } else
813                                 alarm_setup_screen.on = TRUE;
814                         draw_alarm_setup_screen(&alarm_setup_screen);
815                         return EVENT_RET_HANDLED;
816                         break;
817                 default:
818                         return EVENT_RET_UNHANDLED;
819                         break;
820         };
821         return EVENT_RET_UNHANDLED;
822 }
823
824
825 /*
826  * Test menu
827  */
828 typedef struct {
829         uint8_t menu_pos;
830 } test_menu_t;
831 static test_menu_t test_menu = { 0 };
832
833 void draw_menu_test_screen(void)
834 {
835         hal_lcd_clear_display();
836 #if 0
837         SetFont(MetaWatch16);
838         WriteLcdString(2, 2, "Menu");
839         SetFont(MetaWatch7);
840         WriteLcdString(2, 20, "Item 1");
841         WriteLcdString(2, 29, "Item 2");
842         WriteLcdString(2, 38, "Item 3");
843         WriteLcdString(2, 47, "Item 4");
844         WriteLcdString(2, 56, "Item 5");
845
846         WriteLcdString(50, 20+(9*test_menu.menu_pos), "*");
847 #endif
848         oswald_write_string(2, 2, FONT_DROID8x12, FALSE, "Menu");
849
850         oswald_write_string(2, 20, FONT_DROID8x12, FALSE, "Item 1");
851         oswald_write_string(2, 29, FONT_DROID8x12, FALSE, "Item 2");
852         oswald_write_string(2, 38, FONT_DROID8x12, FALSE, "Item 3");
853         oswald_write_string(2, 47, FONT_DROID8x12, FALSE, "Item 4");
854         oswald_write_string(2, 56, FONT_DROID8x12, FALSE, "Item 5");
855
856         oswald_write_character(50, 18+(9*test_menu.menu_pos), FONT_6x9, FALSE, 0x11);
857
858         hal_lcd_update_display();
859 }
860
861 event_ret_t handle_menu_user_buttons(watch_button button)
862 {
863         switch (button) {
864                 case BUTTON_A:
865                         test_menu.menu_pos--;
866                         test_menu.menu_pos %= 5;
867                         break;
868                 case BUTTON_B:
869                         test_menu.menu_pos++;
870                         test_menu.menu_pos %= 5;
871                         break;
872                 default:
873                         return EVENT_RET_UNHANDLED;
874                         break;
875         }
876         draw_menu_test_screen();
877         return EVENT_RET_HANDLED;
878 }
879
880 event_ret_t test_menu_handle_events(uint16_t event, void *data)
881 {
882         switch (event) {
883                 case EVENT_USER_BUTTONS:
884                         dbg_out("button event %d\n", *(int *)data);
885                         return handle_menu_user_buttons(*(watch_button *)data);
886                         break;
887                 case EVENT_SCREEN_VISIBLE:
888                         test_menu.menu_pos = 0;
889                         draw_menu_test_screen();
890                         break;
891                 default:
892                         return EVENT_RET_UNHANDLED;
893                         break;
894         };
895         return EVENT_RET_HANDLED;
896 }
897
898
899 /*
900  * Stop Watch
901  */
902 typedef struct {
903         uint8_t hr;
904         uint8_t min;
905         uint8_t sec;
906         uint8_t csec;
907         uint8_t lapse_hr;
908         uint8_t lapse_min;
909         uint8_t lapse_sec;
910         uint8_t lapse_csec;
911         boolean running;
912 } stopwatch_data_t;
913 static stopwatch_data_t stopwatch_screen = { 0, 0, 0, 0, 0, 0, 0, 0, FALSE };
914
915
916 static void draw_stop_watch_screen(stopwatch_data_t *sdata)
917 {
918         int gRow = 1;
919         int gColumn = 35;
920
921         hal_lcd_clear_display();
922
923         oswald_draw_bitmap(36, 0, stopwatch_icon_width, stopwatch_icon_height, stopwatch_icon_bits);
924
925         oswald_draw_bitmap(81, 6, startstopbutton_icon_width, startstopbutton_icon_height, startstopbutton_icon_bits);
926         oswald_draw_bitmap(81, 38, lapsebutton_icon_width, lapsebutton_icon_height, lapsebutton_icon_bits);
927         oswald_draw_bitmap(81, 70, enterbutton_icon_width, enterbutton_icon_height, enterbutton_icon_bits);
928
929         gRow += 3 + oswald_write_character(gRow, gColumn, FONT_LCD13x21, FALSE, (sdata->hr % 10));
930         gRow += oswald_write_character(gRow, gColumn, FONT_LCD13x21, FALSE, (sdata->min / 10));
931         gRow += 3 + oswald_write_character(gRow, gColumn, FONT_LCD13x21, FALSE, (sdata->min % 10));
932         gRow += oswald_write_character(gRow, gColumn, FONT_LCD13x21, FALSE, (sdata->sec / 10));
933         gRow += 3 + oswald_write_character(gRow, gColumn, FONT_LCD13x21, FALSE, (sdata->sec % 10));
934         gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, FALSE, (sdata->csec / 10));
935
936         gRow = 6;
937         gColumn = 61;
938         gRow += 13 + oswald_write_character(gRow, gColumn, FONT_LCD8x13, FALSE, (sdata->lapse_hr % 10));
939         gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, FALSE, (sdata->lapse_min / 10));
940         gRow += 13 + oswald_write_character(gRow, gColumn, FONT_LCD8x13, FALSE, (sdata->lapse_min % 10));
941         gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, FALSE, (sdata->lapse_sec / 10));
942         gRow += 3 + oswald_write_character(gRow, gColumn, FONT_LCD8x13, FALSE, (sdata->lapse_sec % 10));
943         gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, FALSE, (sdata->lapse_csec / 10));
944         gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, FALSE, (sdata->lapse_csec % 10));
945
946         hal_lcd_update_display();
947 }
948
949 event_ret_t handle_stop_watch_buttons(watch_button button)
950 {
951         switch (button) {
952                 case BUTTON_A: // start/stop
953                         if (stopwatch_screen.running) {
954                                 hal_disable_centisecond_timer();
955                                 stopwatch_screen.running = FALSE;
956                         } else {
957                                 hal_enable_centisecond_timer();
958                                 stopwatch_screen.running = TRUE;
959                         }
960                         return EVENT_RET_HANDLED;
961                         break;
962                 case BUTTON_B: // lapse
963                         stopwatch_screen.lapse_hr = stopwatch_screen.hr;
964                         stopwatch_screen.lapse_min = stopwatch_screen.min;
965                         stopwatch_screen.lapse_sec = stopwatch_screen.sec;
966                         stopwatch_screen.lapse_csec = stopwatch_screen.csec;
967                         return EVENT_RET_HANDLED;
968                         break;
969                 case BUTTON_F: // reset
970                         stopwatch_screen.hr = 0;
971                         stopwatch_screen.min = 0;
972                         stopwatch_screen.sec = 0;
973                         stopwatch_screen.csec = 0;
974                         stopwatch_screen.lapse_hr = 0;
975                         stopwatch_screen.lapse_min = 0;
976                         stopwatch_screen.lapse_sec = 0;
977                         stopwatch_screen.lapse_csec = 0;
978                         return EVENT_RET_HANDLED;
979                         break;
980                 default:
981                         return EVENT_RET_UNHANDLED;
982                         break;
983         }
984         return EVENT_RET_UNHANDLED;
985 }
986
987 event_ret_t stop_watch_handle_events(uint16_t event, void *data)
988 {
989         switch (event) {
990                 case EVENT_USER_BUTTONS:
991                         dbg_out("button event %d\n", *(int *)data);
992                         draw_stop_watch_screen(&stopwatch_screen);
993                         return handle_stop_watch_buttons(*(watch_button *)data);
994                         break;
995                 case EVENT_SCREEN_VISIBLE:
996                         draw_stop_watch_screen(&stopwatch_screen);
997                         return EVENT_RET_HANDLED;
998                         break;
999                 case EVENT_SCREEN_DESTROY:
1000                         hal_disable_centisecond_timer();
1001                         stopwatch_screen.running = FALSE;
1002                         return EVENT_RET_HANDLED;
1003                         break;
1004                 case EVENT_CS_TIMER:
1005                         stopwatch_screen.csec++;
1006                         if (stopwatch_screen.csec > 99) {
1007                                 stopwatch_screen.csec = 0;
1008                                 stopwatch_screen.sec++;
1009                         };
1010                         if (stopwatch_screen.sec > 59) {
1011                                 stopwatch_screen.sec = 0;
1012                                 stopwatch_screen.min++;
1013                         };
1014                         if (stopwatch_screen.min > 59) {
1015                                 stopwatch_screen.min = 0;
1016                                 stopwatch_screen.hr++;
1017                         };
1018                         if (stopwatch_screen.hr > 59) {
1019                                 stopwatch_screen.hr = 0;
1020                         };
1021                         if (stopwatch_screen.csec % 10 == 0)
1022                                 draw_stop_watch_screen(&stopwatch_screen);
1023                                 //update_stop_watch_screen(&stopwatch_screen);
1024                         return EVENT_RET_HANDLED;
1025                         break;
1026                 default:
1027                         return EVENT_RET_UNHANDLED;
1028                         break;
1029         };
1030         return EVENT_RET_HANDLED;
1031 }
1032
1033
1034 /*
1035  * Alarm screen, shown when alarm is fired
1036  */
1037 void draw_alarm_screen(void)
1038 {
1039         hal_lcd_clear_display();
1040
1041         oswald_draw_bitmap(36, 20, alarm_icon_width, alarm_icon_height, alarm_icon_bits);
1042
1043         oswald_draw_bitmap(81, 70, enterbutton_icon_width, enterbutton_icon_height, enterbutton_icon_bits);
1044
1045         hal_lcd_update_display();
1046 }
1047
1048 event_ret_t alarm_handle_events(uint16_t event, void *data)
1049 {
1050         switch (event) {
1051                 case EVENT_SCREEN_VISIBLE:
1052                         draw_alarm_screen();
1053                         hal_enable_halfsecond_timer();
1054                         hal_vibration_set_state(TRUE);
1055                         return EVENT_RET_HANDLED;
1056                         break;
1057                 case EVENT_SCREEN_DESTROY:
1058                         hal_disable_halfsecond_timer();
1059                         hal_lcd_set_backlight(FALSE);
1060                         hal_vibration_set_state(FALSE);
1061                         return EVENT_RET_HANDLED;
1062                         break;
1063                 case EVENT_USER_BUTTONS:
1064                         dbg_out("button event %d\n", *(int *)data);
1065                         return EVENT_RET_UNHANDLED;
1066                         break;
1067                 case EVENT_HALF_SEC_TIMER:
1068                         hal_lcd_set_backlight(!hal_lcd_get_backlight());
1069                         hal_vibration_set_state(!hal_vibration_get_state());
1070                         dbg_out("timer\n");
1071                         return EVENT_RET_HANDLED;
1072                         break;
1073                 default:
1074                         return EVENT_RET_UNHANDLED;
1075                         break;
1076         };
1077         return EVENT_RET_HANDLED;
1078 }
1079
1080
1081 /*
1082  * Bluetooth setup screen
1083  */
1084 typedef struct {
1085         uint8_t pos;
1086         boolean bt_en;
1087         boolean set_mode;
1088         boolean on;
1089 } bluetooth_data_t;
1090 static bluetooth_data_t bluetooth_screen = {
1091         0,
1092         FALSE,
1093         FALSE,
1094         TRUE
1095 };
1096
1097 void draw_bluetooth_screen(bluetooth_data_t *sdata)
1098 {
1099         char bstr[20];
1100         uint8_t *bd_addr;
1101
1102         hal_lcd_clear_display();
1103
1104         oswald_draw_bitmap(36, 0, Bluetooth_icon_width, Bluetooth_icon_height, Bluetooth_icon_bits);
1105
1106         if (sdata->set_mode) {
1107                 oswald_draw_bitmap(81, 6, upbutton_icon_width, upbutton_icon_height, upbutton_icon_bits);
1108                 oswald_draw_bitmap(81, 38, downbutton_icon_width, downbutton_icon_height, downbutton_icon_bits);
1109                 oswald_draw_bitmap(81, 70, rightbutton_icon_width, rightbutton_icon_height, rightbutton_icon_bits);
1110         } else {
1111                 oswald_draw_bitmap(81, 70, enterbutton_icon_width, enterbutton_icon_height, enterbutton_icon_bits);
1112         }
1113
1114         oswald_write_string(1, 30, FONT_DROID8x12, FALSE, "Enable:");
1115         if ((sdata->pos == 0 && sdata->on) || sdata->pos != 0) {
1116                 if (bluetooth_screen.bt_en)
1117                         oswald_draw_bitmap(53, 33, checked_icon_width, checked_icon_height, checked_icon_bits);
1118                 else
1119                         oswald_draw_bitmap(53, 33, unchecked_icon_width, unchecked_icon_height, unchecked_icon_bits);
1120         }
1121         oswald_write_string(1, 40, FONT_DROID8x12, FALSE, "State:");
1122         switch (hal_bluetooth_get_state()) {
1123                 case BLUETOOTH_OFF:
1124                         oswald_write_string(53, 40, FONT_DROID8x12, FALSE, "off");
1125                         break;
1126                 case BLUETOOTH_ON:
1127                         oswald_write_string(53, 40, FONT_DROID8x12, FALSE, "on");
1128                         break;
1129                 case BLUETOOTH_CONNECTED:
1130                         oswald_write_string(53, 40, FONT_DROID8x12, FALSE, "conn.");
1131                         break;
1132                 default:
1133                         break;
1134         };
1135         oswald_write_string(1, 50, FONT_DROID8x12, FALSE, "Visible:");
1136         if ((sdata->pos == 1 && sdata->on) || sdata->pos != 1) {
1137                 // oswald_write_character(53, 50, FONT_DROID8x12, hal_bluetooth_get_visible() ? 'x' : '_');
1138                 if (hal_bluetooth_get_visible())
1139                         oswald_draw_bitmap(53, 53, checked_icon_width, checked_icon_height, checked_icon_bits);
1140                 else
1141                         oswald_draw_bitmap(53, 53, unchecked_icon_width, unchecked_icon_height, unchecked_icon_bits);
1142         }
1143
1144         if (hal_bluetooth_get_state() >= BLUETOOTH_ON) {
1145                 bd_addr = hal_bluetooth_get_local_bdaddr();
1146                 snprintf(bstr, 20, "%02x:%02x:%02x:%02x:%02x:%02x", bd_addr[5], bd_addr[4], bd_addr[3], bd_addr[2], bd_addr[1], bd_addr[0]);
1147                 oswald_write_string(2, 85, FONT_5x7, FALSE, bstr);
1148         } else {
1149         }
1150
1151         hal_lcd_update_display();
1152 }
1153
1154 void bluetooth_handle_updown(uint8_t pos, int8_t incr)
1155 {
1156         switch (pos) {
1157                 case 0:
1158                         if (hal_bluetooth_get_state() >= BLUETOOTH_ON) {
1159                                 hal_bluetooth_set_state(BLUETOOTH_OFF);
1160                                 bluetooth_screen.bt_en = FALSE;
1161                         } else {
1162                                 hal_bluetooth_set_state(BLUETOOTH_ON);
1163                                 bluetooth_screen.bt_en = TRUE;
1164                         }
1165                         break;
1166                 case 1:
1167                         if (hal_bluetooth_get_state() >= BLUETOOTH_ON && !hal_bluetooth_get_visible()) {
1168                                 hal_bluetooth_set_visible(TRUE);
1169                         } else {
1170                                 hal_bluetooth_set_visible(FALSE);
1171                         }
1172                         break;
1173                 default:
1174                         break;
1175         };
1176 }
1177
1178 event_ret_t handle_bluetooth_buttons(watch_button button, bluetooth_data_t *sdata)
1179 {
1180         if (bluetooth_screen.set_mode) {
1181                 switch (button) {
1182                         case BUTTON_A:
1183                                 bluetooth_handle_updown(sdata->pos, 1);
1184                                 break;
1185                         case BUTTON_B:
1186                                 bluetooth_handle_updown(sdata->pos, -1);
1187                                 break;
1188                         case BUTTON_C:
1189                                 sdata->pos++;
1190                                 sdata->pos %= 2;
1191                                 break;
1192                         case BUTTON_F:
1193                                 bluetooth_screen.set_mode = FALSE;
1194                                 break;
1195                         default:
1196                                 return EVENT_RET_UNHANDLED;
1197                                 break;
1198                 }
1199         } else {
1200                 switch (button) {
1201                         case BUTTON_F:
1202                                 bluetooth_screen.set_mode = TRUE;
1203                                 break;
1204                         default:
1205                                 return EVENT_RET_UNHANDLED;
1206                                 break;
1207                 }
1208         }
1209
1210         draw_bluetooth_screen(sdata);
1211
1212         return EVENT_RET_HANDLED;
1213 }
1214
1215 event_ret_t bluetooth_screen_events(uint16_t event, void *data)
1216 {
1217         switch (event) {
1218                 case EVENT_SCREEN_VISIBLE:
1219                         bluetooth_screen.pos = 0;
1220                         bluetooth_screen.bt_en = (hal_bluetooth_get_state() > 0);
1221                         draw_bluetooth_screen(&bluetooth_screen);
1222                         hal_enable_halfsecond_timer();
1223                         break;
1224                 case EVENT_SCREEN_DESTROY:
1225                         hal_disable_halfsecond_timer();
1226                         break;
1227                 case EVENT_USER_BUTTONS:
1228                         dbg_out("button event %d\n", *(int *)data);
1229                         return handle_bluetooth_buttons(*(watch_button *)data, &bluetooth_screen);
1230                         break;
1231                 case EVENT_HALF_SEC_TIMER:
1232                         if (bluetooth_screen.set_mode) {
1233                                 if (bluetooth_screen.on)
1234                                         bluetooth_screen.on = FALSE;
1235                                 else
1236                                         bluetooth_screen.on = TRUE;
1237                         } else
1238                                 bluetooth_screen.on = TRUE;
1239                         draw_bluetooth_screen(&bluetooth_screen);
1240                         break;
1241                 default:
1242                         return EVENT_RET_UNHANDLED;
1243                         break;
1244         };
1245         return EVENT_RET_HANDLED;
1246 }
1247
1248
1249 /*
1250  * Info Screen
1251  */
1252 void draw_info_screen(void)
1253 {
1254         hal_lcd_clear_display();
1255
1256         oswald_draw_bitmap(36, 0, info_icon_width, info_icon_height, info_icon_bits);
1257
1258         oswald_draw_bitmap(81, 70, enterbutton_icon_width, enterbutton_icon_height, enterbutton_icon_bits);
1259
1260         oswald_write_string(2, 29, FONT_DROID8x12, FALSE, "Oswald");
1261         oswald_write_string(35, 29, FONT_DROID8x12, FALSE, OSWALD_VERSION);
1262         oswald_write_string(2, 41, FONT_DROID8x12, FALSE, "HAL");
1263         oswald_write_string(35, 41, FONT_DROID8x12, FALSE, (char *)hal_get_version_string());
1264         oswald_write_string(2, 53, FONT_DROID8x12, FALSE, "Build");
1265         oswald_write_string(35, 53, FONT_DROID8x12, FALSE, (char *)hal_get_buildno_string());
1266         oswald_write_string(2, 65, FONT_DROID8x12, FALSE, "Radio");
1267         oswald_write_string(35, 65, FONT_DROID8x12, FALSE, (char *)hal_get_radio_version_string());
1268
1269         hal_lcd_update_display();
1270 }
1271
1272 event_ret_t info_screen_handle_events(uint16_t event, void *data)
1273 {
1274         switch (event) {
1275                 case EVENT_SCREEN_VISIBLE:
1276                         draw_info_screen();
1277                         return EVENT_RET_HANDLED;
1278                         break;
1279                 case EVENT_USER_BUTTONS:
1280                         dbg_out("button event %d\n", *(int *)data);
1281                         break;
1282                 default:
1283                         return EVENT_RET_UNHANDLED;
1284                         break;
1285         };
1286         return EVENT_RET_UNHANDLED;
1287 }
1288
1289
1290 /*
1291  * Messages Screens
1292  */
1293 typedef struct {
1294         int8_t pos;     // marker position
1295         int8_t offset;  // offset in msg list
1296 } messages_data_t;
1297 static messages_data_t messages_screen = {
1298         0,
1299         0,
1300 };
1301
1302 typedef struct {
1303         uint8_t day;
1304         uint8_t month;
1305         uint8_t year;   // without century, add +1900
1306         uint8_t hour;
1307         uint8_t minute;
1308 } msg_timedate_t;
1309
1310 #define MSG_TYPE_READ           0
1311 #define MSG_TYPE_NEW            1
1312 #define MSG_TYPE_END            127
1313
1314 typedef struct {
1315         uint8_t type;
1316         msg_timedate_t td;
1317         char *msg;
1318 } message_t;
1319
1320 uint8_t Msgs = 15;
1321 message_t Msg[] = {
1322         { MSG_TYPE_READ, {9,5,113,0,38}, "Testmessage with more text than fits into the menu." },
1323         { MSG_TYPE_NEW, {9,5,113,0,39}, "Sitting in the train waiting to arrive." },
1324         { MSG_TYPE_READ, {9,5,113,0,40}, "People in the train are annoying!" },
1325         { MSG_TYPE_READ, {9,5,113,0,40}, "Auch auf Deutsch geht das hier und Text können lang sein." },
1326         { MSG_TYPE_NEW, {8,5,113,0,40}, "Und hier noch eine neue Nachricht, die nun wirklich lang ist, laenger als die anderen." },
1327         { MSG_TYPE_READ, {9,5,113,0,38}, "Testmessage with more text than fits into the menu." },
1328         { MSG_TYPE_NEW, {9,5,113,0,39}, "Sitting in the train waiting to arrive." },
1329         { MSG_TYPE_READ, {9,5,113,0,40}, "People in the train are annoying!" },
1330         { MSG_TYPE_READ, {9,5,113,0,40}, "Auch auf Deutsch geht das hier und Text können lang sein." },
1331         { MSG_TYPE_NEW, {8,5,113,0,40}, "Und hier noch eine neue Nachricht, die nun wirklich lang ist, laenger als die anderen." },
1332         { MSG_TYPE_READ, {9,5,113,0,38}, "Testmessage with more text than fits into the menu." },
1333         { MSG_TYPE_NEW, {9,5,113,0,39}, "Sitting in the train waiting to arrive." },
1334         { MSG_TYPE_READ, {9,5,113,0,40}, "People in the train are annoying!" },
1335         { MSG_TYPE_READ, {9,5,113,0,40}, "Auch auf Deutsch geht das hier und Text können lang sein." },
1336         { MSG_TYPE_NEW, {8,5,113,0,40}, "Und hier noch eine neue Nachricht, die nun wirklich lang ist, laenger als die anderen." },
1337         { MSG_TYPE_END, {0,0,0,0,0}, "Exit" },
1338 };
1339
1340 void draw_message_screen(messages_data_t *sdata)
1341 {
1342         char dstr[32];
1343         uint8_t strpos, msglen;
1344         uint8_t line;
1345
1346         hal_lcd_clear_display();
1347
1348 #if 0
1349         oswald_draw_bitmap(81, 6, upbutton_icon_width, upbutton_icon_height, upbutton_icon_bits);
1350         oswald_draw_bitmap(81, 38, downbutton_icon_width, downbutton_icon_height, downbutton_icon_bits);
1351 #endif
1352         oswald_draw_bitmap(81, 70, enterbutton_icon_width, enterbutton_icon_height, enterbutton_icon_bits);
1353
1354         Msg[sdata->offset + sdata->pos].type = MSG_TYPE_READ;
1355         snprintf(dstr, 19, "#%02d/%02d", sdata->pos + sdata->offset + 1, Msgs);
1356         oswald_write_string(30, 0, FONT_5x7, FALSE, dstr);
1357         oswald_draw_line(0,7,95,7);
1358
1359
1360         // here goes the text
1361         msglen = strlen(Msg[sdata->pos+sdata->offset].msg);
1362         strpos=0;
1363         line=0;
1364         while ((strpos < msglen) && (line < 6)) {
1365                 strpos += oswald_write_string_length(4, 9+(line*12), 84, FONT_DROID8x12, FALSE, &Msg[sdata->pos+sdata->offset].msg[strpos]);
1366                 line++;
1367         }
1368
1369
1370         oswald_draw_line(0,87,95,87);
1371
1372         if (Msg[sdata->offset + sdata->pos].type != MSG_TYPE_END) {
1373                 snprintf(dstr, 19, "%c %02d.%02d.%04d,%02d:%02d", (Msg[sdata->pos+sdata->offset].type == MSG_TYPE_NEW) ? '*':' ', Msg[sdata->pos+sdata->offset].td.day, Msg[sdata->pos+sdata->offset].td.month, Msg[sdata->pos+sdata->offset].td.year+1900, Msg[sdata->pos+sdata->offset].td.hour, Msg[sdata->pos+sdata->offset].td.minute);
1374                 oswald_write_string(2, 89, FONT_5x7, FALSE, dstr);
1375         }
1376
1377         hal_lcd_update_display();
1378 }
1379
1380 event_ret_t handle_message_screen_buttons(watch_button button, messages_data_t *sdata)
1381 {
1382         switch (button) {
1383                 case BUTTON_A:
1384                         break;
1385                 case BUTTON_B:
1386                         return EVENT_RET_HANDLED;
1387                         break;
1388                 case BUTTON_C:
1389                         // OswaldState.screen->event_func(EVENT_SCREEN_DESTROY, NULL);
1390                         OswaldState.screen_id = MESSAGES_SCREEN;
1391                         OswaldState.screen = &OswaldScreens[OswaldState.screen_id];
1392                         OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL);
1393                         return EVENT_RET_HANDLED;
1394                         break;
1395                 default:
1396                         break;
1397         }
1398
1399         return EVENT_RET_UNHANDLED;
1400 }
1401
1402 event_ret_t message_screen_handle_events(uint16_t event, void *data)
1403 {
1404         switch (event) {
1405                 case EVENT_SCREEN_VISIBLE:
1406                         draw_message_screen(&messages_screen);
1407                         return EVENT_RET_HANDLED;
1408                         break;
1409                 case EVENT_USER_BUTTONS:
1410                         dbg_out("button event %d\n", *(int *)data);
1411                         return handle_message_screen_buttons(*(watch_button *)data, &messages_screen);
1412                         break;
1413                 default:
1414                         break;
1415         };
1416         return EVENT_RET_UNHANDLED;
1417 }
1418
1419 void draw_messages_screen(messages_data_t *sdata)
1420 {
1421         char dstr[32];
1422         int i;
1423
1424         hal_lcd_clear_display();
1425
1426         // oswald_draw_bitmap(36, 0, Message_icon_width, Message_icon_height, Message_icon_bits);
1427
1428         oswald_draw_bitmap(81, 6, upbutton_icon_width, upbutton_icon_height, upbutton_icon_bits);
1429         oswald_draw_bitmap(81, 38, downbutton_icon_width, downbutton_icon_height, downbutton_icon_bits);
1430         oswald_draw_bitmap(81, 70, enterbutton_icon_width, enterbutton_icon_height, enterbutton_icon_bits);
1431
1432         if (Msg[sdata->offset + sdata->pos].type != MSG_TYPE_END) {
1433                 snprintf(dstr, 19, "#%02d/%02d", sdata->pos + sdata->offset + 1, Msgs);
1434                 oswald_write_string(30, 0, FONT_5x7, FALSE, dstr);
1435         }
1436         oswald_draw_line(0,7,95,7);
1437
1438         for (i=0; i<6; i++) {
1439                 if (Msg[i+sdata->offset].type != MSG_TYPE_END) {
1440                         //oswald_write_string_length(4, 9+(i*12), 84, FONT_DROID8x12, (Msg[i+sdata->offset].type == MSG_TYPE_NEW), Msg[i+sdata->offset].msg);
1441                         if (Msg[i+sdata->offset].type == MSG_TYPE_NEW)
1442                                 oswald_write_string_length(4, 9+(i*12), 84, FONT_DROID8x12b, (i+sdata->offset) == (sdata->offset + sdata->pos), Msg[i+sdata->offset].msg);
1443                         else
1444                                 oswald_write_string_length(4, 9+(i*12), 84, FONT_DROID8x12, (i+sdata->offset) == (sdata->offset + sdata->pos), Msg[i+sdata->offset].msg);
1445                 } else {
1446                         oswald_draw_bitmap(0, 66, leftbutton_icon_width, leftbutton_icon_height, leftbutton_icon_bits);
1447                 }
1448         }
1449
1450         // marker selected msg
1451         oswald_draw_line(1,9,1,81);
1452         oswald_draw_line_ww(1,10+(sdata->pos*12),1,20+(sdata->pos*12),2);
1453
1454         oswald_draw_line(0,87,95,87);
1455
1456         if (Msg[sdata->offset + sdata->pos].type != MSG_TYPE_END) {
1457                 snprintf(dstr, 19, "%c %02d.%02d.%04d,%02d:%02d", (Msg[sdata->pos+sdata->offset].type == MSG_TYPE_NEW) ? '*':' ', Msg[sdata->pos+sdata->offset].td.day, Msg[sdata->pos+sdata->offset].td.month, Msg[sdata->pos+sdata->offset].td.year+1900, Msg[sdata->pos+sdata->offset].td.hour, Msg[sdata->pos+sdata->offset].td.minute);
1458                 oswald_write_string(2, 89, FONT_5x7, FALSE, dstr);
1459         }
1460
1461         hal_lcd_update_display();
1462 }
1463
1464 event_ret_t handle_messages_screen_buttons(watch_button button, messages_data_t *sdata)
1465 {
1466         switch (button) {
1467                 case BUTTON_A:
1468                         sdata->pos--;
1469                         if (sdata->pos < 0) {
1470                                 if (sdata->offset > 0) {
1471                                         sdata->pos = 0;
1472                                         sdata->offset--;
1473                                         if (sdata->offset < 0)
1474                                                 sdata->offset = 0;
1475                                 } else {
1476                                         sdata->pos = 5;
1477                                         sdata->offset = (Msgs - 5);
1478                                         if (sdata->offset < 0)
1479                                                 sdata->offset = 0;
1480                                 }
1481                         }
1482                         draw_messages_screen(&messages_screen);
1483                         return EVENT_RET_HANDLED;
1484                         break;
1485                 case BUTTON_B:
1486                         sdata->pos++;
1487                         if (sdata->pos > 5) {
1488                                 sdata->pos = 5;
1489                                 sdata->offset++;
1490                                 if ((sdata->offset + 5) > Msgs) {
1491                                         sdata->offset = 0;
1492                                         sdata->pos = 0;
1493                                 }
1494                         }
1495                         draw_messages_screen(&messages_screen);
1496                         return EVENT_RET_HANDLED;
1497                         break;
1498                 case BUTTON_C:
1499                         if (Msg[sdata->offset + sdata->pos].type == MSG_TYPE_END)
1500                                 return EVENT_RET_UNHANDLED;
1501                         else
1502                                 // OswaldState.screen->event_func(EVENT_SCREEN_DESTROY, NULL);
1503                                 OswaldState.screen_id = MESSAGE_SCREEN;
1504                                 OswaldState.screen = &OswaldScreens[OswaldState.screen_id];
1505                                 OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL);
1506                                 return EVENT_RET_HANDLED;
1507                         break;
1508                 default:
1509                         break;
1510         }
1511
1512         return EVENT_RET_UNHANDLED;
1513 }
1514
1515 event_ret_t messages_screen_handle_events(uint16_t event, void *data)
1516 {
1517         switch (event) {
1518                 case EVENT_SCREEN_VISIBLE:
1519 //                      messages_screen.pos = 0;
1520 //                      messages_screen.offset = 0;
1521                         draw_messages_screen(&messages_screen);
1522                         return EVENT_RET_HANDLED;
1523                         break;
1524                 case EVENT_USER_BUTTONS:
1525                         dbg_out("button event %d\n", *(int *)data);
1526                         return handle_messages_screen_buttons(*(watch_button *)data, &messages_screen);
1527                         break;
1528                 default:
1529                         break;
1530         };
1531         return EVENT_RET_UNHANDLED;
1532 }
1533