Added char rockboxdir[] containing the directory /.rockbox/ where we should
[kugel-rb.git] / apps / settings.c
blob8835ac8653255813bd4ccad92e5bc3622e93efc6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by wavey@wavey.org
11 * RTC config saving code (C) 2002 by hessu@hes.iki.fi
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
21 #include <stdio.h>
22 #include "config.h"
23 #include "kernel.h"
24 #include "settings.h"
25 #include "disk.h"
26 #include "panic.h"
27 #include "debug.h"
28 #include "button.h"
29 #include "lcd.h"
30 #include "mpeg.h"
31 #include "string.h"
32 #include "ata.h"
33 #include "fat.h"
34 #include "power.h"
35 #include "backlight.h"
36 #include "powermgmt.h"
37 #include "status.h"
38 #ifdef HAVE_LCD_BITMAP
39 #include "icons.h"
40 #endif
42 struct user_settings global_settings;
43 char rockboxdir[] = "/.rockbox/"; /* config/font/data file directory */
45 #define CONFIG_BLOCK_VERSION 1
46 #define CONFIG_BLOCK_SIZE 512
47 #define RTC_BLOCK_SIZE 44
49 /********************************************
51 Config block as saved on the battery-packed RTC user RAM memory block
52 of 44 bytes, starting at offset 0x14 of the RTC memory space.
54 offset abs
55 0x00 0x14 "Roc" header signature: 0x52 0x6f 0x63
56 0x03 0x17 <version byte: 0x0>
57 0x04 0x18 <volume byte>
58 0x05 0x19 <balance byte>
59 0x06 0x1a <bass byte>
60 0x07 0x1b <treble byte>
61 0x08 0x1c <loudness byte>
62 0x09 0x1d <bass boost byte>
63 0x0a 0x1e <contrast byte>
64 0x0b 0x1f <backlight byte>
65 0x0c 0x20 <poweroff timer byte>
66 0x0d 0x21 <resume settings byte>
67 0x0e 0x22 <shuffle,mp3filter,sort_case,discharge,statusbar,show_hidden>
68 0x0f 0x23 <scroll speed & WPS display byte>
69 0x10 0x24 <ff/rewind accleration rate>
70 0x11 0x25 <AVC byte>
71 0x12 0x26 <(int) Resume playlist index, or -1 if no playlist resume>
72 0x16 0x2a <(int) Byte offset into resume file>
73 0x1a 0x2e <time until disk spindown>
75 <all unused space filled with 0xff>
77 the geeky but useless statistics part:
78 0x24 <total uptime in seconds: 32 bits uint, actually unused for now>
80 0x2a <checksum 2 bytes: xor of 0x0-0x29>
82 Config memory is reset to 0xff and initialized with 'factory defaults' if
83 a valid header & checksum is not found. Config version number is only
84 increased when information is _relocated_ or space is _reused_ so that old
85 versions can read and modify configuration changed by new versions. New
86 versions should check for the value of '0xff' in each config memory
87 location used, and reset the setting in question with a factory default if
88 needed. Memory locations not used by a given version should not be
89 modified unless the header & checksum test fails.
92 Rest of config block, only saved to disk:
94 0xF8 (int) Playlist shuffle seed
95 0xFC (char[260]) Resume playlist (path/to/dir or path/to/playlist.m3u)
97 *************************************/
99 #include "rtc.h"
100 static unsigned char config_block[CONFIG_BLOCK_SIZE];
103 * Calculates the checksum for the config block and returns it
106 static unsigned short calculate_config_checksum(unsigned char* buf)
108 unsigned int i;
109 unsigned char cksum[2];
110 cksum[0] = cksum[1] = 0;
112 for (i=0; i < RTC_BLOCK_SIZE - 2; i+=2 ) {
113 cksum[0] ^= buf[i];
114 cksum[1] ^= buf[i+1];
117 return (cksum[0] << 8) | cksum[1];
121 * initialize the config block buffer
123 static void init_config_buffer( void )
125 DEBUGF( "init_config_buffer()\n" );
127 /* reset to 0xff - all unused */
128 memset(config_block, 0xff, CONFIG_BLOCK_SIZE);
129 /* insert header */
130 config_block[0] = 'R';
131 config_block[1] = 'o';
132 config_block[2] = 'c';
133 config_block[3] = CONFIG_BLOCK_VERSION;
137 * save the config block buffer to disk or RTC RAM
139 static int save_config_buffer( void )
141 unsigned short chksum;
142 #ifdef HAVE_RTC
143 unsigned int i;
144 #endif
146 DEBUGF( "save_config_buffer()\n" );
148 /* update the checksum in the end of the block before saving */
149 chksum = calculate_config_checksum(config_block);
150 config_block[ RTC_BLOCK_SIZE - 2 ] = chksum >> 8;
151 config_block[ RTC_BLOCK_SIZE - 1 ] = chksum & 0xff;
153 #ifdef HAVE_RTC
154 /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so
155 that it would write a number of bytes at a time since the RTC chip
156 supports that, but this will have to do for now 8-) */
157 for (i=0; i < RTC_BLOCK_SIZE; i++ ) {
158 int r = rtc_write(0x14+i, config_block[i]);
159 if (r) {
160 DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n", 14+i, r );
161 return r;
165 #endif
167 if (fat_startsector() != 0)
168 ata_delayed_write( 61, config_block);
169 else
170 return -1;
172 return 0;
176 * load the config block buffer from disk or RTC RAM
178 static int load_config_buffer( void )
180 unsigned short chksum;
181 bool correct = false;
183 #ifdef HAVE_RTC
184 unsigned int i;
185 unsigned char rtc_block[RTC_BLOCK_SIZE];
186 #endif
188 DEBUGF( "load_config_buffer()\n" );
190 if (fat_startsector() != 0) {
191 ata_read_sectors( 61, 1, config_block);
193 /* calculate the checksum, check it and the header */
194 chksum = calculate_config_checksum(config_block);
196 if (config_block[0] == 'R' &&
197 config_block[1] == 'o' &&
198 config_block[2] == 'c' &&
199 config_block[3] == CONFIG_BLOCK_VERSION &&
200 (chksum >> 8) == config_block[RTC_BLOCK_SIZE - 2] &&
201 (chksum & 0xff) == config_block[RTC_BLOCK_SIZE - 1])
203 DEBUGF( "load_config_buffer: header & checksum test ok\n" );
204 correct = true;
208 #ifdef HAVE_RTC
209 /* read rtc block */
210 for (i=0; i < RTC_BLOCK_SIZE; i++ )
211 rtc_block[i] = rtc_read(0x14+i);
213 chksum = calculate_config_checksum(rtc_block);
215 /* if rtc block is ok, use that */
216 if (rtc_block[0] == 'R' &&
217 rtc_block[1] == 'o' &&
218 rtc_block[2] == 'c' &&
219 rtc_block[3] == CONFIG_BLOCK_VERSION &&
220 (chksum >> 8) == rtc_block[RTC_BLOCK_SIZE - 2] &&
221 (chksum & 0xff) == rtc_block[RTC_BLOCK_SIZE - 1])
223 memcpy(config_block, rtc_block, RTC_BLOCK_SIZE);
224 correct = true;
226 #endif
228 if ( !correct ) {
229 /* if checksum is not valid, clear the config buffer */
230 DEBUGF( "load_config_buffer: header & checksum test failed\n" );
231 init_config_buffer();
232 return -1;
235 return 0;
239 * persist all runtime user settings to disk or RTC RAM
241 int settings_save( void )
243 DEBUGF( "settings_save()\n" );
245 /* update the config block buffer with current
246 settings and save the block in the RTC */
247 config_block[0x4] = (unsigned char)global_settings.volume;
248 config_block[0x5] = (unsigned char)global_settings.balance;
249 config_block[0x6] = (unsigned char)global_settings.bass;
250 config_block[0x7] = (unsigned char)global_settings.treble;
251 config_block[0x8] = (unsigned char)global_settings.loudness;
252 config_block[0x9] = (unsigned char)global_settings.bass_boost;
254 config_block[0xa] = (unsigned char)global_settings.contrast;
255 config_block[0xb] = (unsigned char)global_settings.backlight;
256 config_block[0xc] = (unsigned char)global_settings.poweroff;
257 config_block[0xd] = (unsigned char)global_settings.resume;
259 config_block[0xe] = (unsigned char)
260 ((global_settings.playlist_shuffle & 1) |
261 ((global_settings.mp3filter & 1) << 1) |
262 ((global_settings.sort_case & 1) << 2) |
263 ((global_settings.discharge & 1) << 3) |
264 ((global_settings.statusbar & 1) << 4) |
265 ((global_settings.show_hidden_files & 1) << 5));
267 config_block[0xf] = (unsigned char)
268 ((global_settings.scroll_speed << 3) |
269 (global_settings.wps_display & 7));
271 config_block[0x10] = (unsigned char)global_settings.ff_rewind_accel;
272 config_block[0x11] = (unsigned char)global_settings.avc;
273 config_block[0x1a] = (unsigned char)global_settings.disk_spindown;
275 memcpy(&config_block[0x12], &global_settings.resume_index, 4);
276 memcpy(&config_block[0x16], &global_settings.resume_offset, 4);
277 memcpy(&config_block[0xF8], &global_settings.resume_seed, 4);
279 memcpy(&config_block[0x24], &global_settings.total_uptime, 4);
280 strncpy(&config_block[0xFC], global_settings.resume_file, MAX_PATH);
282 DEBUGF("+Resume file %s\n",global_settings.resume_file);
283 DEBUGF("+Resume index %X offset %X\n",
284 global_settings.resume_index,
285 global_settings.resume_offset);
286 DEBUGF("+Resume shuffle %s seed %X\n",
287 global_settings.playlist_shuffle?"on":"off",
288 global_settings.resume_seed);
290 if(save_config_buffer())
292 lcd_clear_display();
293 #ifdef HAVE_LCD_CHARCELLS
294 lcd_puts(0, 0, "Save failed");
295 lcd_puts(0, 1, "Batt. low?");
296 #else
297 lcd_puts(4, 2, "Save failed");
298 lcd_puts(2, 4, "Is battery low?");
299 lcd_update();
300 #endif
301 sleep(HZ*2);
302 return -1;
304 return 0;
308 * load settings from disk or RTC RAM
310 void settings_load(void)
312 unsigned char c;
314 DEBUGF( "reload_all_settings()\n" );
316 /* populate settings with default values */
317 settings_reset();
319 /* load the buffer from the RTC (resets it to all-unused if the block
320 is invalid) and decode the settings which are set in the block */
321 if (!load_config_buffer()) {
322 if (config_block[0x4] != 0xFF)
323 global_settings.volume = config_block[0x4];
324 if (config_block[0x5] != 0xFF)
325 global_settings.balance = config_block[0x5];
326 if (config_block[0x6] != 0xFF)
327 global_settings.bass = config_block[0x6];
328 if (config_block[0x7] != 0xFF)
329 global_settings.treble = config_block[0x7];
330 if (config_block[0x8] != 0xFF)
331 global_settings.loudness = config_block[0x8];
332 if (config_block[0x9] != 0xFF)
333 global_settings.bass_boost = config_block[0x9];
335 if (config_block[0xa] != 0xFF) {
336 global_settings.contrast = config_block[0xa];
337 if ( global_settings.contrast < MIN_CONTRAST_SETTING )
338 global_settings.contrast = DEFAULT_CONTRAST_SETTING;
340 if (config_block[0xb] != 0xFF)
341 global_settings.backlight = config_block[0xb];
342 if (config_block[0xc] != 0xFF)
343 global_settings.poweroff = config_block[0xc];
344 if (config_block[0xd] != 0xFF)
345 global_settings.resume = config_block[0xd];
346 if (config_block[0xe] != 0xFF) {
347 global_settings.playlist_shuffle = config_block[0xe] & 1;
348 global_settings.mp3filter = (config_block[0xe] >> 1) & 1;
349 global_settings.sort_case = (config_block[0xe] >> 2) & 1;
350 global_settings.discharge = (config_block[0xe] >> 3) & 1;
351 global_settings.statusbar = (config_block[0xe] >> 4) & 1;
352 global_settings.show_hidden_files = (config_block[0xe] >> 5) & 1;
355 c = config_block[0xf] >> 3;
356 if (c != 31)
357 global_settings.scroll_speed = c;
359 c = config_block[0xf] & 7;
360 if (c != 7)
361 global_settings.wps_display = c;
363 if (config_block[0x10] != 0xFF)
364 global_settings.ff_rewind_accel = config_block[0x10];
366 if (config_block[0x11] != 0xFF)
367 global_settings.avc = config_block[0x11];
369 if (config_block[0x12] != 0xFF)
370 memcpy(&global_settings.resume_index, &config_block[0x12], 4);
372 if (config_block[0x16] != 0xFF)
373 memcpy(&global_settings.resume_offset, &config_block[0x16], 4);
375 if (config_block[0x1a] != 0xFF)
376 global_settings.disk_spindown = config_block[0x1a];
378 memcpy(&global_settings.resume_seed, &config_block[0xF8], 4);
380 if (config_block[0x24] != 0xFF)
381 memcpy(&global_settings.total_uptime, &config_block[0x24], 4);
383 strncpy(global_settings.resume_file, &config_block[0xFC], MAX_PATH);
384 global_settings.resume_file[MAX_PATH]=0;
386 lcd_set_contrast(global_settings.contrast);
387 lcd_scroll_speed(global_settings.scroll_speed);
388 backlight_time(global_settings.backlight);
389 ata_spindown(global_settings.disk_spindown);
390 #ifdef HAVE_CHARGE_CTRL
391 charge_restart_level = global_settings.discharge ? CHARGE_RESTART_LO : CHARGE_RESTART_HI;
392 #endif
396 * reset all settings to their default value
398 void settings_reset(void) {
400 DEBUGF( "settings_reset()\n" );
402 global_settings.volume = mpeg_sound_default(SOUND_VOLUME);
403 global_settings.balance = mpeg_sound_default(SOUND_BALANCE);
404 global_settings.bass = mpeg_sound_default(SOUND_BASS);
405 global_settings.treble = mpeg_sound_default(SOUND_TREBLE);
406 global_settings.loudness = mpeg_sound_default(SOUND_LOUDNESS);
407 global_settings.bass_boost = mpeg_sound_default(SOUND_SUPERBASS);
408 global_settings.avc = mpeg_sound_default(SOUND_AVC);
409 global_settings.resume = RESUME_ASK;
410 global_settings.contrast = DEFAULT_CONTRAST_SETTING;
411 global_settings.poweroff = DEFAULT_POWEROFF_SETTING;
412 global_settings.backlight = DEFAULT_BACKLIGHT_SETTING;
413 global_settings.wps_display = DEFAULT_WPS_DISPLAY;
414 global_settings.mp3filter = true;
415 global_settings.sort_case = false;
416 global_settings.statusbar = true;
417 global_settings.loop_playlist = true;
418 global_settings.playlist_shuffle = false;
419 global_settings.discharge = 0;
420 global_settings.total_uptime = 0;
421 global_settings.scroll_speed = 8;
422 global_settings.show_hidden_files = false;
423 global_settings.ff_rewind_accel = DEFAULT_FF_REWIND_ACCEL_SETTING;
424 global_settings.resume_index = -1;
425 global_settings.resume_offset = -1;
426 global_settings.disk_spindown = 5;
431 * dump the list of current settings
433 void settings_display(void)
435 #ifdef DEBUG
436 DEBUGF( "\nsettings_display()\n" );
438 DEBUGF( "\nvolume:\t\t%d\nbalance:\t%d\nbass:\t\t%d\ntreble:\t\t%d\nloudness:\t%d\nbass boost:\t%d\n",
439 global_settings.volume,
440 global_settings.balance,
441 global_settings.bass,
442 global_settings.treble,
443 global_settings.loudness,
444 global_settings.bass_boost );
446 DEBUGF( "contrast:\t%d\npoweroff:\t%d\nbacklight:\t%d\n",
447 global_settings.contrast,
448 global_settings.poweroff,
449 global_settings.backlight );
450 #endif
453 void set_bool(char* string, bool* variable )
455 bool done = false;
456 int button;
458 #ifdef HAVE_LCD_BITMAP
459 if(global_settings.statusbar)
460 lcd_setmargins(0, STATUSBAR_HEIGHT);
461 else
462 lcd_setmargins(0, 0);
463 #endif
464 lcd_clear_display();
465 lcd_puts_scroll(0, 0, string);
467 while ( !done ) {
468 lcd_puts(0, 1, *variable ? "on " : "off");
469 #ifdef HAVE_LCD_BITMAP
470 status_draw();
471 #endif
472 lcd_update();
474 button = button_get_w_tmo(HZ/2);
475 switch ( button ) {
476 #ifdef HAVE_RECORDER_KEYPAD
477 case BUTTON_LEFT:
478 #else
479 case BUTTON_STOP:
480 case BUTTON_MENU:
481 #endif
482 done = true;
483 break;
485 #ifdef HAVE_RECORDER_KEYPAD
486 case BUTTON_UP:
487 case BUTTON_DOWN:
488 #else
489 case BUTTON_LEFT:
490 case BUTTON_RIGHT:
491 #endif
492 if(!(button & BUTTON_REL))
493 *variable = !*variable;
494 break;
496 #ifdef HAVE_RECORDER_KEYPAD
497 case BUTTON_F3:
498 #ifdef HAVE_LCD_BITMAP
499 global_settings.statusbar = !global_settings.statusbar;
500 settings_save();
501 if(global_settings.statusbar)
502 lcd_setmargins(0, STATUSBAR_HEIGHT);
503 else
504 lcd_setmargins(0, 0);
505 lcd_clear_display();
506 lcd_puts_scroll(0, 0, string);
507 #endif
508 break;
509 #endif
512 lcd_stop_scroll();
515 void set_int(char* string,
516 char* unit,
517 int* variable,
518 void (*function)(int),
519 int step,
520 int min,
521 int max )
523 bool done = false;
525 #ifdef HAVE_LCD_BITMAP
526 if(global_settings.statusbar)
527 lcd_setmargins(0, STATUSBAR_HEIGHT);
528 else
529 lcd_setmargins(0, 0);
530 #endif
531 lcd_clear_display();
532 lcd_puts_scroll(0, 0, string);
534 while (!done) {
535 char str[32];
536 snprintf(str,sizeof str,"%d %s ", *variable, unit);
537 lcd_puts(0, 1, str);
538 #ifdef HAVE_LCD_BITMAP
539 status_draw();
540 #endif
541 lcd_update();
543 switch( button_get_w_tmo(HZ/2) ) {
544 #ifdef HAVE_RECORDER_KEYPAD
545 case BUTTON_UP:
546 case BUTTON_UP | BUTTON_REPEAT:
547 #else
548 case BUTTON_RIGHT:
549 case BUTTON_RIGHT | BUTTON_REPEAT:
550 #endif
551 *variable += step;
552 if(*variable > max )
553 *variable = max;
554 break;
556 #ifdef HAVE_RECORDER_KEYPAD
557 case BUTTON_DOWN:
558 case BUTTON_DOWN | BUTTON_REPEAT:
559 #else
560 case BUTTON_LEFT:
561 case BUTTON_LEFT | BUTTON_REPEAT:
562 #endif
563 *variable -= step;
564 if(*variable < min )
565 *variable = min;
566 break;
568 #ifdef HAVE_RECORDER_KEYPAD
569 case BUTTON_LEFT:
570 #else
571 case BUTTON_STOP:
572 case BUTTON_MENU:
573 #endif
574 done = true;
575 break;
577 #ifdef HAVE_RECORDER_KEYPAD
578 case BUTTON_F3:
579 #ifdef HAVE_LCD_BITMAP
580 global_settings.statusbar = !global_settings.statusbar;
581 settings_save();
582 if(global_settings.statusbar)
583 lcd_setmargins(0, STATUSBAR_HEIGHT);
584 else
585 lcd_setmargins(0, 0);
586 lcd_clear_display();
587 lcd_puts_scroll(0, 0, string);
588 #endif
589 break;
590 #endif
592 if ( function )
593 function(*variable);
595 lcd_stop_scroll();
598 void set_option(char* string, int* variable, char* options[], int numoptions )
600 bool done = false;
602 #ifdef HAVE_LCD_BITMAP
603 if(global_settings.statusbar)
604 lcd_setmargins(0, STATUSBAR_HEIGHT);
605 else
606 lcd_setmargins(0, 0);
607 #endif
608 lcd_clear_display();
609 lcd_puts_scroll(0, 0, string);
611 while ( !done ) {
612 lcd_puts(0, 1, options[*variable]);
613 #ifdef HAVE_LCD_BITMAP
614 status_draw();
615 #endif
616 lcd_update();
618 switch ( button_get_w_tmo(HZ/2) ) {
619 #ifdef HAVE_RECORDER_KEYPAD
620 case BUTTON_UP:
621 case BUTTON_UP | BUTTON_REPEAT:
622 #else
623 case BUTTON_RIGHT:
624 case BUTTON_RIGHT | BUTTON_REPEAT:
625 #endif
626 if ( *variable < (numoptions-1) )
627 (*variable)++;
628 break;
630 #ifdef HAVE_RECORDER_KEYPAD
631 case BUTTON_DOWN:
632 case BUTTON_DOWN | BUTTON_REPEAT:
633 #else
634 case BUTTON_LEFT:
635 case BUTTON_LEFT | BUTTON_REPEAT:
636 #endif
637 if ( *variable > 0 )
638 (*variable)--;
639 break;
641 #ifdef HAVE_RECORDER_KEYPAD
642 case BUTTON_LEFT:
643 #else
644 case BUTTON_STOP:
645 case BUTTON_MENU:
646 #endif
647 done = true;
648 break;
650 #ifdef HAVE_RECORDER_KEYPAD
651 case BUTTON_F3:
652 #ifdef HAVE_LCD_BITMAP
653 global_settings.statusbar = !global_settings.statusbar;
654 settings_save();
655 if(global_settings.statusbar)
656 lcd_setmargins(0, STATUSBAR_HEIGHT);
657 else
658 lcd_setmargins(0, 0);
659 lcd_clear_display();
660 lcd_puts_scroll(0, 0, string);
661 #endif
662 break;
663 #endif
666 lcd_stop_scroll();
669 #ifdef HAVE_RTC
670 #define INDEX_X 0
671 #define INDEX_Y 1
672 #define INDEX_WIDTH 2
673 char *dayname[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
674 char *monthname[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
675 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
676 char cursor[][3] = {{ 0, 8, 12}, {18, 8, 12}, {36, 8, 12},
677 {24, 16, 24}, {54, 16, 18}, {78, 16, 12}};
678 char daysinmonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
680 void set_time(char* string, int timedate[])
682 bool done = false;
683 int button;
684 int min = 0, steps = 0;
685 int cursorpos = 0;
686 int lastcursorpos = !cursorpos;
687 unsigned char buffer[19];
688 int realyear;
689 int julianday;
690 int i;
691 #if defined(LOADABLE_FONTS) || defined(LCD_PROPFONTS)
692 unsigned char reffub[5];
693 unsigned int width, height;
694 unsigned int separator_width, weekday_width;
695 unsigned int line_height, prev_line_height;
696 #if defined(LOADABLE_FONTS)
697 unsigned char *font = lcd_getcurrentldfont();
698 #endif
699 #endif
701 #ifdef HAVE_LCD_BITMAP
702 if(global_settings.statusbar)
703 lcd_setmargins(0, STATUSBAR_HEIGHT);
704 else
705 lcd_setmargins(0, 0);
706 #endif
707 lcd_clear_display();
708 lcd_puts_scroll(0, 0, string);
710 while ( !done ) {
711 /* calculate the number of days in febuary */
712 realyear = timedate[3] + 2000;
713 if((realyear % 4 == 0 && !(realyear % 100 == 0)) || realyear % 400 == 0)
714 daysinmonth[1] = 29;
715 else
716 daysinmonth[1] = 28;
718 /* fix day if month or year changed */
719 if (timedate[5] > daysinmonth[timedate[4] - 1])
720 timedate[5] = daysinmonth[timedate[4] - 1];
722 /* calculate day of week */
723 julianday = 0;
724 for(i = 0; i < timedate[4] - 1; i++) {
725 julianday += daysinmonth[i];
727 julianday += timedate[5];
728 timedate[6] = (realyear + julianday + (realyear - 1) / 4 -
729 (realyear - 1) / 100 + (realyear - 1) / 400 + 7 - 1) % 7;
731 snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d ",
732 timedate[0],
733 timedate[1],
734 timedate[2]);
735 lcd_puts(0, 1, buffer);
736 #if defined(LCD_PROPFONTS)
737 /* recalculate the positions and offsets */
738 lcd_getstringsize(string, 0, &width, &prev_line_height);
739 lcd_getstringsize(buffer, 0, &width, &line_height);
740 lcd_getstringsize(":", 0, &separator_width, &height);
742 strncpy(reffub, buffer, 2);
743 reffub[2] = '\0';
744 lcd_getstringsize(reffub, 0, &width, &height);
745 cursor[0][INDEX_X] = 0;
746 cursor[0][INDEX_Y] = 1 + prev_line_height + 1;
747 cursor[0][INDEX_WIDTH] = width;
749 strncpy(reffub, buffer + 3, 2);
750 reffub[2] = '\0';
751 lcd_getstringsize(reffub, 0, &width, &height);
752 cursor[1][INDEX_X] = cursor[0][INDEX_WIDTH] + separator_width;
753 cursor[1][INDEX_Y] = 1 + prev_line_height + 1;
754 cursor[1][INDEX_WIDTH] = width;
756 strncpy(reffub, buffer + 6, 2);
757 reffub[2] = '\0';
758 lcd_getstringsize(reffub, 0, &width, &height);
759 cursor[2][INDEX_X] = cursor[0][INDEX_WIDTH] + separator_width +
760 cursor[1][INDEX_WIDTH] + separator_width;
761 cursor[2][INDEX_Y] = 1 + prev_line_height + 1;
762 cursor[2][INDEX_WIDTH] = width;
764 lcd_getstringsize(buffer, 0, &width, &prev_line_height);
765 #elif defined(LOADABLE_FONTS)
766 /* recalculate the positions and offsets */
767 lcd_getstringsize(string, font, &width, &prev_line_height);
768 lcd_getstringsize(buffer, font, &width, &line_height);
769 lcd_getstringsize(":", font, &separator_width, &height);
771 strncpy(reffub, buffer, 2);
772 reffub[2] = '\0';
773 lcd_getstringsize(reffub, font, &width, &height);
774 cursor[0][INDEX_X] = 0;
775 cursor[0][INDEX_Y] = prev_line_height;
776 cursor[0][INDEX_WIDTH] = width;
778 strncpy(reffub, buffer + 3, 2);
779 reffub[2] = '\0';
780 lcd_getstringsize(reffub, font, &width, &height);
781 cursor[1][INDEX_X] = cursor[0][INDEX_WIDTH] + separator_width;
782 cursor[1][INDEX_Y] = prev_line_height;
783 cursor[1][INDEX_WIDTH] = width;
785 strncpy(reffub, buffer + 6, 2);
786 reffub[2] = '\0';
787 lcd_getstringsize(reffub, font, &width, &height);
788 cursor[2][INDEX_X] = cursor[0][INDEX_WIDTH] + separator_width +
789 cursor[1][INDEX_WIDTH] + separator_width;
790 cursor[2][INDEX_Y] = prev_line_height;
791 cursor[2][INDEX_WIDTH] = width;
793 lcd_getstringsize(buffer, font, &width, &prev_line_height);
794 #endif
796 snprintf(buffer, sizeof(buffer), "%s 20%02d %s %02d ",
797 dayname[timedate[6]],
798 timedate[3],
799 monthname[timedate[4] - 1],
800 timedate[5]);
801 lcd_puts(0, 2, buffer);
802 #if defined(LCD_PROPFONTS)
803 /* recalculate the positions and offsets */
804 lcd_getstringsize(buffer, 0, &width, &line_height);
805 strncpy(reffub, buffer, 3);
806 reffub[3] = '\0';
807 lcd_getstringsize(reffub, 0, &weekday_width, &height);
808 lcd_getstringsize(" ", 0, &separator_width, &height);
810 strncpy(reffub, buffer + 4, 4);
811 reffub[4] = '\0';
812 lcd_getstringsize(reffub, 0, &width, &height);
813 cursor[3][INDEX_X] = weekday_width + separator_width;
814 cursor[3][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height + 1;
815 cursor[3][INDEX_WIDTH] = width;
817 strncpy(reffub, buffer + 9, 3);
818 reffub[3] = '\0';
819 lcd_getstringsize(reffub, 0, &width, &height);
820 cursor[4][INDEX_X] = weekday_width + separator_width +
821 cursor[3][INDEX_WIDTH] + separator_width;
822 cursor[4][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height + 1;
823 cursor[4][INDEX_WIDTH] = width;
825 strncpy(reffub, buffer + 13, 2);
826 reffub[2] = '\0';
827 lcd_getstringsize(reffub, 0, &width, &height);
828 cursor[5][INDEX_X] = weekday_width + separator_width +
829 cursor[3][INDEX_WIDTH] + separator_width +
830 cursor[4][INDEX_WIDTH] + separator_width;
831 cursor[5][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height + 1;
832 cursor[5][INDEX_WIDTH] = width;
834 lcd_invertrect(cursor[cursorpos][INDEX_X],
835 cursor[cursorpos][INDEX_Y] + lcd_getymargin(),
836 cursor[cursorpos][INDEX_WIDTH],
837 line_height);
838 #elif defined(LOADABLE_FONTS)
839 /* recalculate the positions and offsets */
840 lcd_getstringsize(buffer, font, &width, &line_height);
841 strncpy(reffub, buffer, 3);
842 reffub[3] = '\0';
843 lcd_getstringsize(reffub, font, &weekday_width, &height);
844 lcd_getstringsize(" ", font, &separator_width, &height);
846 strncpy(reffub, buffer + 4, 4);
847 reffub[4] = '\0';
848 lcd_getstringsize(reffub, font, &width, &height);
849 cursor[3][INDEX_X] = weekday_width + separator_width;
850 cursor[3][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height;
851 cursor[3][INDEX_WIDTH] = width;
853 strncpy(reffub, buffer + 9, 3);
854 reffub[3] = '\0';
855 lcd_getstringsize(reffub, font, &width, &height);
856 cursor[4][INDEX_X] = weekday_width + separator_width +
857 cursor[3][INDEX_WIDTH] + separator_width;
858 cursor[4][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height;
859 cursor[4][INDEX_WIDTH] = width;
861 strncpy(reffub, buffer + 13, 2);
862 reffub[2] = '\0';
863 lcd_getstringsize(reffub, font, &width, &height);
864 cursor[5][INDEX_X] = weekday_width + separator_width +
865 cursor[3][INDEX_WIDTH] + separator_width +
866 cursor[4][INDEX_WIDTH] + separator_width;
867 cursor[5][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height;
868 cursor[5][INDEX_WIDTH] = width;
870 lcd_invertrect(cursor[cursorpos][INDEX_X],
871 cursor[cursorpos][INDEX_Y] + lcd_getymargin(),
872 cursor[cursorpos][INDEX_WIDTH],
873 line_height);
874 #else
875 lcd_invertrect(cursor[cursorpos][INDEX_X],
876 cursor[cursorpos][INDEX_Y] + lcd_getymargin(),
877 cursor[cursorpos][INDEX_WIDTH],
879 #endif
880 lcd_puts(0, 4, "ON to set");
881 lcd_puts(0, 5, "OFF to revert");
882 #ifdef HAVE_LCD_BITMAP
883 status_draw();
884 #endif
885 lcd_update();
887 /* calculate the minimum and maximum for the number under cursor */
888 if(cursorpos!=lastcursorpos) {
889 lastcursorpos=cursorpos;
890 switch(cursorpos) {
891 case 0: /* hour */
892 min = 0;
893 steps = 24;
894 break;
895 case 1: /* minute */
896 case 2: /* second */
897 min = 0;
898 steps = 60;
899 break;
900 case 3: /* year */
901 min = 0;
902 steps = 100;
903 break;
904 case 4: /* month */
905 min = 1;
906 steps = 12;
907 break;
908 case 5: /* day */
909 min = 1;
910 steps = daysinmonth[timedate[4] - 1];
911 break;
915 button = button_get_w_tmo(HZ/2);
916 switch ( button ) {
917 case BUTTON_LEFT:
918 cursorpos = (cursorpos + 6 - 1) % 6;
919 break;
920 case BUTTON_RIGHT:
921 cursorpos = (cursorpos + 6 + 1) % 6;
922 break;
923 case BUTTON_UP:
924 case BUTTON_UP | BUTTON_REPEAT:
925 timedate[cursorpos] = (timedate[cursorpos] + steps - min + 1) % steps + min;
926 if(timedate[cursorpos] == 0)
927 timedate[cursorpos] += min;
928 break;
929 case BUTTON_DOWN:
930 case BUTTON_DOWN | BUTTON_REPEAT:
931 timedate[cursorpos]=(timedate[cursorpos]+steps - min - 1) % steps + min;
932 if(timedate[cursorpos] == 0)
933 timedate[cursorpos] += min;
934 break;
935 case BUTTON_ON:
936 done = true;
937 if (timedate[6] == 0) /* rtc needs 1 .. 7 */
938 timedate[6] = 7;
939 break;
940 case BUTTON_OFF:
941 done = true;
942 timedate[0] = -1;
943 break;
944 #ifdef HAVE_RECORDER_KEYPAD
945 case BUTTON_F3:
946 #ifdef HAVE_LCD_BITMAP
947 global_settings.statusbar = !global_settings.statusbar;
948 settings_save();
949 if(global_settings.statusbar)
950 lcd_setmargins(0, STATUSBAR_HEIGHT);
951 else
952 lcd_setmargins(0, 0);
953 lcd_clear_display();
954 lcd_puts_scroll(0, 0, string);
955 #endif
956 break;
957 #endif
958 default:
959 break;
963 #endif