When we read the year from the RTC, it can be so totally messed up so that
[kugel-rb.git] / apps / settings.c
bloba6d31341f892b8d1f8e0157ed4a0df525b74300f
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 "thread.h"
25 #include "settings.h"
26 #include "disk.h"
27 #include "panic.h"
28 #include "debug.h"
29 #include "button.h"
30 #include "usb.h"
31 #include "backlight.h"
32 #include "lcd.h"
33 #include "mpeg.h"
34 #include "string.h"
35 #include "ata.h"
36 #include "fat.h"
37 #include "power.h"
38 #include "backlight.h"
39 #include "powermgmt.h"
40 #include "status.h"
41 #include "atoi.h"
42 #include "screens.h"
43 #include "ctype.h"
44 #include "file.h"
45 #include "errno.h"
46 #include "system.h"
47 #include "misc.h"
48 #ifdef HAVE_LCD_BITMAP
49 #include "icons.h"
50 #include "font.h"
51 #include "peakmeter.h"
52 #endif
53 #include "lang.h"
54 #include "language.h"
55 #include "wps-display.h"
56 #include "powermgmt.h"
57 #include "sprintf.h"
58 #include "keyboard.h"
59 #include "version.h"
61 struct user_settings global_settings;
62 char rockboxdir[] = ROCKBOX_DIR; /* config/font/data file directory */
64 #define CONFIG_BLOCK_VERSION 5
65 #define CONFIG_BLOCK_SIZE 512
66 #define RTC_BLOCK_SIZE 44
68 #ifdef HAVE_LCD_BITMAP
69 #define MAX_LINES 10
70 #else
71 #define MAX_LINES 2
72 #endif
74 /********************************************
76 Config block as saved on the battery-packed RTC user RAM memory block
77 of 44 bytes, starting at offset 0x14 of the RTC memory space.
79 offset abs
80 0x00 0x14 "Roc" header signature: 0x52 0x6f 0x63
81 0x03 0x17 <version byte: 0x0>
82 0x04 0x18 <volume byte>
83 0x05 0x19 <balance byte>
84 0x06 0x1a <bass byte>
85 0x07 0x1b <treble byte>
86 0x08 0x1c <loudness byte>
87 0x09 0x1d <bass boost byte>
88 0x0a 0x1e <contrast (bit 0-5), invert bit (bit 6)>
89 0x0b 0x1f <backlight_on_when_charging, invert_cursor, backlight_timeout>
90 0x0c 0x20 <poweroff timer byte>
91 0x0d 0x21 <resume settings byte>
92 0x0e 0x22 <shuffle,dirfilter,sort_case,discharge,statusbar,show_hidden,
93 scroll bar>
94 0x0f 0x23 <volume type, battery type, timeformat, scroll speed>
95 0x10 0x24 <ff/rewind min step, acceleration rate>
96 0x11 0x25 <AVC, channel config>
97 0x12 0x26 <(int) Resume playlist index, or -1 if no playlist resume>
98 0x16 0x2a <(int) Byte offset into resume file>
99 0x1a 0x2e <time until disk spindown>
100 0x1b 0x2f <browse current, play selected, queue_resume>
101 0x1c 0x30 <peak meter hold timeout (bit 0-4),
102 rec_editable (bit 7)>
103 0x1d 0x31 <(int) queue resume index>
104 0x21 0x35 <repeat mode (bit 0-1), rec. channels (bit 2),
105 mic gain (bit 4-7)>
106 0x22 0x36 <rec. quality (bit 0-2), source (bit 3-4), frequency (bit 5-7)>
107 0x23 0x37 <rec. left gain (bit 0-3)>
108 0x24 0x38 <rec. right gain (bit 0-3)>
109 0x25 0x39 <disk poweroff flag (bit 0), MP3 buffer margin (bit 1-3),
110 Trickle charge flag (bit 4)>
111 0x26 0x40 <runtime low byte>
112 0x27 0x41 <runtime high byte>
113 0x28 0x42 <topruntime low byte>
114 0x29 0x43 <topruntime high byte>
116 0x2a <checksum 2 bytes: xor of 0x0-0x29>
118 Config memory is reset to 0xff and initialized with 'factory defaults' if
119 a valid header & checksum is not found. Config version number is only
120 increased when information is _relocated_ or space is _reused_ so that old
121 versions can read and modify configuration changed by new versions. New
122 versions should check for the value of '0xff' in each config memory
123 location used, and reset the setting in question with a factory default if
124 needed. Memory locations not used by a given version should not be
125 modified unless the header & checksum test fails.
128 Rest of config block, only saved to disk:
129 0xAA Max number of files in playlist (1000-20000)
130 0xAC Max number of files in dir (50-10000)
131 0xAE fade on pause/unpause/stop setting (bit 0)
132 caption backlight (bit 1)
133 0xB0 peak meter clip hold timeout (bit 0-4), peak meter performance (bit 7)
134 0xB1 peak meter release step size, peak_meter_dbfs (bit 7)
135 0xB2 peak meter min either in -db or in percent
136 0xB3 peak meter max either in -db or in percent
137 0xB4 battery capacity
138 0xB5 scroll step in pixels
139 0xB6 scroll start and endpoint delay
140 0xB7 bidir scroll setting (bidi if 0-200% longer than screen width)
141 0xB8 (char[20]) WPS file
142 0xCC (char[20]) Lang file
143 0xE0 (char[20]) Font file
144 0xF4 (int) Playlist first index
145 0xF8 (int) Playlist shuffle seed
146 0xFC (char[260]) Resume playlist (path/to/dir or path/to/playlist.m3u)
147 0xFD (char)jump scroll mode (only for player)
148 0xFE (char)jump scroll delay (only for player)
150 *************************************/
152 #include "rtc.h"
153 static unsigned char config_block[CONFIG_BLOCK_SIZE];
156 * Calculates the checksum for the config block and returns it
159 static unsigned short calculate_config_checksum(unsigned char* buf)
161 unsigned int i;
162 unsigned char cksum[2];
163 cksum[0] = cksum[1] = 0;
165 for (i=0; i < RTC_BLOCK_SIZE - 2; i+=2 ) {
166 cksum[0] ^= buf[i];
167 cksum[1] ^= buf[i+1];
170 return (cksum[0] << 8) | cksum[1];
174 * initialize the config block buffer
176 static void init_config_buffer( void )
178 DEBUGF( "init_config_buffer()\n" );
180 /* reset to 0xff - all unused */
181 memset(config_block, 0xff, CONFIG_BLOCK_SIZE);
182 /* insert header */
183 config_block[0] = 'R';
184 config_block[1] = 'o';
185 config_block[2] = 'c';
186 config_block[3] = CONFIG_BLOCK_VERSION;
190 * save the config block buffer to disk or RTC RAM
192 static int save_config_buffer( void )
194 unsigned short chksum;
195 #ifdef HAVE_RTC
196 unsigned int i;
197 #endif
199 DEBUGF( "save_config_buffer()\n" );
201 /* update the checksum in the end of the block before saving */
202 chksum = calculate_config_checksum(config_block);
203 config_block[ RTC_BLOCK_SIZE - 2 ] = chksum >> 8;
204 config_block[ RTC_BLOCK_SIZE - 1 ] = chksum & 0xff;
206 #ifdef HAVE_RTC
207 /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so
208 that it would write a number of bytes at a time since the RTC chip
209 supports that, but this will have to do for now 8-) */
210 for (i=0; i < RTC_BLOCK_SIZE; i++ ) {
211 int r = rtc_write(0x14+i, config_block[i]);
212 if (r) {
213 DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n",
214 14+i, r );
215 return r;
219 #endif
221 if (fat_startsector() != 0)
222 ata_delayed_write( 61, config_block);
223 else
224 return -1;
226 return 0;
230 * load the config block buffer from disk or RTC RAM
232 static int load_config_buffer( void )
234 unsigned short chksum;
235 bool correct = false;
237 #ifdef HAVE_RTC
238 unsigned int i;
239 unsigned char rtc_block[RTC_BLOCK_SIZE];
240 #endif
242 DEBUGF( "load_config_buffer()\n" );
244 if (fat_startsector() != 0) {
245 ata_read_sectors( 61, 1, config_block);
247 /* calculate the checksum, check it and the header */
248 chksum = calculate_config_checksum(config_block);
250 if (config_block[0] == 'R' &&
251 config_block[1] == 'o' &&
252 config_block[2] == 'c' &&
253 config_block[3] == CONFIG_BLOCK_VERSION &&
254 (chksum >> 8) == config_block[RTC_BLOCK_SIZE - 2] &&
255 (chksum & 0xff) == config_block[RTC_BLOCK_SIZE - 1])
257 DEBUGF( "load_config_buffer: header & checksum test ok\n" );
258 correct = true;
262 #ifdef HAVE_RTC
263 /* read rtc block */
264 for (i=0; i < RTC_BLOCK_SIZE; i++ )
265 rtc_block[i] = rtc_read(0x14+i);
267 chksum = calculate_config_checksum(rtc_block);
269 /* if rtc block is ok, use that */
270 if (rtc_block[0] == 'R' &&
271 rtc_block[1] == 'o' &&
272 rtc_block[2] == 'c' &&
273 rtc_block[3] == CONFIG_BLOCK_VERSION &&
274 (chksum >> 8) == rtc_block[RTC_BLOCK_SIZE - 2] &&
275 (chksum & 0xff) == rtc_block[RTC_BLOCK_SIZE - 1])
277 memcpy(config_block, rtc_block, RTC_BLOCK_SIZE);
278 correct = true;
280 #endif
282 if ( !correct ) {
283 /* if checksum is not valid, clear the config buffer */
284 DEBUGF( "load_config_buffer: header & checksum test failed\n" );
285 init_config_buffer();
286 return -1;
289 return 0;
293 * persist all runtime user settings to disk or RTC RAM
295 int settings_save( void )
297 DEBUGF( "settings_save()\n" );
299 /* update the config block buffer with current
300 settings and save the block in the RTC */
301 config_block[0x4] = (unsigned char)global_settings.volume;
302 config_block[0x5] = (char)global_settings.balance;
303 config_block[0x6] = (unsigned char)global_settings.bass;
304 config_block[0x7] = (unsigned char)global_settings.treble;
305 config_block[0x8] = (unsigned char)global_settings.loudness;
306 config_block[0x9] = (unsigned char)global_settings.bass_boost;
308 config_block[0xa] = (unsigned char)
309 ((global_settings.contrast & 0x3f) |
310 (global_settings.invert ? 0x40 : 0));
312 config_block[0xb] = (unsigned char)
313 ((global_settings.backlight_on_when_charging?0x40:0) |
314 (global_settings.invert_cursor ? 0x20 : 0) |
315 (global_settings.backlight_timeout & 0x1f));
316 config_block[0xc] = (unsigned char)global_settings.poweroff;
317 config_block[0xd] = (unsigned char)global_settings.resume;
319 config_block[0xe] = (unsigned char)
320 ((global_settings.playlist_shuffle & 1) |
321 ((global_settings.dirfilter & 1) << 1) |
322 ((global_settings.sort_case & 1) << 2) |
323 ((global_settings.discharge & 1) << 3) |
324 ((global_settings.statusbar & 1) << 4) |
325 ((global_settings.dirfilter & 2) << 4) |
326 ((global_settings.scrollbar & 1) << 6));
328 config_block[0xf] = (unsigned char)
329 ((global_settings.volume_type & 1) |
330 ((global_settings.battery_type & 1) << 1) |
331 ((global_settings.timeformat & 1) << 2) |
332 ( global_settings.scroll_speed << 3));
334 config_block[0x10] = (unsigned char)
335 ((global_settings.ff_rewind_min_step & 15) << 4 |
336 (global_settings.ff_rewind_accel & 15));
338 config_block[0x11] = (unsigned char)
339 ((global_settings.avc & 0x03) |
340 ((global_settings.channel_config & 0x07) << 2));
342 memcpy(&config_block[0x12], &global_settings.resume_index, 4);
343 memcpy(&config_block[0x16], &global_settings.resume_offset, 4);
345 config_block[0x1a] = (unsigned char)global_settings.disk_spindown;
346 config_block[0x1b] = (unsigned char)
347 (((global_settings.browse_current & 1)) |
348 ((global_settings.play_selected & 1) << 1) |
349 ((global_settings.queue_resume & 3) << 2));
351 config_block[0x1c] = (unsigned char)global_settings.peak_meter_hold |
352 (global_settings.rec_editable?0x80:0);
354 memcpy(&config_block[0x1d], &global_settings.queue_resume_index, 4);
356 config_block[0x21] = (unsigned char)
357 ((global_settings.repeat_mode & 3) |
358 ((global_settings.rec_channels & 1) << 2) |
359 ((global_settings.rec_mic_gain & 0x0f) << 4));
360 config_block[0x22] = (unsigned char)
361 ((global_settings.rec_quality & 7) |
362 ((global_settings.rec_source & 1) << 3) |
363 ((global_settings.rec_frequency & 7) << 5));
364 config_block[0x23] = (unsigned char)global_settings.rec_left_gain;
365 config_block[0x24] = (unsigned char)global_settings.rec_right_gain;
366 config_block[0x25] = (unsigned char)
367 ((global_settings.disk_poweroff & 1) |
368 ((global_settings.buffer_margin & 7) << 1) |
369 ((global_settings.trickle_charge & 1) << 4));
372 static long lasttime = 0;
374 global_settings.runtime += (current_tick - lasttime) / HZ;
375 lasttime = current_tick;
377 if ( global_settings.runtime > global_settings.topruntime )
378 global_settings.topruntime = global_settings.runtime;
380 config_block[0x26]=(unsigned char)(global_settings.runtime & 0xff);
381 config_block[0x27]=(unsigned char)(global_settings.runtime >> 8);
382 config_block[0x28]=(unsigned char)(global_settings.topruntime & 0xff);
383 config_block[0x29]=(unsigned char)(global_settings.topruntime >> 8);
386 config_block[0xaa] = (unsigned char)
387 global_settings.max_files_in_playlist & 0xff;
388 config_block[0xab] = (unsigned char)
389 (global_settings.max_files_in_playlist >> 8) & 0xff;
390 config_block[0xac] = (unsigned char)
391 global_settings.max_files_in_dir & 0xff;
392 config_block[0xad] = (unsigned char)
393 (global_settings.max_files_in_dir >> 8) & 0xff;
394 config_block[0xae] = (unsigned char)
395 ((global_settings.fade_on_stop & 1) |
396 ((global_settings.caption_backlight & 1) << 1));
397 config_block[0xb0] = (unsigned char)global_settings.peak_meter_clip_hold |
398 (global_settings.peak_meter_performance ? 0x80 : 0);
399 config_block[0xb1] = global_settings.peak_meter_release |
400 (global_settings.peak_meter_dbfs ? 0x80 : 0);
401 config_block[0xb2] = (unsigned char)global_settings.peak_meter_min;
402 config_block[0xb3] = (unsigned char)global_settings.peak_meter_max;
404 config_block[0xb4]=(global_settings.battery_capacity - 1000) / 50;
405 config_block[0xb5]=(unsigned char)global_settings.scroll_step;
406 config_block[0xb6]=(unsigned char)global_settings.scroll_delay;
407 config_block[0xb7]=(unsigned char)global_settings.bidir_limit;
409 strncpy(&config_block[0xb8], global_settings.wps_file, MAX_FILENAME);
410 strncpy(&config_block[0xcc], global_settings.lang_file, MAX_FILENAME);
411 strncpy(&config_block[0xe0], global_settings.font_file, MAX_FILENAME);
412 memcpy(&config_block[0xF4], &global_settings.resume_first_index, 4);
413 memcpy(&config_block[0xF8], &global_settings.resume_seed, 4);
415 strncpy(&config_block[0xFC], global_settings.resume_file, MAX_PATH);
416 #ifdef HAVE_LCD_CHARCELLS
417 config_block[0xfd]=(unsigned char)global_settings.jump_scroll;
418 config_block[0xfe]=(unsigned char)global_settings.jump_scroll_delay;
419 #endif
420 DEBUGF( "+Resume file %s\n",global_settings.resume_file );
421 DEBUGF( "+Resume index %X offset %X\n",
422 global_settings.resume_index,
423 global_settings.resume_offset );
424 DEBUGF( "+Resume shuffle %s seed %X\n",
425 global_settings.playlist_shuffle?"on":"off",
426 global_settings.resume_seed );
428 if(save_config_buffer())
430 lcd_clear_display();
431 #ifdef HAVE_LCD_CHARCELLS
432 lcd_puts(0, 0, str(LANG_SETTINGS_SAVE_PLAYER));
433 lcd_puts(0, 1, str(LANG_SETTINGS_BATTERY_PLAYER));
434 #else
435 lcd_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
436 lcd_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
437 lcd_update();
438 #endif
439 sleep(HZ*2);
440 return -1;
442 return 0;
445 #ifdef HAVE_LCD_BITMAP
447 * Applies the range infos stored in global_settings to
448 * the peak meter.
450 void settings_apply_pm_range(void)
452 int pm_min, pm_max;
454 /* depending on the scale mode (dBfs or percent) the values
455 of global_settings.peak_meter_dbfs have different meanings */
456 if (global_settings.peak_meter_dbfs)
458 /* convert to dBfs * 100 */
459 pm_min = -(((int)global_settings.peak_meter_min) * 100);
460 pm_max = -(((int)global_settings.peak_meter_max) * 100);
462 else
464 /* percent is stored directly -> no conversion */
465 pm_min = global_settings.peak_meter_min;
466 pm_max = global_settings.peak_meter_max;
469 /* apply the range */
470 peak_meter_init_range(global_settings.peak_meter_dbfs, pm_min, pm_max);
472 #endif /* HAVE_LCD_BITMAP */
474 void settings_apply(void)
476 char buf[64];
478 mpeg_sound_set(SOUND_BASS, global_settings.bass);
479 mpeg_sound_set(SOUND_TREBLE, global_settings.treble);
480 mpeg_sound_set(SOUND_BALANCE, global_settings.balance);
481 mpeg_sound_set(SOUND_VOLUME, global_settings.volume);
482 mpeg_sound_set(SOUND_CHANNELS, global_settings.channel_config);
483 #ifdef HAVE_MAS3587F
484 mpeg_sound_set(SOUND_LOUDNESS, global_settings.loudness);
485 mpeg_sound_set(SOUND_SUPERBASS, global_settings.bass_boost);
486 mpeg_sound_set(SOUND_AVC, global_settings.avc);
487 #endif
489 lcd_set_contrast(global_settings.contrast);
490 lcd_scroll_speed(global_settings.scroll_speed);
491 backlight_set_timeout(global_settings.backlight_timeout);
492 backlight_set_on_when_charging(global_settings.backlight_on_when_charging);
493 ata_spindown(global_settings.disk_spindown);
495 #ifdef HAVE_ATA_POWER_OFF
496 ata_poweroff(global_settings.disk_poweroff);
497 #endif
499 set_poweroff_timeout(global_settings.poweroff);
500 #ifdef HAVE_CHARGE_CTRL
501 charge_restart_level = global_settings.discharge ?
502 CHARGE_RESTART_LO : CHARGE_RESTART_HI;
503 enable_trickle_charge(global_settings.trickle_charge);
504 #endif
506 set_battery_capacity(global_settings.battery_capacity);
508 #ifdef HAVE_LCD_BITMAP
509 lcd_set_invert_display(global_settings.invert);
510 settings_apply_pm_range();
511 peak_meter_init_times(
512 global_settings.peak_meter_release, global_settings.peak_meter_hold,
513 global_settings.peak_meter_clip_hold);
514 #endif
516 if ( global_settings.wps_file[0] &&
517 global_settings.wps_file[0] != 0xff ) {
518 snprintf(buf, sizeof buf, ROCKBOX_DIR "/%s.wps",
519 global_settings.wps_file);
520 wps_load(buf, false);
522 else
523 wps_reset();
525 #ifdef HAVE_LCD_BITMAP
526 if ( global_settings.font_file[0] &&
527 global_settings.font_file[0] != 0xff ) {
528 snprintf(buf, sizeof buf, ROCKBOX_DIR "/%s.fnt",
529 global_settings.font_file);
530 font_load(buf);
532 else
533 font_reset();
535 lcd_scroll_step(global_settings.scroll_step);
536 #else
537 lcd_jump_scroll(global_settings.jump_scroll);
538 lcd_jump_scroll_delay(global_settings.jump_scroll_delay);
539 #endif
540 lcd_bidir_scroll(global_settings.bidir_limit);
541 lcd_scroll_delay(global_settings.scroll_delay * (HZ/10));
543 if ( global_settings.lang_file[0] &&
544 global_settings.lang_file[0] != 0xff ) {
545 snprintf(buf, sizeof buf, ROCKBOX_DIR "/%s.lng",
546 global_settings.lang_file);
547 lang_load(buf);
552 * load settings from disk or RTC RAM
554 void settings_load(void)
557 DEBUGF( "reload_all_settings()\n" );
559 /* populate settings with default values */
560 settings_reset();
562 /* load the buffer from the RTC (resets it to all-unused if the block
563 is invalid) and decode the settings which are set in the block */
564 if (!load_config_buffer()) {
565 if (config_block[0x4] != 0xFF)
566 global_settings.volume = config_block[0x4];
567 if (config_block[0x5] != 0xFF)
568 global_settings.balance = (char)config_block[0x5];
569 if (config_block[0x6] != 0xFF)
570 global_settings.bass = config_block[0x6];
571 if (config_block[0x7] != 0xFF)
572 global_settings.treble = config_block[0x7];
573 if (config_block[0x8] != 0xFF)
574 global_settings.loudness = config_block[0x8];
575 if (config_block[0x9] != 0xFF)
576 global_settings.bass_boost = config_block[0x9];
578 if (config_block[0xa] != 0xFF) {
579 global_settings.contrast = config_block[0xa] & 0x3f;
580 global_settings.invert =
581 config_block[0xa] & 0x40 ? true : false;
582 if ( global_settings.contrast < MIN_CONTRAST_SETTING )
583 global_settings.contrast = DEFAULT_CONTRAST_SETTING;
586 if (config_block[0xb] != 0xFF) {
587 /* Bit 7 is unused to be able to detect uninitialized entry */
588 global_settings.backlight_timeout = config_block[0xb] & 0x1f;
589 global_settings.invert_cursor =
590 config_block[0xb] & 0x20 ? true : false;
591 global_settings.backlight_on_when_charging =
592 config_block[0xb] & 0x40 ? true : false;
595 if (config_block[0xc] != 0xFF)
596 global_settings.poweroff = config_block[0xc];
597 if (config_block[0xd] != 0xFF)
598 global_settings.resume = config_block[0xd];
599 if (config_block[0xe] != 0xFF) {
600 global_settings.playlist_shuffle = config_block[0xe] & 1;
601 global_settings.dirfilter = (config_block[0xe] >> 1) & 1;
602 global_settings.sort_case = (config_block[0xe] >> 2) & 1;
603 global_settings.discharge = (config_block[0xe] >> 3) & 1;
604 global_settings.statusbar = (config_block[0xe] >> 4) & 1;
605 global_settings.dirfilter |= ((config_block[0xe] >> 5) & 1) << 1;
606 global_settings.scrollbar = (config_block[0xe] >> 6) & 1;
607 /* Don't use the last bit, it must be unused to detect
608 an uninitialized entry */
611 if (config_block[0xf] != 0xFF) {
612 global_settings.volume_type = config_block[0xf] & 1;
613 global_settings.battery_type = (config_block[0xf] >> 1) & 1;
614 global_settings.timeformat = (config_block[0xf] >> 2) & 1;
615 global_settings.scroll_speed = config_block[0xf] >> 3;
618 if (config_block[0x10] != 0xFF) {
619 global_settings.ff_rewind_min_step = (config_block[0x10] >> 4) & 15;
620 global_settings.ff_rewind_accel = config_block[0x10] & 15;
623 if (config_block[0x11] != 0xFF)
625 global_settings.avc = config_block[0x11] & 0x03;
626 global_settings.channel_config = (config_block[0x11] >> 2) & 0x07;
629 if (config_block[0x12] != 0xFF)
630 memcpy(&global_settings.resume_index, &config_block[0x12], 4);
632 if (config_block[0x16] != 0xFF)
633 memcpy(&global_settings.resume_offset, &config_block[0x16], 4);
635 if (config_block[0x1a] != 0xFF)
636 global_settings.disk_spindown = config_block[0x1a];
638 if (config_block[0x1b] != 0xFF) {
639 global_settings.browse_current = (config_block[0x1b]) & 1;
640 global_settings.play_selected = (config_block[0x1b] >> 1) & 1;
641 global_settings.queue_resume = (config_block[0x1b] >> 2) & 3;
644 if (config_block[0x1c] != 0xFF) {
645 global_settings.peak_meter_hold = (config_block[0x1c]) & 0x1f;
646 global_settings.rec_editable =
647 (config_block[0x1c] & 0x80)?true:false;
650 if (config_block[0x1d] != 0xFF)
651 memcpy(&global_settings.queue_resume_index, &config_block[0x1d],
654 if (config_block[0x21] != 0xFF)
656 global_settings.repeat_mode = config_block[0x21] & 3;
657 global_settings.rec_channels = (config_block[0x21] >> 2) & 1;
658 global_settings.rec_mic_gain = (config_block[0x21] >> 4) & 0x0f;
661 if (config_block[0x22] != 0xFF)
663 global_settings.rec_quality = config_block[0x22] & 7;
664 global_settings.rec_source = (config_block[0x22] >> 3) & 3;
665 global_settings.rec_frequency = (config_block[0x22] >> 5) & 7;
668 if (config_block[0x23] != 0xFF)
669 global_settings.rec_left_gain = config_block[0x23] & 0x0f;
671 if (config_block[0x24] != 0xFF)
672 global_settings.rec_right_gain = config_block[0x24] & 0x0f;
674 if (config_block[0x25] != 0xFF)
676 global_settings.disk_poweroff = config_block[0x25] & 1;
677 global_settings.buffer_margin = (config_block[0x25] >> 1) & 7;
678 global_settings.trickle_charge = (config_block[0x25] >> 4) & 1;
681 if (config_block[0x27] != 0xff)
682 global_settings.runtime =
683 config_block[0x26] | (config_block[0x27] << 8);
685 if (config_block[0x29] != 0xff)
686 global_settings.topruntime =
687 config_block[0x28] | (config_block[0x29] << 8);
689 if (config_block[0xae] != 0xff) {
690 global_settings.fade_on_stop = config_block[0xae] & 1;
691 global_settings.caption_backlight = (config_block[0xae] >> 1) & 1;
694 if(config_block[0xb0] != 0xff) {
695 global_settings.peak_meter_clip_hold = (config_block[0xb0]) & 0x1f;
696 global_settings.peak_meter_performance =
697 (config_block[0xb0] & 0x80) != 0;
700 if(config_block[0xb1] != 0xff) {
701 global_settings.peak_meter_release = config_block[0xb1] & 0x7f;
702 global_settings.peak_meter_dbfs = (config_block[0xb1] & 0x80) != 0;
705 if(config_block[0xb2] != 0xff)
706 global_settings.peak_meter_min = config_block[0xb2];
708 if(config_block[0xb3] != 0xff)
709 global_settings.peak_meter_max = config_block[0xb3];
711 if(config_block[0xb4] != 0xff)
712 global_settings.battery_capacity = config_block[0xb4]*50 + 1000;
714 if (config_block[0xb5] != 0xff)
715 global_settings.scroll_step = config_block[0xb5];
717 if (config_block[0xb6] != 0xff)
718 global_settings.scroll_delay = config_block[0xb6];
720 if (config_block[0xb7] != 0xff)
721 global_settings.bidir_limit = config_block[0xb7];
723 if (config_block[0xac] != 0xff)
724 global_settings.max_files_in_dir =
725 config_block[0xac] | (config_block[0xad] << 8);
727 if (config_block[0xaa] != 0xff)
728 global_settings.max_files_in_playlist =
729 config_block[0xaa] | (config_block[0xab] << 8);
731 memcpy(&global_settings.resume_first_index, &config_block[0xF4], 4);
732 memcpy(&global_settings.resume_seed, &config_block[0xF8], 4);
734 strncpy(global_settings.wps_file, &config_block[0xb8], MAX_FILENAME);
735 strncpy(global_settings.lang_file, &config_block[0xcc], MAX_FILENAME);
736 strncpy(global_settings.font_file, &config_block[0xe0], MAX_FILENAME);
737 strncpy(global_settings.resume_file, &config_block[0xFC], MAX_PATH);
738 #ifdef HAVE_LCD_CHARSCELLS
739 if (config_block[0xfd] != 0xff)
740 global_settings.jump_scroll = config_block[0xfd];
741 if (config_block[0xfe] != 0xff)
742 global_settings.jump_scroll_delay = config_block[0xfe];
743 #endif
744 global_settings.resume_file[MAX_PATH]=0;
747 settings_apply();
750 /* parse a line from a configuration file. the line format is:
752 setting name: setting value
754 Any whitespace before setting name or value (after ':') is ignored.
755 A # as first non-whitespace character discards the whole line.
756 Function sets pointers to null-terminated setting name and value.
757 Returns false if no valid config entry was found.
760 static bool settings_parseline(char* line, char** name, char** value)
762 char* ptr;
764 while ( isspace(*line) )
765 line++;
767 if ( *line == '#' )
768 return false;
770 ptr = strchr(line, ':');
771 if ( !ptr )
772 return false;
774 *name = line;
775 *ptr = 0;
776 ptr++;
777 while (isspace(*ptr))
778 ptr++;
779 *value = ptr;
780 return true;
783 void set_file(char* filename, char* setting, int maxlen)
785 char* fptr = strrchr(filename,'/');
786 int len;
787 int extlen = 0;
788 char* ptr;
790 if (!fptr)
791 return;
793 *fptr = 0;
794 fptr++;
796 len = strlen(fptr);
797 ptr = fptr + len;
798 while (*ptr != '.') {
799 extlen++;
800 ptr--;
803 if (strcmp(ROCKBOX_DIR, filename) || (len-extlen > maxlen))
804 return;
806 strncpy(setting, fptr, len-extlen);
807 setting[len-extlen]=0;
809 settings_save();
812 static void set_sound(char* value, int type, int* setting)
814 int num = atoi(value);
816 num = mpeg_phys2val(type, num);
818 if ((num > mpeg_sound_max(type)) ||
819 (num < mpeg_sound_min(type)))
821 num = mpeg_sound_default(type);
824 *setting = num;
825 mpeg_sound_set(type, num);
827 #ifdef HAVE_MAS3507D
828 /* This is required to actually apply balance */
829 if (SOUND_BALANCE == type)
830 mpeg_sound_set(SOUND_VOLUME, global_settings.volume);
831 #endif
834 static void set_cfg_bool(bool* variable, char* value)
836 /* look for the 'n' in 'on' */
837 if ((value[1] & 0xdf) == 'N')
838 *variable = true;
839 else
840 *variable = false;
843 static void set_cfg_int(int* variable, char* value, int min, int max )
845 *variable = atoi(value);
847 if (*variable < min)
848 *variable = min;
849 else
850 if (*variable > max)
851 *variable = max;
854 static void set_cfg_option(int* variable, char* value,
855 char* options[], int numoptions )
857 int i;
859 for (i=0; i<numoptions; i++) {
860 if (!strcasecmp(options[i], value)) {
861 *variable = i;
862 break;
867 bool settings_load_config(char* file)
869 int fd;
870 char line[128];
872 fd = open(file, O_RDONLY);
873 if (fd < 0)
874 return false;
876 while (read_line(fd, line, sizeof line) > 0)
878 char* name;
879 char* value;
881 if (!settings_parseline(line, &name, &value))
882 continue;
884 if (!strcasecmp(name, "volume"))
885 set_sound(value, SOUND_VOLUME, &global_settings.volume);
886 else if (!strcasecmp(name, "bass"))
887 set_sound(value, SOUND_BASS, &global_settings.bass);
888 else if (!strcasecmp(name, "treble"))
889 set_sound(value, SOUND_TREBLE, &global_settings.treble);
890 else if (!strcasecmp(name, "balance"))
891 set_sound(value, SOUND_BALANCE, &global_settings.balance);
892 else if (!strcasecmp(name, "channels")) {
893 static char* options[] = {
894 "stereo","stereo narrow","mono","mono left",
895 "mono right","karaoke","stereo wide"};
896 set_cfg_option(&global_settings.channel_config, value,
897 options, 7);
899 else if (!strcasecmp(name, "wps")) {
900 if (wps_load(value,false))
901 set_file(value, global_settings.wps_file, MAX_FILENAME);
903 else if (!strcasecmp(name, "lang")) {
904 if (!lang_load(value))
905 set_file(value, global_settings.lang_file, MAX_FILENAME);
907 else if (!strcasecmp(name, "bidir limit"))
908 set_cfg_int(&global_settings.bidir_limit, value, 0, 200);
909 #ifdef HAVE_LCD_BITMAP
910 else if (!strcasecmp(name, "font")) {
911 if (font_load(value))
912 set_file(value, global_settings.font_file, MAX_FILENAME);
914 else if (!strcasecmp(name, "scroll step"))
915 set_cfg_int(&global_settings.scroll_step, value, 1, LCD_WIDTH);
916 else if (!strcasecmp(name, "statusbar"))
917 set_cfg_bool(&global_settings.statusbar, value);
918 else if (!strcasecmp(name, "peak meter release"))
919 set_cfg_int(&global_settings.peak_meter_release, value, 1, 0x7e);
920 else if (!strcasecmp(name, "peak meter hold")) {
921 static char* options[] = {
922 "off","200ms","300ms","500ms",
923 "1","2","3","4","5","6","7","8","9","10",
924 "15","20","30","1min"};
925 set_cfg_option(&global_settings.peak_meter_hold, value,
926 options, 18);
928 else if (!strcasecmp(name, "peak meter clip hold")) {
929 static char* options[] = {
930 "on","1","2","3","4","5","6","7","8","9","10",
931 "15","20","25","30","45","60","90",
932 "2min","3min","5min","10min","20min","45min","90min"};
933 set_cfg_option(&global_settings.peak_meter_clip_hold, value,
934 options, 25);
936 else if (!strcasecmp(name, "peak meter dbfs"))
937 set_cfg_bool(&global_settings.peak_meter_dbfs, value);
938 else if (!strcasecmp(name, "peak meter min"))
939 set_cfg_int(&global_settings.peak_meter_min, value, 0, 100);
940 else if (!strcasecmp(name, "peak meter max"))
941 set_cfg_int(&global_settings.peak_meter_max, value, 0, 100);
942 else if (!strcasecmp(name, "peak meter busy"))
943 set_cfg_bool(&global_settings.peak_meter_performance, value);
944 else if (!strcasecmp(name, "volume display")) {
945 static char* options[] = {"graphic", "numeric"};
946 set_cfg_option(&global_settings.volume_type, value, options, 2);
948 else if (!strcasecmp(name, "battery display")) {
949 static char* options[] = {"graphic", "numeric"};
950 set_cfg_option(&global_settings.battery_type, value, options, 2);
952 else if (!strcasecmp(name, "time format")) {
953 static char* options[] = {"24hour", "12hour"};
954 set_cfg_option(&global_settings.timeformat, value, options, 2);
956 else if (!strcasecmp(name, "scrollbar"))
957 set_cfg_bool(&global_settings.scrollbar, value);
958 else if (!strcasecmp(name, "invert"))
959 set_cfg_bool(&global_settings.invert, value);
960 else if (!strcasecmp(name, "invert cursor"))
961 set_cfg_bool(&global_settings.invert_cursor, value);
962 #endif
963 else if (!strcasecmp(name, "caption backlight"))
964 set_cfg_bool(&global_settings.caption_backlight, value);
965 else if (!strcasecmp(name, "shuffle"))
966 set_cfg_bool(&global_settings.playlist_shuffle, value);
967 else if (!strcasecmp(name, "repeat")) {
968 static char* options[] = {"off", "all", "one"};
969 set_cfg_option(&global_settings.repeat_mode, value, options, 3);
971 else if (!strcasecmp(name, "resume")) {
972 static char* options[] = {"off", "ask", "ask once", "on"};
973 set_cfg_option(&global_settings.resume, value, options, 4);
975 else if (!strcasecmp(name, "sort case"))
976 set_cfg_bool(&global_settings.sort_case, value);
977 else if (!strcasecmp(name, "show files")) {
978 static char* options[] = {"all", "supported","music", "playlists"};
979 set_cfg_option(&global_settings.dirfilter, value, options, 4);
981 else if (!strcasecmp(name, "follow playlist"))
982 set_cfg_bool(&global_settings.browse_current, value);
983 else if (!strcasecmp(name, "play selected"))
984 set_cfg_bool(&global_settings.play_selected, value);
985 else if (!strcasecmp(name, "contrast"))
986 set_cfg_int(&global_settings.contrast, value,
987 0, MAX_CONTRAST_SETTING);
988 else if (!strcasecmp(name, "scroll speed"))
989 set_cfg_int(&global_settings.scroll_speed, value, 1, 10);
990 else if (!strcasecmp(name, "scan min step")) {
991 static char* options[] =
992 {"1","2","3","4","5","6","8","10",
993 "15","20","25","30","45","60"};
994 set_cfg_option(&global_settings.ff_rewind_min_step, value,
995 options, 14);
997 else if (!strcasecmp(name, "scan accel"))
998 set_cfg_int(&global_settings.ff_rewind_accel, value, 0, 15);
999 else if (!strcasecmp(name, "scroll delay"))
1000 set_cfg_int(&global_settings.scroll_delay, value, 0, 250);
1001 else if (!strcasecmp(name, "backlight timeout")) {
1002 static char* options[] = {
1003 "off","on","1","2","3","4","5","6","7","8","9",
1004 "10","15","20","25","30","45","60","90"};
1005 set_cfg_option(&global_settings.backlight_timeout, value,
1006 options, 19);
1008 else if (!strcasecmp(name, "backlight when plugged"))
1009 set_cfg_bool(&global_settings.backlight_on_when_charging, value);
1010 else if (!strcasecmp(name, "antiskip"))
1011 set_cfg_int(&global_settings.buffer_margin, value, 0, 7);
1012 else if (!strcasecmp(name, "disk spindown"))
1013 set_cfg_int(&global_settings.disk_spindown, value, 3, 254);
1014 #ifdef HAVE_ATA_POWER_OFF
1015 else if (!strcasecmp(name, "disk poweroff"))
1016 set_cfg_bool(&global_settings.disk_poweroff, value);
1017 #endif
1018 #ifdef HAVE_MAS3587F
1019 else if (!strcasecmp(name, "loudness"))
1020 set_sound(value, SOUND_LOUDNESS, &global_settings.loudness);
1021 else if (!strcasecmp(name, "bass boost"))
1022 set_sound(value, SOUND_SUPERBASS, &global_settings.bass_boost);
1023 else if (!strcasecmp(name, "auto volume")) {
1024 static char* options[] = {"off", "2", "4", "8" };
1025 set_cfg_option(&global_settings.avc, value, options, 4);
1027 else if (!strcasecmp(name, "rec mic gain"))
1028 set_sound(value, SOUND_MIC_GAIN, &global_settings.rec_mic_gain);
1029 else if (!strcasecmp(name, "rec left gain"))
1030 set_sound(value, SOUND_LEFT_GAIN, &global_settings.rec_left_gain);
1031 else if (!strcasecmp(name, "rec right gain"))
1032 set_sound(value, SOUND_RIGHT_GAIN, &global_settings.rec_right_gain);
1033 else if (!strcasecmp(name, "rec quality"))
1034 set_cfg_int(&global_settings.rec_quality, value, 0, 7);
1035 else if (!strcasecmp(name, "rec source")) {
1036 static char* options[] = {"mic", "line", "spdif"};
1037 set_cfg_option(&global_settings.rec_source, value, options, 3);
1039 else if (!strcasecmp(name, "rec frequency")) {
1040 static char* options[] = {"44", "48", "32", "22", "24", "16"};
1041 set_cfg_option(&global_settings.rec_frequency, value, options, 6);
1043 else if (!strcasecmp(name, "rec channels")) {
1044 static char* options[] = {"stereo", "mono"};
1045 set_cfg_option(&global_settings.rec_channels, value, options, 2);
1047 else if (!strcasecmp(name, "editable recordings")) {
1048 set_cfg_bool(&global_settings.rec_editable, value);
1050 #endif
1051 else if (!strcasecmp(name, "idle poweroff")) {
1052 static char* options[] = {"off","1","2","3","4","5","6","7","8",
1053 "9","10","15","30","45","60"};
1054 set_cfg_option(&global_settings.poweroff, value, options, 15);
1056 else if (!strcasecmp(name, "battery capacity"))
1057 set_cfg_int(&global_settings.battery_capacity, value,
1058 1500, BATTERY_CAPACITY_MAX);
1059 #ifdef HAVE_CHARGE_CTRL
1060 else if (!strcasecmp(name, "deep discharge"))
1061 set_cfg_bool(&global_settings.discharge, value);
1062 else if (!strcasecmp(name, "trickle charge"))
1063 set_cfg_bool(&global_settings.trickle_charge, value);
1064 #endif
1065 else if (!strcasecmp(name, "volume fade"))
1066 set_cfg_bool(&global_settings.fade_on_stop, value);
1067 else if (!strcasecmp(name, "max files in dir"))
1068 set_cfg_int(&global_settings.max_files_in_dir, value,
1069 50, 10000);
1070 else if (!strcasecmp(name, "max files in playlist"))
1071 set_cfg_int(&global_settings.max_files_in_playlist, value,
1072 1000, 20000);
1075 close(fd);
1076 settings_apply();
1077 settings_save();
1078 return true;
1082 bool settings_save_config(void)
1084 bool done = false;
1085 int fd, i, value;
1086 char filename[MAX_PATH];
1087 char* boolopt[] = {"off","on"};
1089 /* find unused filename */
1090 for (i=0; ; i++) {
1091 snprintf(filename, sizeof filename, "/.rockbox/config%02d.cfg", i);
1092 fd = open(filename, O_RDONLY);
1093 if (fd < 0)
1094 break;
1095 close(fd);
1098 /* allow user to modify filename */
1099 while (!done) {
1100 if (!kbd_input(filename, sizeof filename)) {
1101 fd = creat(filename,0);
1102 if (fd < 0) {
1103 lcd_clear_display();
1104 lcd_puts(0,0,str(LANG_FAILED));
1105 lcd_update();
1106 sleep(HZ);
1108 else
1109 done = true;
1111 else
1112 break;
1115 /* abort if file couldn't be created */
1116 if (!done) {
1117 lcd_clear_display();
1118 lcd_puts(0,0,str(LANG_RESET_DONE_CANCEL));
1119 lcd_update();
1120 sleep(HZ);
1121 return false;
1124 fprintf(fd, "# >>> .cfg file created by rockbox %s <<<\r\n", appsversion);
1125 fprintf(fd, "# >>> http://rockbox.haxx.se <<<\r\n#\r\n");
1126 fprintf(fd, "#\r\n# wps / language / font \r\n#\r\n");
1128 if (global_settings.wps_file[0] != 0)
1129 fprintf(fd, "wps: /.rockbox/%s.wps\r\n", global_settings.wps_file);
1131 if (global_settings.lang_file[0] != 0)
1132 fprintf(fd, "lang: /.rockbox/%s.lng\r\n", global_settings.lang_file);
1134 #ifdef HAVE_LCD_BITMAP
1135 if (global_settings.font_file[0] != 0)
1136 fprintf(fd, "font: /.rockbox/%s.fnt\r\n", global_settings.font_file);
1137 #endif
1139 fprintf(fd, "#\r\n# Sound settings\r\n#\r\n");
1141 value = mpeg_val2phys(SOUND_VOLUME, global_settings.volume);
1142 fprintf(fd, "volume: %d\r\n", value);
1144 value = mpeg_val2phys(SOUND_BASS, global_settings.bass);
1145 fprintf(fd, "bass: %d\r\n", value);
1147 value = mpeg_val2phys(SOUND_TREBLE, global_settings.treble);
1148 fprintf(fd, "treble: %d\r\n", value);
1150 value = mpeg_val2phys(SOUND_BALANCE, global_settings.balance);
1151 fprintf(fd, "balance: %d\r\n", value);
1154 static char* options[] =
1155 {"stereo","stereo narrow","mono","mono left",
1156 "mono right","karaoke","stereo wide"};
1157 fprintf(fd, "channels: %s\r\n",
1158 options[global_settings.channel_config]);
1161 #ifdef HAVE_MAS3587F
1162 value = mpeg_val2phys(SOUND_LOUDNESS, global_settings.loudness);
1163 fprintf(fd, "loudness: %d\r\n", value);
1165 value = mpeg_val2phys(SOUND_SUPERBASS, global_settings.bass_boost);
1166 fprintf(fd, "bass boost: %d\r\n", value);
1169 static char* options[] = {"off", "2", "4", "8" };
1170 fprintf(fd, "auto volume: %s\r\n", options[global_settings.avc]);
1172 #endif
1174 fprintf(fd, "#\r\n# Playback\r\n#\r\n");
1175 fprintf(fd, "shuffle: %s\r\n", boolopt[global_settings.playlist_shuffle]);
1178 static char* options[] = {"off", "all", "one"};
1179 fprintf(fd, "repeat: %s\r\n", options[global_settings.repeat_mode]);
1182 fprintf(fd, "play selected: %s\r\n",
1183 boolopt[global_settings.play_selected]);
1186 static char* options[] = {"off", "ask", "ask once", "on"};
1187 fprintf(fd, "resume: %s\r\n", options[global_settings.resume]);
1191 static char* options[] =
1192 {"1","2","3","4","5","6","8","10",
1193 "15","20","25","30","45","60"};
1194 fprintf(fd, "scan min step: %s\r\n",
1195 options[global_settings.ff_rewind_min_step]);
1198 fprintf(fd, "scan accel: %d\r\nantiskip: %d\r\n",
1199 global_settings.ff_rewind_accel,
1200 global_settings.buffer_margin);
1201 fprintf(fd, "volume fade: %s\r\n", boolopt[global_settings.fade_on_stop]);
1202 fprintf(fd, "#\r\n# File View\r\n#\r\n");
1203 fprintf(fd, "sort case: %s\r\n", boolopt[global_settings.sort_case]);
1206 static char* options[] = {"all", "supported","music", "playlists"};
1207 fprintf(fd, "show files: %s\r\n", options[global_settings.dirfilter]);
1210 fprintf(fd, "follow playlist: %s\r\n",
1211 boolopt[global_settings.browse_current]);
1213 fprintf(fd, "#\r\n# Display\r\n#\r\n");
1215 #ifdef HAVE_LCD_BITMAP
1216 fprintf(fd, "statusbar: %s\r\nscrollbar: %s\r\n",
1217 boolopt[global_settings.statusbar],
1218 boolopt[global_settings.scrollbar]);
1221 static char* options[] = {"graphic", "numeric"};
1222 fprintf(fd, "volume display: %s\r\nbattery display: %s\r\n",
1223 options[global_settings.volume_type],
1224 options[global_settings.battery_type]);
1226 #endif
1228 fprintf(fd, "scroll speed: %d\r\nscroll delay: %d\r\n",
1229 global_settings.scroll_speed,
1230 global_settings.scroll_delay);
1232 #ifdef HAVE_LCD_BITMAP
1233 fprintf(fd, "scroll step: %d\r\n", global_settings.scroll_step);
1234 #else
1235 fprintf(fd, "jump scroll: %d\r\n", global_settings.jump_scroll);
1236 fprintf(fd, "jump scroll delay: %d\r\n", global_settings.jump_scroll_delay);
1237 #endif
1239 fprintf(fd, "bidir limit: %d\r\n", global_settings.bidir_limit);
1242 static char* options[] =
1243 {"off","on","1","2","3","4","5","6","7","8","9",
1244 "10","15","20","25","30","45","60","90"};
1245 fprintf(fd, "backlight timeout: %s\r\n",
1246 options[global_settings.backlight_timeout]);
1249 fprintf(fd, "backlight when plugged: %s\r\n",
1250 boolopt[global_settings.backlight_on_when_charging]);
1252 fprintf(fd, "caption backlight: %s\r\n",
1253 boolopt[global_settings.caption_backlight]);
1254 fprintf(fd, "contrast: %d\r\n", global_settings.contrast);
1256 #ifdef HAVE_LCD_BITMAP
1257 fprintf(fd, "invert: %s\r\n", boolopt[global_settings.invert]);
1259 fprintf(fd, "invert cursor: %s\r\n",
1260 boolopt[global_settings.invert_cursor]);
1262 fprintf(fd, "peak meter release: %d\r\n",
1263 global_settings.peak_meter_release);
1266 static char* options[] =
1267 {"off","200ms","300ms","500ms","1","2","3","4","5",
1268 "6","7","8","9","10","15","20","30","1min"};
1269 fprintf(fd, "peak meter hold: %s\r\n",
1270 options[global_settings.peak_meter_hold]);
1274 static char* options[] =
1275 {"on","1","2","3","4","5","6","7","8","9","10","15","20","25","30",
1276 "45","60","90","2min","3min","5min","10min","20min","45min","90min"};
1277 fprintf(fd, "peak meter clip hold: %s\r\n",
1278 options[global_settings.peak_meter_clip_hold]);
1281 fprintf(fd, "peak meter busy: %s\r\npeak meter dbfs: %s\r\n",
1282 boolopt[global_settings.peak_meter_performance],
1283 boolopt[global_settings.peak_meter_dbfs]);
1285 fprintf(fd, "peak meter min: %d\r\npeak meter max: %d\r\n",
1286 global_settings.peak_meter_min,
1287 global_settings.peak_meter_max);
1288 #endif
1290 fprintf(fd, "#\r\n# System\r\n#\r\ndisk spindown: %d\r\n",
1291 global_settings.disk_spindown);
1293 #ifdef HAVE_ATA_POWER_OFF
1294 fprintf(fd, "disk poweroff: %s\r\n",
1295 boolopt[global_settings.disk_poweroff]);
1296 #endif
1298 fprintf(fd, "battery capacity: %d\r\n", global_settings.battery_capacity);
1300 #ifdef HAVE_CHARGE_CTRL
1301 fprintf(fd, "deep discharge: %s\r\ntrickle charge: %s\r\n",
1302 boolopt[global_settings.discharge],
1303 boolopt[global_settings.trickle_charge]);
1304 #endif
1306 #ifdef HAVE_LCD_BITMAP
1308 static char* options[] = {"24hour", "12hour"};
1309 fprintf(fd, "time format: %s\r\n",
1310 options[global_settings.timeformat]);
1312 #endif
1315 static char* options[] =
1316 {"off","1","2","3","4","5","6","7","8",
1317 "9","10","15","30","45","60"};
1318 fprintf(fd, "idle poweroff: %s\r\n",
1319 options[global_settings.poweroff]);
1322 #ifdef HAVE_MAS3587F
1323 fprintf(fd, "#\r\n# Recording\r\n#\r\n");
1324 fprintf(fd, "rec quality: %d\r\n", global_settings.rec_quality);
1327 static char* options[] = {"44", "48", "32", "22", "24", "16"};
1328 fprintf(fd, "rec frequency: %s\r\n",
1329 options[global_settings.rec_frequency]);
1333 static char* options[] = {"mic", "line", "spdif"};
1334 fprintf(fd, "rec source: %s\r\n", options[global_settings.rec_source]);
1338 static char* options[] = {"stereo", "mono"};
1339 fprintf(fd, "rec channels: %s\r\n",
1340 options[global_settings.rec_channels]);
1343 fprintf(fd,
1344 "rec mic gain: %d\r\nrec left gain: %d\r\nrec right gain: %d\r\n",
1345 global_settings.rec_mic_gain,
1346 global_settings.rec_left_gain,
1347 global_settings.rec_right_gain);
1349 fprintf(fd, "editable recordings: %s\r\n",
1350 boolopt[global_settings.rec_editable]);
1352 #endif
1354 fprintf(fd, "max files in dir: %d\r\n", global_settings.max_files_in_dir);
1355 fprintf(fd, "max files in playlist: %d\r\n",
1356 global_settings.max_files_in_playlist);
1358 close(fd);
1360 lcd_clear_display();
1361 lcd_puts(0,0,str(LANG_SETTINGS_SAVED1));
1362 lcd_puts(0,1,str(LANG_SETTINGS_SAVED2));
1363 lcd_update();
1364 sleep(HZ);
1365 return true;
1369 * reset all settings to their default value
1371 void settings_reset(void) {
1373 DEBUGF( "settings_reset()\n" );
1375 global_settings.volume = mpeg_sound_default(SOUND_VOLUME);
1376 global_settings.balance = mpeg_sound_default(SOUND_BALANCE);
1377 global_settings.bass = mpeg_sound_default(SOUND_BASS);
1378 global_settings.treble = mpeg_sound_default(SOUND_TREBLE);
1379 global_settings.loudness = mpeg_sound_default(SOUND_LOUDNESS);
1380 global_settings.bass_boost = mpeg_sound_default(SOUND_SUPERBASS);
1381 global_settings.avc = mpeg_sound_default(SOUND_AVC);
1382 global_settings.channel_config = mpeg_sound_default(SOUND_CHANNELS);
1383 global_settings.rec_quality = 5;
1384 global_settings.rec_source = 0; /* 0=mic */
1385 global_settings.rec_frequency = 0; /* 0=44.1kHz */
1386 global_settings.rec_channels = 0; /* 0=Stereo */
1387 global_settings.rec_mic_gain = 8;
1388 global_settings.rec_left_gain = 2; /* 0dB */
1389 global_settings.rec_right_gain = 2; /* 0dB */
1390 global_settings.rec_editable = false;
1391 global_settings.resume = RESUME_ASK;
1392 global_settings.contrast = DEFAULT_CONTRAST_SETTING;
1393 global_settings.invert = DEFAULT_INVERT_SETTING;
1394 global_settings.poweroff = DEFAULT_POWEROFF_SETTING;
1395 global_settings.backlight_timeout = DEFAULT_BACKLIGHT_TIMEOUT_SETTING;
1396 global_settings.invert_cursor = DEFAULT_INVERT_CURSOR_SETTING;
1397 global_settings.backlight_on_when_charging =
1398 DEFAULT_BACKLIGHT_ON_WHEN_CHARGING_SETTING;
1399 global_settings.battery_capacity = 1500; /* mAh */
1400 global_settings.trickle_charge = true;
1401 global_settings.dirfilter = SHOW_MUSIC;
1402 global_settings.sort_case = false;
1403 global_settings.statusbar = true;
1404 global_settings.scrollbar = true;
1405 global_settings.repeat_mode = REPEAT_ALL;
1406 global_settings.playlist_shuffle = false;
1407 global_settings.discharge = 0;
1408 global_settings.timeformat = 0;
1409 global_settings.volume_type = 0;
1410 global_settings.battery_type = 0;
1411 global_settings.scroll_speed = 8;
1412 global_settings.bidir_limit = 50;
1413 #ifdef HAVE_LCD_CHARCELLS
1414 global_settings.jump_scroll = 1;
1415 global_settings.jump_scroll_delay = 50;
1416 #endif
1417 global_settings.scroll_delay = 100;
1418 global_settings.scroll_step = 6;
1419 global_settings.ff_rewind_min_step = DEFAULT_FF_REWIND_MIN_STEP;
1420 global_settings.ff_rewind_accel = DEFAULT_FF_REWIND_ACCEL_SETTING;
1421 global_settings.resume_index = -1;
1422 global_settings.resume_offset = -1;
1423 global_settings.save_queue_resume = true;
1424 global_settings.queue_resume = 0;
1425 global_settings.queue_resume_index = -1;
1426 global_settings.disk_spindown = 5;
1427 global_settings.disk_poweroff = false;
1428 global_settings.buffer_margin = 0;
1429 global_settings.browse_current = false;
1430 global_settings.play_selected = true;
1431 global_settings.peak_meter_release = 8;
1432 global_settings.peak_meter_hold = 3;
1433 global_settings.peak_meter_clip_hold = 16;
1434 global_settings.peak_meter_dbfs = true;
1435 global_settings.peak_meter_min = 60;
1436 global_settings.peak_meter_max = 0;
1437 global_settings.peak_meter_performance = false;
1438 global_settings.wps_file[0] = 0;
1439 global_settings.font_file[0] = 0;
1440 global_settings.lang_file[0] = 0;
1441 global_settings.runtime = 0;
1442 global_settings.topruntime = 0;
1443 global_settings.fade_on_stop = true;
1444 global_settings.caption_backlight = false;
1445 global_settings.max_files_in_dir = 400;
1446 global_settings.max_files_in_playlist = 10000;
1449 bool set_bool(char* string, bool* variable )
1451 return set_bool_options(string, variable, str(LANG_SET_BOOL_YES),
1452 str(LANG_SET_BOOL_NO));
1455 bool set_bool_options(char* string, bool* variable,
1456 char* yes_str, char* no_str )
1458 char* names[] = { no_str, yes_str };
1459 int value = *variable;
1460 bool result;
1462 result = set_option(string, &value, names, 2, NULL);
1463 *variable = value;
1464 return result;
1467 bool set_int(char* string,
1468 char* unit,
1469 int* variable,
1470 void (*function)(int),
1471 int step,
1472 int min,
1473 int max )
1475 bool done = false;
1476 int button;
1477 int org_value=*variable;
1479 #ifdef HAVE_LCD_BITMAP
1480 if(global_settings.statusbar)
1481 lcd_setmargins(0, STATUSBAR_HEIGHT);
1482 else
1483 lcd_setmargins(0, 0);
1484 #endif
1486 lcd_clear_display();
1487 lcd_puts_scroll(0, 0, string);
1489 while (!done) {
1490 char str[32];
1491 snprintf(str,sizeof str,"%d %s ", *variable, unit);
1492 lcd_puts(0, 1, str);
1493 #ifdef HAVE_LCD_BITMAP
1494 status_draw(true);
1495 #endif
1496 lcd_update();
1498 button = button_get_w_tmo(HZ/2);
1499 switch(button) {
1500 #ifdef HAVE_RECORDER_KEYPAD
1501 case BUTTON_UP:
1502 case BUTTON_UP | BUTTON_REPEAT:
1503 #else
1504 case BUTTON_RIGHT:
1505 case BUTTON_RIGHT | BUTTON_REPEAT:
1506 #endif
1507 *variable += step;
1508 break;
1510 #ifdef HAVE_RECORDER_KEYPAD
1511 case BUTTON_DOWN:
1512 case BUTTON_DOWN | BUTTON_REPEAT:
1513 #else
1514 case BUTTON_LEFT:
1515 case BUTTON_LEFT | BUTTON_REPEAT:
1516 #endif
1517 *variable -= step;
1518 break;
1520 #ifdef HAVE_RECORDER_KEYPAD
1521 case BUTTON_LEFT:
1522 case BUTTON_PLAY:
1523 #else
1524 case BUTTON_PLAY:
1525 #endif
1526 done = true;
1527 break;
1529 #ifdef HAVE_RECORDER_KEYPAD
1530 case BUTTON_OFF:
1531 #else
1532 case BUTTON_STOP:
1533 case BUTTON_MENU:
1534 #endif
1535 if (*variable != org_value) {
1536 *variable=org_value;
1537 lcd_stop_scroll();
1538 lcd_puts(0, 0, str(LANG_MENU_SETTING_CANCEL));
1539 lcd_update();
1540 sleep(HZ/2);
1542 done = true;
1543 break;
1545 case SYS_USB_CONNECTED:
1546 usb_screen();
1547 return true;
1550 if(*variable > max )
1551 *variable = max;
1553 if(*variable < min )
1554 *variable = min;
1556 if ( function && button != BUTTON_NONE)
1557 function(*variable);
1559 lcd_stop_scroll();
1561 return false;
1564 bool set_option(char* string, int* variable, char* options[],
1565 int numoptions, void (*function)(int))
1567 bool done = false;
1568 int button;
1569 int org_value=*variable;
1571 #ifdef HAVE_LCD_BITMAP
1572 if(global_settings.statusbar)
1573 lcd_setmargins(0, STATUSBAR_HEIGHT);
1574 else
1575 lcd_setmargins(0, 0);
1576 #endif
1578 lcd_clear_display();
1579 lcd_puts_scroll(0, 0, string);
1581 while ( !done ) {
1582 lcd_puts(0, 1, options[*variable]);
1583 #ifdef HAVE_LCD_BITMAP
1584 status_draw(true);
1585 #endif
1586 lcd_update();
1588 button = button_get_w_tmo(HZ/2);
1589 switch (button) {
1590 #ifdef HAVE_RECORDER_KEYPAD
1591 case BUTTON_UP:
1592 case BUTTON_UP | BUTTON_REPEAT:
1593 #else
1594 case BUTTON_RIGHT:
1595 case BUTTON_RIGHT | BUTTON_REPEAT:
1596 #endif
1597 if ( *variable < (numoptions-1) )
1598 (*variable)++;
1599 else
1600 (*variable) -= (numoptions-1);
1601 break;
1603 #ifdef HAVE_RECORDER_KEYPAD
1604 case BUTTON_DOWN:
1605 case BUTTON_DOWN | BUTTON_REPEAT:
1606 #else
1607 case BUTTON_LEFT:
1608 case BUTTON_LEFT | BUTTON_REPEAT:
1609 #endif
1610 if ( *variable > 0 )
1611 (*variable)--;
1612 else
1613 (*variable) += (numoptions-1);
1614 break;
1616 #ifdef HAVE_RECORDER_KEYPAD
1617 case BUTTON_LEFT:
1618 case BUTTON_PLAY:
1619 #else
1620 case BUTTON_PLAY:
1621 #endif
1622 done = true;
1623 break;
1625 #ifdef HAVE_RECORDER_KEYPAD
1626 case BUTTON_OFF:
1627 #else
1628 case BUTTON_STOP:
1629 case BUTTON_MENU:
1630 #endif
1631 if (*variable != org_value) {
1632 *variable=org_value;
1633 lcd_stop_scroll();
1634 lcd_puts(0, 0, str(LANG_MENU_SETTING_CANCEL));
1635 lcd_update();
1636 sleep(HZ/2);
1638 done = true;
1639 break;
1641 case SYS_USB_CONNECTED:
1642 usb_screen();
1643 return true;
1646 if ( function && button != BUTTON_NONE)
1647 function(*variable);
1649 lcd_stop_scroll();
1650 return false;
1653 #ifdef HAVE_LCD_BITMAP
1654 #define INDEX_X 0
1655 #define INDEX_Y 1
1656 #define INDEX_WIDTH 2
1657 bool set_time(char* string, int timedate[])
1659 bool done = false;
1660 int button;
1661 int min = 0, steps = 0;
1662 int cursorpos = 0;
1663 int lastcursorpos = !cursorpos;
1664 unsigned char buffer[19];
1665 int realyear;
1666 int julianday;
1667 int i;
1668 unsigned char reffub[5];
1669 unsigned int width, height;
1670 unsigned int separator_width, weekday_width;
1671 unsigned int line_height, prev_line_height;
1672 int dayname[] = {LANG_WEEKDAY_SUNDAY,
1673 LANG_WEEKDAY_MONDAY,
1674 LANG_WEEKDAY_TUESDAY,
1675 LANG_WEEKDAY_WEDNESDAY,
1676 LANG_WEEKDAY_THURSDAY,
1677 LANG_WEEKDAY_FRIDAY,
1678 LANG_WEEKDAY_SATURDAY};
1679 int monthname[] = {LANG_MONTH_JANUARY,
1680 LANG_MONTH_FEBRUARY,
1681 LANG_MONTH_MARCH,
1682 LANG_MONTH_APRIL,
1683 LANG_MONTH_MAY,
1684 LANG_MONTH_JUNE,
1685 LANG_MONTH_JULY,
1686 LANG_MONTH_AUGUST,
1687 LANG_MONTH_SEPTEMBER,
1688 LANG_MONTH_OCTOBER,
1689 LANG_MONTH_NOVEMBER,
1690 LANG_MONTH_DECEMBER};
1691 char cursor[][3] = {{ 0, 8, 12}, {18, 8, 12}, {36, 8, 12},
1692 {24, 16, 24}, {54, 16, 18}, {78, 16, 12}};
1693 char daysinmonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1695 int monthname_len = 0, dayname_len = 0;
1698 #ifdef HAVE_LCD_BITMAP
1699 if(global_settings.statusbar)
1700 lcd_setmargins(0, STATUSBAR_HEIGHT);
1701 else
1702 lcd_setmargins(0, 0);
1703 #endif
1704 lcd_clear_display();
1705 lcd_puts_scroll(0, 0, string);
1707 while ( !done ) {
1708 /* calculate the number of days in febuary */
1709 realyear = timedate[3] + 2000;
1711 if(realyear > 2030)
1712 realyear = 2003; /* yeah, I believe this is now */
1714 if((realyear % 4 == 0 && !(realyear % 100 == 0)) || realyear % 400 == 0)
1715 daysinmonth[1] = 29;
1716 else
1717 daysinmonth[1] = 28;
1719 /* fix day if month or year changed */
1720 if (timedate[5] > daysinmonth[timedate[4] - 1])
1721 timedate[5] = daysinmonth[timedate[4] - 1];
1723 /* calculate day of week */
1724 julianday = 0;
1725 for(i = 0; i < timedate[4] - 1; i++) {
1726 julianday += daysinmonth[i];
1728 julianday += timedate[5];
1729 timedate[6] = (realyear + julianday + (realyear - 1) / 4 -
1730 (realyear - 1) / 100 + (realyear - 1) / 400 + 7 - 1) % 7;
1732 snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d ",
1733 timedate[0], timedate[1], timedate[2]);
1734 lcd_puts(0, 1, buffer);
1736 /* recalculate the positions and offsets */
1737 lcd_getstringsize(string, &width, &prev_line_height);
1738 lcd_getstringsize(buffer, &width, &line_height);
1739 lcd_getstringsize(":", &separator_width, &height);
1741 /* hour */
1742 strncpy(reffub, buffer, 2);
1743 reffub[2] = '\0';
1744 lcd_getstringsize(reffub, &width, &height);
1745 cursor[0][INDEX_X] = 0;
1746 cursor[0][INDEX_Y] = prev_line_height;
1747 cursor[0][INDEX_WIDTH] = width;
1749 /* minute */
1750 strncpy(reffub, buffer + 3, 2);
1751 reffub[2] = '\0';
1752 lcd_getstringsize(reffub, &width, &height);
1753 cursor[1][INDEX_X] = cursor[0][INDEX_WIDTH] + separator_width;
1754 cursor[1][INDEX_Y] = prev_line_height;
1755 cursor[1][INDEX_WIDTH] = width;
1757 /* second */
1758 strncpy(reffub, buffer + 6, 2);
1759 reffub[2] = '\0';
1760 lcd_getstringsize(reffub, &width, &height);
1761 cursor[2][INDEX_X] = cursor[0][INDEX_WIDTH] + separator_width +
1762 cursor[1][INDEX_WIDTH] + separator_width;
1763 cursor[2][INDEX_Y] = prev_line_height;
1764 cursor[2][INDEX_WIDTH] = width;
1766 lcd_getstringsize(buffer, &width, &prev_line_height);
1768 snprintf(buffer, sizeof(buffer), "%s %04d %s %02d ",
1769 str(dayname[timedate[6]]), realyear,
1770 str(monthname[timedate[4] - 1]), timedate[5]);
1771 lcd_puts(0, 2, buffer);
1773 /* recalculate the positions and offsets */
1774 lcd_getstringsize(buffer, &width, &line_height);
1776 /* store these 2 to prevent _repeated_ strlen calls */
1777 monthname_len = strlen(str(monthname[timedate[4] - 1]));
1778 dayname_len = strlen(str(dayname[timedate[6]]));
1780 /* weekday */
1781 strncpy(reffub, buffer, dayname_len);
1782 reffub[dayname_len] = '\0';
1783 lcd_getstringsize(reffub, &weekday_width, &height);
1784 lcd_getstringsize(" ", &separator_width, &height);
1786 /* year */
1787 strncpy(reffub, buffer + dayname_len + 1, 4);
1788 reffub[4] = '\0';
1789 lcd_getstringsize(reffub, &width, &height);
1790 cursor[3][INDEX_X] = weekday_width + separator_width;
1791 cursor[3][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height;
1792 cursor[3][INDEX_WIDTH] = width;
1794 /* month */
1795 strncpy(reffub, buffer + dayname_len + 6, monthname_len);
1796 reffub[monthname_len] = '\0';
1797 lcd_getstringsize(reffub, &width, &height);
1798 cursor[4][INDEX_X] = weekday_width + separator_width +
1799 cursor[3][INDEX_WIDTH] + separator_width;
1800 cursor[4][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height;
1801 cursor[4][INDEX_WIDTH] = width;
1803 /* day */
1804 strncpy(reffub, buffer + dayname_len + monthname_len + 7, 2);
1805 reffub[2] = '\0';
1806 lcd_getstringsize(reffub, &width, &height);
1807 cursor[5][INDEX_X] = weekday_width + separator_width +
1808 cursor[3][INDEX_WIDTH] + separator_width +
1809 cursor[4][INDEX_WIDTH] + separator_width;
1810 cursor[5][INDEX_Y] = cursor[0][INDEX_Y] + prev_line_height;
1811 cursor[5][INDEX_WIDTH] = width;
1813 lcd_invertrect(cursor[cursorpos][INDEX_X],
1814 cursor[cursorpos][INDEX_Y] + lcd_getymargin(),
1815 cursor[cursorpos][INDEX_WIDTH],
1816 line_height);
1818 lcd_puts(0, 4, str(LANG_TIME_SET));
1819 lcd_puts(0, 5, str(LANG_TIME_REVERT));
1820 #ifdef HAVE_LCD_BITMAP
1821 status_draw(true);
1822 #endif
1823 lcd_update();
1825 /* calculate the minimum and maximum for the number under cursor */
1826 if(cursorpos!=lastcursorpos) {
1827 lastcursorpos=cursorpos;
1828 switch(cursorpos) {
1829 case 0: /* hour */
1830 min = 0;
1831 steps = 24;
1832 break;
1833 case 1: /* minute */
1834 case 2: /* second */
1835 min = 0;
1836 steps = 60;
1837 break;
1838 case 3: /* year */
1839 min = 0;
1840 steps = 100;
1841 break;
1842 case 4: /* month */
1843 min = 1;
1844 steps = 12;
1845 break;
1846 case 5: /* day */
1847 min = 1;
1848 steps = daysinmonth[timedate[4] - 1];
1849 break;
1853 button = button_get_w_tmo(HZ/2);
1854 switch ( button ) {
1855 case BUTTON_LEFT:
1856 cursorpos = (cursorpos + 6 - 1) % 6;
1857 break;
1858 case BUTTON_RIGHT:
1859 cursorpos = (cursorpos + 6 + 1) % 6;
1860 break;
1861 case BUTTON_UP:
1862 case BUTTON_UP | BUTTON_REPEAT:
1863 timedate[cursorpos] = (timedate[cursorpos] + steps - min + 1) %
1864 steps + min;
1865 if(timedate[cursorpos] == 0)
1866 timedate[cursorpos] += min;
1867 break;
1868 case BUTTON_DOWN:
1869 case BUTTON_DOWN | BUTTON_REPEAT:
1870 timedate[cursorpos]=(timedate[cursorpos]+steps - min - 1) %
1871 steps + min;
1872 if(timedate[cursorpos] == 0)
1873 timedate[cursorpos] += min;
1874 break;
1875 case BUTTON_ON:
1876 done = true;
1877 if (timedate[6] == 0) /* rtc needs 1 .. 7 */
1878 timedate[6] = 7;
1879 break;
1880 case BUTTON_OFF:
1881 done = true;
1882 timedate[0] = -1;
1883 break;
1884 #ifdef HAVE_RECORDER_KEYPAD
1885 case BUTTON_F3:
1886 #ifdef HAVE_LCD_BITMAP
1887 global_settings.statusbar = !global_settings.statusbar;
1888 settings_save();
1889 if(global_settings.statusbar)
1890 lcd_setmargins(0, STATUSBAR_HEIGHT);
1891 else
1892 lcd_setmargins(0, 0);
1893 lcd_clear_display();
1894 lcd_puts_scroll(0, 0, string);
1895 #endif
1896 break;
1897 #endif
1899 case SYS_USB_CONNECTED:
1900 usb_screen();
1901 return true;
1905 return false;
1907 #endif