Use same loop count for writing and memset'ing in test_mem to have same precision...
[kugel-rb.git] / apps / menus / time_menu.c
blobb4ed207f5c4da121be1a827995311935024703c2
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Jonathan Gordon
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdbool.h>
23 #include <stddef.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include "config.h"
27 #include "string.h"
28 #include "lang.h"
29 #include "action.h"
30 #include "settings.h"
31 #include "powermgmt.h"
32 #include "menu.h"
33 #include "misc.h"
34 #include "exported_menus.h"
35 #include "keyboard.h"
36 #include "talk.h"
37 #include "time.h"
38 #include "viewport.h"
39 #include "list.h"
40 #include "alarm_menu.h"
41 #include "screens.h"
42 #include "radio.h"
43 #include "font.h"
44 #include "system.h"
46 static int timedate_set(void)
48 /* Make a local copy of the time struct */
49 struct tm tm = *get_time();
50 int result;
52 /* do some range checks */
53 /* This prevents problems with time/date setting after a power loss */
54 if (!valid_time(&tm))
56 /* Macros to convert a 2-digit string to a decimal constant.
57 (YEAR), MONTH and DAY are set by the date command, which outputs
58 DAY as 00..31 and MONTH as 01..12. The leading zero would lead to
59 misinterpretation as an octal constant. */
60 #define S100(x) 1 ## x
61 #define C2DIG2DEC(x) (S100(x)-100)
63 tm.tm_hour = 0;
64 tm.tm_min = 0;
65 tm.tm_sec = 0;
66 tm.tm_mday = C2DIG2DEC(DAY);
67 tm.tm_mon = C2DIG2DEC(MONTH)-1;
68 tm.tm_wday = 1;
69 tm.tm_year = YEAR-1900;
72 result = (int)set_time_screen(str(LANG_SET_TIME), &tm);
74 if(tm.tm_year != -1) {
75 set_time(&tm);
77 return result;
80 MENUITEM_FUNCTION(time_set, 0, ID2P(LANG_SET_TIME),
81 timedate_set, NULL, NULL, Icon_NOICON);
82 MENUITEM_SETTING(timeformat, &global_settings.timeformat, NULL);
84 /* in main_menu.c */
85 extern const struct menu_item_ex sleep_timer_call;
87 #ifdef HAVE_RTC_ALARM
88 MENUITEM_FUNCTION(alarm_screen_call, 0, ID2P(LANG_ALARM_MOD_ALARM_MENU),
89 (menu_function)alarm_screen, NULL, NULL, Icon_NOICON);
90 #if CONFIG_TUNER || defined(HAVE_RECORDING)
92 #if CONFIG_TUNER && !defined(HAVE_RECORDING)
93 /* This need only be shown if we dont have recording, because if we do
94 then always show the setting item, because there will always be at least
95 2 items */
96 static int alarm_callback(int action,const struct menu_item_ex *this_item)
98 (void)this_item;
99 switch (action)
101 case ACTION_REQUEST_MENUITEM:
102 if (radio_hardware_present() == 0)
103 return ACTION_EXIT_MENUITEM;
104 break;
106 return action;
108 #else
109 #define alarm_callback NULL
110 #endif /* CONFIG_TUNER && !HAVE_RECORDING */
111 /* have to do this manually because the setting screen
112 doesnt handle variable item count */
113 static int alarm_setting(void)
115 struct opt_items items[ALARM_START_COUNT];
116 int i = 0;
117 items[i].string = str(LANG_RESUME_PLAYBACK);
118 items[i].voice_id = LANG_RESUME_PLAYBACK;
119 i++;
120 #if CONFIG_TUNER
121 if (radio_hardware_present())
123 items[i].string = str(LANG_FM_RADIO);
124 items[i].voice_id = LANG_FM_RADIO;
125 i++;
127 #endif
128 #ifdef HAVE_RECORDING
129 items[i].string = str(LANG_RECORDING);
130 items[i].voice_id = LANG_RECORDING;
131 i++;
132 #endif
133 return set_option(str(LANG_ALARM_WAKEUP_SCREEN),
134 &global_settings.alarm_wake_up_screen,
135 INT, items, i, NULL);
138 MENUITEM_FUNCTION(alarm_wake_up_screen, 0, ID2P(LANG_ALARM_WAKEUP_SCREEN),
139 alarm_setting, NULL, alarm_callback, Icon_Menu_setting);
140 #endif /* CONFIG_TUNER || defined(HAVE_RECORDING) */
142 #endif /* HAVE_RTC_ALARM */
143 static void talk_timedate(void)
145 struct tm *tm = get_time();
146 if (!global_settings.talk_menu)
147 return;
148 talk_id(VOICE_CURRENT_TIME, false);
149 if (valid_time(tm))
151 talk_time(tm, true);
152 talk_date(get_time(), true);
154 else
156 talk_id(LANG_UNKNOWN, true);
160 static void draw_timedate(struct viewport *vp, struct screen *display)
162 struct tm *tm = get_time();
163 int line;
164 char time[16], date[16];
165 const char *t = time, *d = date;
166 if (vp->height == 0)
167 return;
168 display->set_viewport(vp);
169 display->clear_viewport();
170 if (viewport_get_nb_lines(vp) >= 4)
171 line = 1;
172 else
173 line = 0;
175 if (valid_time(tm))
177 snprintf(time, sizeof(time), "%02d:%02d:%02d%s",
178 global_settings.timeformat == 0 ? tm->tm_hour :
179 ((tm->tm_hour + 11) % 12) + 1,
180 tm->tm_min,
181 tm->tm_sec,
182 global_settings.timeformat == 0 ? "" :
183 tm->tm_hour>11 ? " P" : " A");
184 snprintf(date, sizeof(date), "%s %d %d",
185 str(LANG_MONTH_JANUARY + tm->tm_mon),
186 tm->tm_mday,
187 tm->tm_year+1900);
189 else
191 t = "--:--:--";
192 d = str(LANG_UNKNOWN);
195 display->puts(0, line++, t);
196 display->puts(0, line, d);
198 display->update_viewport();
199 display->set_viewport(NULL);
203 static struct viewport clock_vps[NB_SCREENS], menu[NB_SCREENS];
204 static bool menu_was_pressed;
205 static int time_menu_callback(int action,
206 const struct menu_item_ex *this_item)
208 (void)this_item;
209 int i;
210 static int last_redraw = 0;
211 bool redraw = false;
213 if (TIME_BEFORE(last_redraw+HZ/2, current_tick))
214 redraw = true;
215 switch (action)
217 case ACTION_REDRAW:
218 redraw = true;
219 break;
220 case ACTION_STD_CONTEXT:
221 talk_timedate();
222 action = ACTION_NONE;
223 break;
224 /* need to tell do_menu() to return, but then get time_screen()
225 to return 0! ACTION_STD_MENU will return GO_TO_PREVIOUS from here
226 so check do_menu()'s return val and menu_was_pressed */
227 case ACTION_STD_MENU:
228 menu_was_pressed = true;
229 break;
231 if (redraw)
233 last_redraw = current_tick;
234 FOR_NB_SCREENS(i)
235 draw_timedate(&clock_vps[i], &screens[i]);
237 return action;
241 MAKE_MENU(time_menu, ID2P(LANG_TIME_MENU), time_menu_callback, Icon_NOICON,
242 &time_set, &sleep_timer_call,
243 #ifdef HAVE_RTC_ALARM
244 &alarm_screen_call,
245 #if defined(HAVE_RECORDING) || CONFIG_TUNER
246 &alarm_wake_up_screen,
247 #endif
248 #endif
249 &timeformat);
251 int time_screen(void* ignored)
253 (void)ignored;
254 int i, nb_lines, font_h, ret;
255 menu_was_pressed = false;
257 FOR_NB_SCREENS(i)
259 viewport_set_defaults(&clock_vps[i], i);
260 #ifdef HAVE_BUTTONBAR
261 if (global_settings.buttonbar)
263 clock_vps[i].height -= BUTTONBAR_HEIGHT;
265 #endif
266 nb_lines = viewport_get_nb_lines(&clock_vps[i]);
268 menu[i] = clock_vps[i];
269 /* force time to be drawn centered */
270 clock_vps[i].flags |= VP_FLAG_ALIGN_CENTER;
272 font_h = font_get(clock_vps[i].font)->height;
273 nb_lines -= 2; /* at least 2 lines for menu */
274 if (nb_lines > 4)
275 nb_lines = 4;
276 if (nb_lines >= 2)
277 clock_vps[i].height = nb_lines*font_h;
278 else /* disable the clock_vps drawing */
279 clock_vps[i].height = 0;
280 menu[i].y += clock_vps[i].height;
281 menu[i].height -= clock_vps[i].height;
282 draw_timedate(&clock_vps[i], &screens[i]);
285 ret = do_menu(&time_menu, NULL, menu, false);
286 /* see comments above in the button callback */
287 if (!menu_was_pressed && ret == GO_TO_PREVIOUS)
288 return 0;
289 return ret;