]> git.karo-electronics.de Git - oswald.git/blob - ui/oswald_screens.c
c079e44fed344702d90b57093fbd436ad5106708
[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/timesetup_icon.xbm"
15
16 #if defined(__GNUC__) && (__MSP430X__ > 0)
17 __attribute__((__far__))
18 #endif
19 #include "bitmaps/stopwatch_icon.xbm"
20
21 #if defined(__GNUC__) && (__MSP430X__ > 0)
22 __attribute__((__far__))
23 #endif
24 #include "bitmaps/alarm_icon.xbm"
25
26 #if defined(__GNUC__) && (__MSP430X__ > 0)
27 __attribute__((__far__))
28 #endif
29 #include "bitmaps/startstopbutton_icon.xbm"
30
31 #if defined(__GNUC__) && (__MSP430X__ > 0)
32 __attribute__((__far__))
33 #endif
34 #include "bitmaps/lapsebutton_icon.xbm"
35
36 #if defined(__GNUC__) && (__MSP430X__ > 0)
37 __attribute__((__far__))
38 #endif
39 #include "bitmaps/upbutton_icon.xbm"
40
41 #if defined(__GNUC__) && (__MSP430X__ > 0)
42 __attribute__((__far__))
43 #endif
44 #include "bitmaps/downbutton_icon.xbm"
45
46 #if defined(__GNUC__) && (__MSP430X__ > 0)
47 __attribute__((__far__))
48 #endif
49 #include "bitmaps/Bluetooth_icon.xbm"
50
51 #if defined(__GNUC__) && (__MSP430X__ > 0)
52 __attribute__((__far__))
53 #endif
54 #include "bitmaps/info_icon.xbm"
55
56 #if defined(__GNUC__) && (__MSP430X__ > 0)
57 __attribute__((__far__))
58 #endif
59 #include "bitmaps/acc_icon.xbm"
60
61
62
63 /*
64  * Common event handler part of the watch faces
65  */
66 typedef struct {
67         void (*screendraw_func)(boolean show_seconds);
68         boolean show_seconds;
69         boolean analogue;
70 } idle_data_t;
71 static idle_data_t idle_screen = {
72         DrawLcdDigitalClock,
73         TRUE,
74         FALSE,
75 };
76  
77 event_ret_t idle_handle_user_buttons(watch_button button)
78 {
79         switch (button) {
80                 case BUTTON_A:
81                         if (idle_screen.show_seconds)
82                                 idle_screen.show_seconds = FALSE;
83                         else
84                                 idle_screen.show_seconds = TRUE;
85                         break;
86                 case BUTTON_B:
87                         if (idle_screen.analogue == TRUE) {
88                                 idle_screen.analogue = FALSE;
89                                 idle_screen.screendraw_func = DrawLcdDigitalClock;
90                         } else {
91                                 idle_screen.analogue = TRUE;
92                                 idle_screen.screendraw_func = DrawLcdAnaClock;
93                         };
94                         break;
95                 case BUTTON_C:
96                         return EVENT_RET_UNHANDLED;
97                         break;
98                 case BUTTON_F:
99                         OswaldState.screen_id = DATETIME_SETTING_SCREEN;
100                         OswaldState.screen = &OswaldScreens[OswaldState.screen_id];
101                         OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL);
102                         return EVENT_RET_HANDLED;
103                         break;
104                 default:
105                         return EVENT_RET_UNHANDLED;
106                         break;
107         };
108
109         idle_screen.screendraw_func(idle_screen.show_seconds);
110
111         return EVENT_RET_HANDLED;
112 }
113
114 event_ret_t idle_handle_events(uint16_t event, void *data)
115 {
116         switch (event) {
117                 case EVENT_ONE_SEC_TIMER:
118                 case EVENT_SCREEN_VISIBLE:
119                         idle_screen.screendraw_func(idle_screen.show_seconds);
120                         return EVENT_RET_HANDLED;
121                         break;
122                 case EVENT_USER_BUTTONS:
123                         dbg_out("button event %d\n", *(int *)data);
124                         return idle_handle_user_buttons(*(watch_button *)data);
125                         break;
126                 default:
127                         return EVENT_RET_UNHANDLED;
128                         break;
129         };
130         return EVENT_RET_UNHANDLED;
131 }
132
133
134 /*
135  * Accelerometer and sensor display screen
136  */
137 typedef struct {
138         accel_data_t accdata;
139 } accelscreen_data_t;
140 static accelscreen_data_t accel_screen = {
141         { 0, 0, 0},
142 };
143
144 void draw_accel_screen(accel_data_t *accel_data)
145 {
146         uint8_t x,y;
147
148         hal_lcd_clear_display();
149
150         oswald_draw_bitmap(36, 0, acc_icon_width, acc_icon_height, acc_icon_bits);
151
152         oswald_write_string(1, 40, FONT_6x9, "X:");
153         oswald_write_number(15, 40, FONT_6x9, accel_data->x);
154         oswald_write_string(1, 52, FONT_6x9, "Y:");
155         oswald_write_number(15, 52, FONT_6x9, accel_data->y);
156         oswald_write_string(1, 64, FONT_6x9, "Z:");
157         oswald_write_number(15, 64, FONT_6x9, accel_data->z);
158
159         oswald_write_string(1, 85, FONT_6x9, "Light:");
160         oswald_write_number(50, 85, FONT_6x9, 0);
161
162         oswald_draw_line(40, 30, 92, 30);
163         oswald_draw_line(92, 30, 92, 82);
164         oswald_draw_line(40, 82, 92, 82);
165         oswald_draw_line(40, 82, 40, 30);
166
167         x = 41+25+((accel_data->x * 50) / (254));
168         y = 31+25+((accel_data->y * 50) / (254));
169         oswald_draw_pixel(x, y);
170         oswald_draw_pixel(x+1, y);
171         oswald_draw_pixel(x-1, y);
172         oswald_draw_pixel(x, y+1);
173         oswald_draw_pixel(x, y-1);
174
175         hal_lcd_update_display();
176 }
177
178 event_ret_t accel_handle_events(uint16_t event, void *data)
179 {
180         switch (event) {
181                 case EVENT_SCREEN_VISIBLE:
182                         draw_accel_screen(&accel_screen.accdata);
183                         hal_accelerometer_enable();
184                         return EVENT_RET_HANDLED;
185                         break;
186                 case EVENT_SCREEN_DESTROY:
187                         hal_accelerometer_disable();
188                         return EVENT_RET_HANDLED;
189                         break;
190                 case EVENT_ACCEL_UPDATE: {
191                         accel_data_t *accel_data = (accel_data_t *)data;
192                         accel_screen.accdata.x = accel_data->x;
193                         accel_screen.accdata.y = accel_data->y;
194                         accel_screen.accdata.z = accel_data->z;
195                         draw_accel_screen(&accel_screen.accdata);
196                         };
197                         return EVENT_RET_HANDLED;
198                         break;
199                 case EVENT_USER_BUTTONS:
200                         dbg_out("button event %d\n", *(int *)data);
201                         break;
202                 default:
203                         return EVENT_RET_UNHANDLED;
204                         break;
205         };
206         return EVENT_RET_UNHANDLED;
207 }
208
209
210 /*
211  * Date / time setup screen
212  */
213 typedef struct {
214         uint8_t pos;
215         boolean set_mode;
216         boolean on;
217 } datetime_setup_data_t;
218 static datetime_setup_data_t dt_setup_screen = {
219         0,
220         FALSE,
221         TRUE
222 };
223
224 void draw_datetime_setup_screen(datetime_setup_data_t *sdata)
225 {
226         hal_lcd_clear_display();
227
228         oswald_draw_bitmap(36, 0, timesetup_icon_width, timesetup_icon_height, timesetup_icon_bits);
229
230         oswald_draw_bitmap(81, 6, upbutton_icon_width, upbutton_icon_height, upbutton_icon_bits);
231         oswald_draw_bitmap(81, 38, downbutton_icon_width, downbutton_icon_height, downbutton_icon_bits);
232
233         if ((sdata->pos == 0 && sdata->on) || sdata->pos != 0) {
234                 oswald_write_character(2, 30, FONT_LCD13x21, (OswaldClk.hour / 10));
235                 oswald_write_character(15, 30, FONT_LCD13x21, (OswaldClk.hour % 10));
236         }
237         oswald_write_character(25, 30, FONT_LCD13x21, 10);
238
239         if ((sdata->pos == 1 && sdata->on) || sdata->pos != 1) {
240                 oswald_write_character(34, 30, FONT_LCD13x21, (OswaldClk.minute / 10));
241                 oswald_write_character(47, 30, FONT_LCD13x21, (OswaldClk.minute % 10));
242         }
243
244         if ((sdata->pos == 2 && sdata->on) || sdata->pos != 2) {
245                 oswald_write_character(61, 38, FONT_LCD8x13, (OswaldClk.second / 10));
246                 oswald_write_character(69, 38, FONT_LCD8x13, (OswaldClk.second % 10));
247         }
248
249
250         if ((sdata->pos == 3 && sdata->on) || sdata->pos != 3) {
251                 oswald_write_number(2, 55, FONT_DROID8x12, OswaldClk.day);
252         }
253         oswald_write_character(15, 55, FONT_DROID8x12, '.');
254         if ((sdata->pos == 4 && sdata->on) || sdata->pos != 4) {
255                 oswald_write_number(21, 55, FONT_DROID8x12, OswaldClk.month);
256         }
257         oswald_write_character(36, 55, FONT_DROID8x12, '.');
258         if ((sdata->pos == 5 && sdata->on) || sdata->pos != 5) {
259                 oswald_write_number(43, 55, FONT_DROID8x12, OswaldClk.year);
260         }
261
262         if ((sdata->pos == 6 && sdata->on) || sdata->pos != 6) {
263                 if (OswaldClk.clk24hr) {
264                         oswald_write_character(2, 76, FONT_6x9, 'x');
265                 } else {
266                         oswald_write_character(2, 76, FONT_6x9, '_');
267                 }
268         }
269         oswald_write_string(15, 73, FONT_DROID8x12, "24hr");
270
271         if ((sdata->pos == 7 && sdata->on) || sdata->pos != 7) {
272                 if (OswaldClk.day_first) {
273                         oswald_write_character(2, 86, FONT_6x9, 'x');
274                 } else {
275                         oswald_write_character(2, 86, FONT_6x9, '_');
276                 }
277         }
278         oswald_write_string(15, 83, FONT_DROID8x12, "dd.mm.  mm/dd");
279
280         hal_lcd_update_display();
281 }
282
283 void datetime_handle_updown(uint8_t pos, int8_t incr)
284 {
285         switch (pos) {
286                 case 0: // hour
287                         if (OswaldClk.hour == 0 && incr == -1) {
288                                 OswaldClk.hour = 23;
289                                 break;
290                         };
291                         OswaldClk.hour += incr;
292                         if (OswaldClk.hour > 23)
293                                 OswaldClk.hour = 0;
294                         break;
295                 case 1: // minute
296                         if (OswaldClk.minute == 0 && incr == -1) {
297                                 OswaldClk.minute = 59;
298                                 break;
299                         };
300                         OswaldClk.minute += incr;
301                         if (OswaldClk.minute > 59)
302                                 OswaldClk.minute = 0;
303                         break;
304                 case 2: // second
305                         OswaldClk.second = 0;
306                         break;
307                 case 3: // day
308                         if (OswaldClk.day == 1 && incr == -1) {
309                                 OswaldClk.day = 31;
310                                 break;
311                         };
312                         OswaldClk.day += incr;
313                         if (OswaldClk.day > 31)
314                                 OswaldClk.day = 1;
315                         break;
316                 case 4: // month
317                         if (OswaldClk.month == 1 && incr == -1) {
318                                 OswaldClk.month = 12;
319                                 break;
320                         };
321                         OswaldClk.month += incr;
322                         if (OswaldClk.month > 12)
323                                 OswaldClk.month = 1;
324                         break;
325                 case 5: // year
326                         OswaldClk.year += incr;
327                         break;
328                 case 6: // 24hr / 12hr
329                         if (OswaldClk.clk24hr)
330                                 OswaldClk.clk24hr = FALSE;
331                         else
332                                 OswaldClk.clk24hr = TRUE;
333                         break;
334                 case 7: // dd.mm. / mm/dd
335                         if (OswaldClk.day_first)
336                                 OswaldClk.day_first = FALSE;
337                         else
338                                 OswaldClk.day_first = TRUE;
339                         break;
340                 default:
341                         break;
342         };
343         if (pos == 2)
344                 hal_set_rtc(&OswaldClk, TRUE);
345         else
346                 hal_set_rtc(&OswaldClk, FALSE);
347 }
348
349 event_ret_t handle_setup_datetime_buttons(watch_button button, datetime_setup_data_t *sdata)
350 {
351         switch (button) {
352                 case BUTTON_A:
353                         datetime_handle_updown(sdata->pos, 1);
354                         break;
355                 case BUTTON_B:
356                         datetime_handle_updown(sdata->pos, -1);
357                         break;
358                 case BUTTON_C:
359                         sdata->pos++;
360                         sdata->pos %= 8;
361                         break;
362                 case BUTTON_F:
363                         OswaldState.screen->event_func(EVENT_SCREEN_DESTROY, NULL);
364                         OswaldState.screen_id = IDLE_SCREEN;
365                         OswaldState.screen = &OswaldScreens[OswaldState.screen_id];
366                         OswaldState.screen->event_func(EVENT_SCREEN_VISIBLE, NULL);
367                         return EVENT_RET_HANDLED;
368                         break;
369                 default:
370                         return EVENT_RET_UNHANDLED;
371                         break;
372         }
373         draw_datetime_setup_screen(sdata);
374         return EVENT_RET_HANDLED;
375 }
376
377 event_ret_t datetime_setup_events(uint16_t event, void *data)
378 {
379         switch (event) {
380                 case EVENT_SCREEN_VISIBLE:
381                         dt_setup_screen.pos = 0;
382                         draw_datetime_setup_screen(&dt_setup_screen);
383                         hal_enable_halfsecond_timer();
384                         return EVENT_RET_HANDLED;
385                         break;
386                 case EVENT_SCREEN_DESTROY:
387                         hal_disable_halfsecond_timer();
388                         return EVENT_RET_HANDLED;
389                         break;
390                 case EVENT_USER_BUTTONS:
391                         dbg_out("button event %d\n", *(int *)data);
392                         return handle_setup_datetime_buttons(*(watch_button *)data, &dt_setup_screen);
393                         break;
394                 case EVENT_HALF_SEC_TIMER:
395                         if (dt_setup_screen.on)
396                                 dt_setup_screen.on = FALSE;
397                         else
398                                 dt_setup_screen.on = TRUE;
399                         draw_datetime_setup_screen(&dt_setup_screen);
400                         return EVENT_RET_HANDLED;
401                         break;
402                 default:
403                         return EVENT_RET_UNHANDLED;
404                         break;
405         };
406         return EVENT_RET_UNHANDLED;
407 }
408
409
410 /*
411  * Alarm setup screen
412  */
413 typedef struct {
414         uint8_t pos;
415         boolean set_mode;
416         boolean on;
417 } alarm_setup_data_t;
418 static alarm_setup_data_t alarm_setup_screen = {
419         0,
420         FALSE,
421         TRUE
422 };
423
424 void draw_alarm_setup_screen(alarm_setup_data_t *sdata)
425 {
426         hal_lcd_clear_display();
427
428         oswald_draw_bitmap(36, 0, alarm_icon_width, alarm_icon_height, alarm_icon_bits);
429
430         oswald_draw_bitmap(81, 6, upbutton_icon_width, upbutton_icon_height, upbutton_icon_bits);
431         oswald_draw_bitmap(81, 38, downbutton_icon_width, downbutton_icon_height, downbutton_icon_bits);
432
433         if ((sdata->pos == 0 && sdata->on) || sdata->pos != 0) {
434                 oswald_write_character(18, 30, FONT_LCD13x21, (OswaldAlarm.hour / 10));
435                 oswald_write_character(32, 30, FONT_LCD13x21, (OswaldAlarm.hour % 10));
436         }
437         oswald_write_character(42, 30, FONT_LCD13x21, 10);
438
439         if ((sdata->pos == 1 && sdata->on) || sdata->pos != 1) {
440                 oswald_write_character(53, 30, FONT_LCD13x21, (OswaldAlarm.minute / 10));
441                 oswald_write_character(67, 30, FONT_LCD13x21, (OswaldAlarm.minute % 10));
442         }
443
444         oswald_write_character(3, 55, FONT_6x9, 'S');
445         oswald_write_character(15, 55, FONT_6x9, 'M');
446         oswald_write_character(27, 55, FONT_6x9, 'T');
447         oswald_write_character(39, 55, FONT_6x9, 'W');
448         oswald_write_character(51, 55, FONT_6x9, 'T');
449         oswald_write_character(63, 55, FONT_6x9, 'F');
450         oswald_write_character(75, 55, FONT_6x9, 'S');
451
452         if ((sdata->pos == 2 && sdata->on) || sdata->pos != 2)
453                 oswald_write_character(3, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_SUNDAY) ? 'x' : '_');
454         if ((sdata->pos == 3 && sdata->on) || sdata->pos != 3)
455                 oswald_write_character(15, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_MONDAY) ? 'x' : '_');
456         if ((sdata->pos == 4 && sdata->on) || sdata->pos != 4)
457                 oswald_write_character(27, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_TUESDAY) ? 'x' : '_');
458         if ((sdata->pos == 5 && sdata->on) || sdata->pos != 5)
459                 oswald_write_character(39, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_WEDNESDAY) ? 'x' : '_');
460         if ((sdata->pos == 6 && sdata->on) || sdata->pos != 6)
461                 oswald_write_character(51, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_THURSDAY) ? 'x' : '_');
462         if ((sdata->pos == 7 && sdata->on) || sdata->pos != 7)
463                 oswald_write_character(63, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_FRIDAY) ? 'x' : '_');
464         if ((sdata->pos == 8 && sdata->on) || sdata->pos != 8)
465                 oswald_write_character(75, 65, FONT_6x9, (OswaldAlarm.wday & WDAY_SATURDAY) ? 'x' : '_');
466
467         hal_lcd_update_display();
468 }
469
470 void alarm_handle_updown(uint8_t pos, int8_t incr)
471 {
472         switch (pos) {
473                 case 0: // hour
474                         if (OswaldAlarm.hour == 0 && incr == -1) {
475                                 OswaldAlarm.hour = 23;
476                                 break;
477                         };
478                         OswaldAlarm.hour += incr;
479                         if (OswaldAlarm.hour > 23)
480                                 OswaldAlarm.hour = 0;
481                         break;
482                 case 1: // minute
483                         if (OswaldAlarm.minute == 0 && incr == -1) {
484                                 OswaldAlarm.minute = 59;
485                                 break;
486                         };
487                         OswaldAlarm.minute += incr;
488                         if (OswaldAlarm.minute > 59)
489                                 OswaldAlarm.minute = 0;
490                         break;
491                 case 2: // sunday
492                         OswaldAlarm.wday ^= WDAY_SUNDAY;
493                         break;
494                 case 3: // monday
495                         OswaldAlarm.wday ^= WDAY_MONDAY;
496                         break;
497                 case 4: // tuesday
498                         OswaldAlarm.wday ^= WDAY_TUESDAY;
499                         break;
500                 case 5: // wednesday
501                         OswaldAlarm.wday ^= WDAY_WEDNESDAY;
502                         break;
503                 case 6: // thursday
504                         OswaldAlarm.wday ^= WDAY_THURSDAY;
505                         break;
506                 case 7: // friday
507                         OswaldAlarm.wday ^= WDAY_FRIDAY;
508                         break;
509                 case 8: // saturday
510                         OswaldAlarm.wday ^= WDAY_SATURDAY;
511                         break;
512                 default:
513                         break;
514         };
515 }
516
517 event_ret_t handle_setup_alarm_buttons(watch_button button, alarm_setup_data_t *sdata)
518 {
519         if (alarm_setup_screen.set_mode) {
520                 switch (button) {
521                         case BUTTON_A:
522                                 alarm_handle_updown(sdata->pos, 1);
523                                 break;
524                         case BUTTON_B:
525                                 alarm_handle_updown(sdata->pos, -1);
526                                 break;
527                         case BUTTON_C:
528                                 sdata->pos++;
529                                 sdata->pos %= 9;
530                                 break;
531                         case BUTTON_F:
532                                 alarm_setup_screen.set_mode = FALSE;
533                                 break;
534                         default:
535                                 return EVENT_RET_UNHANDLED;
536                                 break;
537                 }
538         } else {
539                 switch (button) {
540                         case BUTTON_F:
541                                 alarm_setup_screen.set_mode = TRUE;
542                                 break;
543                         default:
544                                 return EVENT_RET_UNHANDLED;
545                                 break;
546                 }
547         }
548         draw_alarm_setup_screen(sdata);
549
550         return EVENT_RET_HANDLED;
551 }
552
553 event_ret_t alarm_setup_events(uint16_t event, void *data)
554 {
555         switch (event) {
556                 case EVENT_SCREEN_VISIBLE:
557                         alarm_setup_screen.pos = 0;
558                         alarm_setup_screen.on = TRUE;
559                         alarm_setup_screen.set_mode = FALSE;
560                         draw_alarm_setup_screen(&alarm_setup_screen);
561                         hal_enable_halfsecond_timer();
562                         return EVENT_RET_HANDLED;
563                         break;
564                 case EVENT_SCREEN_DESTROY:
565                         hal_disable_halfsecond_timer();
566                         return EVENT_RET_HANDLED;
567                         break;
568                 case EVENT_USER_BUTTONS:
569                         dbg_out("button event %d\n", *(int *)data);
570                         return handle_setup_alarm_buttons(*(watch_button *)data, &alarm_setup_screen);
571                         break;
572                 case EVENT_HALF_SEC_TIMER:
573                         if (alarm_setup_screen.set_mode) {
574                                 if (alarm_setup_screen.on)
575                                         alarm_setup_screen.on = FALSE;
576                                 else
577                                         alarm_setup_screen.on = TRUE;
578                         } else
579                                 alarm_setup_screen.on = TRUE;
580                         draw_alarm_setup_screen(&alarm_setup_screen);
581                         return EVENT_RET_HANDLED;
582                         break;
583                 default:
584                         return EVENT_RET_UNHANDLED;
585                         break;
586         };
587         return EVENT_RET_UNHANDLED;
588 }
589
590
591 /*
592  * Test menu
593  */
594 typedef struct {
595         uint8_t menu_pos;
596 } test_menu_t;
597 static test_menu_t test_menu = { 0 };
598
599 void draw_menu_test_screen(void)
600 {
601         hal_lcd_clear_display();
602 #if 0
603         SetFont(MetaWatch16);
604         WriteLcdString(2, 2, "Menu");
605         SetFont(MetaWatch7);
606         WriteLcdString(2, 20, "Item 1");
607         WriteLcdString(2, 29, "Item 2");
608         WriteLcdString(2, 38, "Item 3");
609         WriteLcdString(2, 47, "Item 4");
610         WriteLcdString(2, 56, "Item 5");
611
612         WriteLcdString(50, 20+(9*test_menu.menu_pos), "*");
613 #endif
614         oswald_write_string(2, 2, FONT_DROID11x14b, "Menu");
615
616         oswald_write_string(2, 20, FONT_DROID8x12, "Item 1");
617         oswald_write_string(2, 29, FONT_DROID8x12, "Item 2");
618         oswald_write_string(2, 38, FONT_DROID8x12, "Item 3");
619         oswald_write_string(2, 47, FONT_DROID8x12, "Item 4");
620         oswald_write_string(2, 56, FONT_DROID8x12, "Item 5");
621
622         oswald_write_character(50, 18+(9*test_menu.menu_pos), FONT_6x9, 0x11);
623
624         hal_lcd_update_display();
625 }
626
627 event_ret_t handle_menu_user_buttons(watch_button button)
628 {
629         switch (button) {
630                 case BUTTON_A:
631                         test_menu.menu_pos--;
632                         test_menu.menu_pos %= 5;
633                         break;
634                 case BUTTON_B:
635                         test_menu.menu_pos++;
636                         test_menu.menu_pos %= 5;
637                         break;
638                 default:
639                         return EVENT_RET_UNHANDLED;
640                         break;
641         }
642         draw_menu_test_screen();
643         return EVENT_RET_HANDLED;
644 }
645
646 event_ret_t test_menu_handle_events(uint16_t event, void *data)
647 {
648         switch (event) {
649                 case EVENT_USER_BUTTONS:
650                         dbg_out("button event %d\n", *(int *)data);
651                         return handle_menu_user_buttons(*(watch_button *)data);
652                         break;
653                 case EVENT_SCREEN_VISIBLE:
654                         test_menu.menu_pos = 0;
655                         draw_menu_test_screen();
656                         break;
657                 default:
658                         return EVENT_RET_UNHANDLED;
659                         break;
660         };
661         return EVENT_RET_HANDLED;
662 }
663
664
665 /*
666  * Stop Watch
667  */
668 typedef struct {
669         uint8_t hr;
670         uint8_t min;
671         uint8_t sec;
672         uint8_t csec;
673         uint8_t lapse_hr;
674         uint8_t lapse_min;
675         uint8_t lapse_sec;
676         uint8_t lapse_csec;
677         boolean running;
678 } stopwatch_data_t;
679 static stopwatch_data_t stopwatch_screen = { 0, 0, 0, 0, 0, 0, 0, 0, FALSE };
680
681 #if 0
682 static void update_stop_watch_screen(stopwatch_data_t *sdata)
683 {
684         //char tstr[16];
685 #if 0
686         SetFont(MetaWatchMonospaced10);
687
688         snprintf(tstr, 16, "%02d:%02d:%02d.%1d", sdata->hr, sdata->min, sdata->sec, sdata->csec / 10);
689         WriteLcdString(5, 40, tstr);
690         snprintf(tstr, 16, "%02d:%02d:%02d.%02d", sdata->lapse_hr, sdata->lapse_min, sdata->lapse_sec, sdata->lapse_csec);
691         WriteLcdString(5, 60, tstr);
692 #endif
693 #if 0
694         snprintf(tstr, 16, "%02d:%02d:%02d.%1d", sdata->hr, sdata->min, sdata->sec, sdata->csec / 10);
695         oswald_write_string(5, 40, FONT_6x9, tstr);
696
697         snprintf(tstr, 16, "%02d:%02d:%02d.%02d", sdata->lapse_hr, sdata->lapse_min, sdata->lapse_sec, sdata->lapse_csec);
698         oswald_write_string(5, 60, FONT_6x9, tstr);
699 #endif
700
701         hal_lcd_update_display();
702 }
703 #endif
704
705 static void draw_stop_watch_screen(stopwatch_data_t *sdata)
706 {
707         int gRow = 1;
708         int gColumn = 35;
709
710         hal_lcd_clear_display();
711
712         oswald_draw_bitmap(36, 0, stopwatch_icon_width, stopwatch_icon_height, stopwatch_icon_bits);
713         oswald_draw_bitmap(81, 6, startstopbutton_icon_width, startstopbutton_icon_height, startstopbutton_icon_bits);
714         oswald_draw_bitmap(81, 38, lapsebutton_icon_width, lapsebutton_icon_height, lapsebutton_icon_bits);
715
716 #if 0
717         update_stop_watch_screen(sdata);
718 #else
719         gRow += 3 + oswald_write_character(gRow, gColumn, FONT_LCD13x21, (sdata->hr % 10));
720         gRow += oswald_write_character(gRow, gColumn, FONT_LCD13x21, (sdata->min / 10));
721         gRow += 3 + oswald_write_character(gRow, gColumn, FONT_LCD13x21, (sdata->min % 10));
722         gRow += oswald_write_character(gRow, gColumn, FONT_LCD13x21, (sdata->sec / 10));
723         gRow += 3 + oswald_write_character(gRow, gColumn, FONT_LCD13x21, (sdata->sec % 10));
724         gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->csec / 10));
725
726         gRow = 6;
727         gColumn = 62;
728         gRow += 13 + oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_hr % 10));
729         gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_min / 10));
730         gRow += 13 + oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_min % 10));
731         gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_sec / 10));
732         gRow += 3 + oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_sec % 10));
733         gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_csec / 10));
734         gRow += oswald_write_character(gRow, gColumn, FONT_LCD8x13, (sdata->lapse_csec % 10));
735
736         hal_lcd_update_display();
737 #endif
738 }
739
740 event_ret_t handle_stop_watch_buttons(watch_button button)
741 {
742         switch (button) {
743                 case BUTTON_A: // start/stop
744                         if (stopwatch_screen.running) {
745                                 hal_disable_centisecond_timer();
746                                 stopwatch_screen.running = FALSE;
747                         } else {
748                                 hal_enable_centisecond_timer();
749                                 stopwatch_screen.running = TRUE;
750                         }
751                         return EVENT_RET_HANDLED;
752                         break;
753                 case BUTTON_B: // lapse
754                         stopwatch_screen.lapse_hr = stopwatch_screen.hr;
755                         stopwatch_screen.lapse_min = stopwatch_screen.min;
756                         stopwatch_screen.lapse_sec = stopwatch_screen.sec;
757                         stopwatch_screen.lapse_csec = stopwatch_screen.csec;
758                         return EVENT_RET_HANDLED;
759                         break;
760                 case BUTTON_F: // reset
761                         stopwatch_screen.hr = 0;
762                         stopwatch_screen.min = 0;
763                         stopwatch_screen.sec = 0;
764                         stopwatch_screen.csec = 0;
765                         stopwatch_screen.lapse_hr = 0;
766                         stopwatch_screen.lapse_min = 0;
767                         stopwatch_screen.lapse_sec = 0;
768                         stopwatch_screen.lapse_csec = 0;
769                         return EVENT_RET_HANDLED;
770                         break;
771                 default:
772                         return EVENT_RET_UNHANDLED;
773                         break;
774         }
775         return EVENT_RET_UNHANDLED;
776 }
777
778 event_ret_t stop_watch_handle_events(uint16_t event, void *data)
779 {
780         switch (event) {
781                 case EVENT_USER_BUTTONS:
782                         dbg_out("button event %d\n", *(int *)data);
783                         return handle_stop_watch_buttons(*(watch_button *)data);
784                         //update_stop_watch_screen(&stopwatch_screen);
785                         draw_stop_watch_screen(&stopwatch_screen);
786                         break;
787                 case EVENT_SCREEN_VISIBLE:
788                         hal_lcd_clear_display();
789                         draw_stop_watch_screen(&stopwatch_screen);
790                         return EVENT_RET_HANDLED;
791                         break;
792                 case EVENT_SCREEN_DESTROY:
793                         hal_disable_centisecond_timer();
794                         stopwatch_screen.running = FALSE;
795                         return EVENT_RET_HANDLED;
796                         break;
797                 case EVENT_CS_TIMER:
798                         stopwatch_screen.csec++;
799                         if (stopwatch_screen.csec > 99) {
800                                 stopwatch_screen.csec = 0;
801                                 stopwatch_screen.sec++;
802                         };
803                         if (stopwatch_screen.sec > 59) {
804                                 stopwatch_screen.sec = 0;
805                                 stopwatch_screen.min++;
806                         };
807                         if (stopwatch_screen.min > 59) {
808                                 stopwatch_screen.min = 0;
809                                 stopwatch_screen.hr++;
810                         };
811                         if (stopwatch_screen.hr > 59) {
812                                 stopwatch_screen.hr = 0;
813                         };
814                         if (stopwatch_screen.csec % 10 == 0)
815                                 draw_stop_watch_screen(&stopwatch_screen);
816                                 //update_stop_watch_screen(&stopwatch_screen);
817                         return EVENT_RET_HANDLED;
818                         break;
819                 default:
820                         return EVENT_RET_UNHANDLED;
821                         break;
822         };
823         return EVENT_RET_HANDLED;
824 }
825
826
827 /*
828  * Alarm screen, shown when alarm is fired
829  */
830 void draw_alarm_screen(void)
831 {
832         hal_lcd_clear_display();
833
834         oswald_draw_bitmap(36, 20, alarm_icon_width, alarm_icon_height, alarm_icon_bits);
835
836         hal_lcd_update_display();
837 }
838
839 event_ret_t alarm_handle_events(uint16_t event, void *data)
840 {
841         switch (event) {
842                 case EVENT_SCREEN_VISIBLE:
843                         draw_alarm_screen();
844                         hal_enable_halfsecond_timer();
845                         hal_vibration_set_state(TRUE);
846                         return EVENT_RET_HANDLED;
847                         break;
848                 case EVENT_SCREEN_DESTROY:
849                         hal_disable_halfsecond_timer();
850                         hal_lcd_set_backlight(FALSE);
851                         hal_vibration_set_state(FALSE);
852                         return EVENT_RET_HANDLED;
853                         break;
854                 case EVENT_USER_BUTTONS:
855                         dbg_out("button event %d\n", *(int *)data);
856                         // hal_lcd_set_backlight(FALSE);
857                         return EVENT_RET_HANDLED;
858                         break;
859                 case EVENT_HALF_SEC_TIMER:
860                         hal_lcd_set_backlight(!hal_lcd_get_backlight());
861                         hal_vibration_set_state(!hal_vibration_get_state());
862                         dbg_out("timer\n");
863                         return EVENT_RET_HANDLED;
864                         break;
865                 default:
866                         return EVENT_RET_UNHANDLED;
867                         break;
868         };
869         return EVENT_RET_HANDLED;
870 }
871
872
873 /*
874  * Bluetooth setup screen
875  */
876 typedef struct {
877         uint8_t pos;
878         boolean bt_en;
879         boolean set_mode;
880         boolean on;
881 } bluetooth_data_t;
882 static bluetooth_data_t bluetooth_screen = {
883         0,
884         FALSE,
885         FALSE,
886         TRUE
887 };
888
889 void draw_bluetooth_screen(bluetooth_data_t *sdata)
890 {
891         char bstr[20];
892         uint8_t *bd_addr;
893
894         hal_lcd_clear_display();
895
896         oswald_draw_bitmap(36, 0, Bluetooth_icon_width, Bluetooth_icon_height, Bluetooth_icon_bits);
897
898         oswald_draw_bitmap(81, 6, upbutton_icon_width, upbutton_icon_height, upbutton_icon_bits);
899         oswald_draw_bitmap(81, 38, downbutton_icon_width, downbutton_icon_height, downbutton_icon_bits);
900
901         oswald_write_string(1, 30, FONT_DROID8x12, "Enable:");
902         if ((sdata->pos == 0 && sdata->on) || sdata->pos != 0) {
903                 oswald_write_character(53, 30, FONT_DROID8x12, bluetooth_screen.bt_en ? 'x' : '_');
904         }
905         oswald_write_string(1, 40, FONT_DROID8x12, "State:");
906         switch (hal_bluetooth_get_state()) {
907                 case BLUETOOTH_OFF:
908                         oswald_write_string(53, 40, FONT_DROID8x12, "off");
909                         break;
910                 case BLUETOOTH_ON:
911                         oswald_write_string(53, 40, FONT_DROID8x12, "on");
912                         break;
913                 case BLUETOOTH_CONNECTED:
914                         oswald_write_string(53, 40, FONT_DROID8x12, "conn.");
915                         break;
916                 default:
917                         break;
918         };
919         oswald_write_string(1, 50, FONT_DROID8x12, "Visible:");
920         if ((sdata->pos == 1 && sdata->on) || sdata->pos != 1) {
921                 oswald_write_character(53, 50, FONT_DROID8x12, hal_bluetooth_get_visible() ? 'x' : '_');
922         }
923
924         if (hal_bluetooth_get_state() >= BLUETOOTH_ON) {
925                 bd_addr = hal_bluetooth_get_local_bdaddr();
926                 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]);
927                 oswald_write_string(2, 85, FONT_5x7, bstr);
928         } else {
929         }
930
931         hal_lcd_update_display();
932 }
933
934 void bluetooth_handle_updown(uint8_t pos, int8_t incr)
935 {
936         switch (pos) {
937                 case 0:
938                         if (hal_bluetooth_get_state() >= BLUETOOTH_ON) {
939                                 hal_bluetooth_set_state(BLUETOOTH_OFF);
940                                 bluetooth_screen.bt_en = FALSE;
941                         } else {
942                                 hal_bluetooth_set_state(BLUETOOTH_ON);
943                                 bluetooth_screen.bt_en = TRUE;
944                         }
945                         break;
946                 case 1:
947                         if (hal_bluetooth_get_state() >= BLUETOOTH_ON && !hal_bluetooth_get_visible()) {
948                                 hal_bluetooth_set_visible(TRUE);
949                         } else {
950                                 hal_bluetooth_set_visible(FALSE);
951                         }
952                         break;
953                 case 2:
954                         break;
955                 case 3:
956                         break;
957                 case 4:
958                         break;
959                 case 5:
960                         break;
961                 case 6:
962                         break;
963                 case 7:
964                         break;
965                 case 8:
966                         break;
967                 default:
968                         break;
969         };
970 }
971
972 event_ret_t handle_bluetooth_buttons(watch_button button, bluetooth_data_t *sdata)
973 {
974         if (bluetooth_screen.set_mode) {
975                 switch (button) {
976                         case BUTTON_A:
977                                 bluetooth_handle_updown(sdata->pos, 1);
978                                 break;
979                         case BUTTON_B:
980                                 bluetooth_handle_updown(sdata->pos, -1);
981                                 break;
982                         case BUTTON_C:
983                                 sdata->pos++;
984                                 sdata->pos %= 2;
985                                 break;
986                         case BUTTON_F:
987                                 bluetooth_screen.set_mode = FALSE;
988                                 break;
989                         default:
990                                 return EVENT_RET_UNHANDLED;
991                                 break;
992                 }
993         } else {
994                 switch (button) {
995                         case BUTTON_F:
996                                 bluetooth_screen.set_mode = TRUE;
997                                 break;
998                         default:
999                                 return EVENT_RET_UNHANDLED;
1000                                 break;
1001                 }
1002         }
1003
1004         draw_bluetooth_screen(sdata);
1005
1006         return EVENT_RET_HANDLED;
1007 }
1008
1009 event_ret_t bluetooth_screen_events(uint16_t event, void *data)
1010 {
1011         switch (event) {
1012                 case EVENT_SCREEN_VISIBLE:
1013                         bluetooth_screen.pos = 0;
1014                         bluetooth_screen.bt_en = (hal_bluetooth_get_state() > 0);
1015                         draw_bluetooth_screen(&bluetooth_screen);
1016                         hal_enable_halfsecond_timer();
1017                         break;
1018                 case EVENT_SCREEN_DESTROY:
1019                         hal_disable_halfsecond_timer();
1020                         break;
1021                 case EVENT_USER_BUTTONS:
1022                         dbg_out("button event %d\n", *(int *)data);
1023                         return handle_bluetooth_buttons(*(watch_button *)data, &bluetooth_screen);
1024                         break;
1025                 case EVENT_HALF_SEC_TIMER:
1026                         if (bluetooth_screen.set_mode) {
1027                                 if (bluetooth_screen.on)
1028                                         bluetooth_screen.on = FALSE;
1029                                 else
1030                                         bluetooth_screen.on = TRUE;
1031                         } else
1032                                 bluetooth_screen.on = TRUE;
1033                         draw_bluetooth_screen(&bluetooth_screen);
1034                         break;
1035                 default:
1036                         return EVENT_RET_UNHANDLED;
1037                         break;
1038         };
1039         return EVENT_RET_HANDLED;
1040 }
1041
1042
1043 /*
1044  * Info Screen
1045  */
1046 void draw_info_screen(accel_data_t *accel_data)
1047 {
1048         hal_lcd_clear_display();
1049
1050         oswald_draw_bitmap(36, 0, info_icon_width, info_icon_height, info_icon_bits);
1051
1052         oswald_write_string(2, 29, FONT_DROID8x12, "Oswald");
1053         oswald_write_string(35, 29, FONT_DROID8x12, OSWALD_VERSION);
1054         oswald_write_string(2, 41, FONT_DROID8x12, "HAL");
1055         oswald_write_string(35, 41, FONT_DROID8x12, (char *)hal_get_version_string());
1056         oswald_write_string(2, 53, FONT_DROID8x12, "Build");
1057         oswald_write_string(35, 53, FONT_DROID8x12, (char *)hal_get_buildno_string());
1058         oswald_write_string(2, 65, FONT_DROID8x12, "Radio");
1059         oswald_write_string(35, 65, FONT_DROID8x12, (char *)hal_get_radio_version_string());
1060
1061         hal_lcd_update_display();
1062 }
1063
1064 event_ret_t info_screen_handle_events(uint16_t event, void *data)
1065 {
1066         switch (event) {
1067                 case EVENT_SCREEN_VISIBLE:
1068                         draw_info_screen(&accel_screen.accdata);
1069                         return EVENT_RET_HANDLED;
1070                         break;
1071                 case EVENT_USER_BUTTONS:
1072                         dbg_out("button event %d\n", *(int *)data);
1073                         break;
1074                 default:
1075                         return EVENT_RET_UNHANDLED;
1076                         break;
1077         };
1078         return EVENT_RET_UNHANDLED;
1079 }
1080