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