When recording, disable voice menus without actually modifying user settings. Patch...
[Rockbox.git] / apps / settings.c
blob09c90af0665af4c5da77541cc155b4bde18a5aee
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 ****************************************************************************/
20 #include <stdio.h>
21 #include <stddef.h>
22 #include <stdlib.h>
23 #include <limits.h>
24 #include "inttypes.h"
25 #include "config.h"
26 #include "action.h"
27 #include "crc32.h"
28 #include "settings.h"
29 #include "debug.h"
30 #include "usb.h"
31 #include "backlight.h"
32 #include "audio.h"
33 #include "mpeg.h"
34 #include "talk.h"
35 #include "string.h"
36 #include "rtc.h"
37 #include "power.h"
38 #include "ata_idle_notify.h"
39 #include "atoi.h"
40 #include "screens.h"
41 #include "ctype.h"
42 #include "file.h"
43 #include "system.h"
44 #include "misc.h"
45 #ifdef HAVE_LCD_BITMAP
46 #include "icons.h"
47 #include "font.h"
48 #include "peakmeter.h"
49 #endif
50 #include "lang.h"
51 #include "language.h"
52 #include "gwps.h"
53 #include "powermgmt.h"
54 #include "sprintf.h"
55 #include "keyboard.h"
56 #include "version.h"
57 #include "sound.h"
58 #include "rbunicode.h"
59 #include "dircache.h"
60 #include "statusbar.h"
61 #include "splash.h"
62 #include "list.h"
63 #include "settings_list.h"
65 #if (LCD_DEPTH > 1) || (defined(HAVE_LCD_REMOTE) && (LCD_REMOTE_DEPTH > 1))
66 #include "backdrop.h"
67 #endif
69 #if CONFIG_TUNER
70 #include "radio.h"
71 #endif
73 #if CONFIG_CODEC == MAS3507D
74 void dac_line_in(bool enable);
75 #endif
76 struct user_settings global_settings;
77 struct system_status global_status;
79 #ifdef HAVE_RECORDING
80 const char rec_base_directory[] = REC_BASE_DIR;
81 #endif
82 #if CONFIG_CODEC == SWCODEC
83 #include "pcmbuf.h"
84 #include "pcm_playback.h"
85 #include "dsp.h"
86 #ifdef HAVE_RECORDING
87 #include "enc_config.h"
88 #endif
89 #endif /* CONFIG_CODEC == SWCODEC */
91 #define NVRAM_BLOCK_SIZE 44
93 #ifdef HAVE_LCD_BITMAP
94 #define MAX_LINES 10
95 #else
96 #define MAX_LINES 2
97 #endif
99 #ifdef HAVE_REMOTE_LCD
100 #include "lcd-remote.h"
101 #endif
103 long lasttime = 0;
105 /** NVRAM stuff, if the target doesnt have NVRAM it is saved in ROCKBOX_DIR /nvram.bin **/
106 /* NVRAM is set out as
107 [0] 'R'
108 [1] 'b'
109 [2] version
110 [3] stored variable count
111 [4-7] crc32 checksum
112 [8-NVRAM_BLOCK_SIZE] data
114 #define NVRAM_DATA_START 8
115 #define NVRAM_FILE ROCKBOX_DIR "/nvram.bin"
116 static char nvram_buffer[NVRAM_BLOCK_SIZE];
118 static bool read_nvram_data(char* buf, int max_len)
120 unsigned crc32 = 0xffffffff;
121 int var_count = 0, i = 0, buf_pos = 0;
122 #ifndef HAVE_RTC_RAM
123 int fd = open(NVRAM_FILE,O_RDONLY);
124 if (fd < 0)
125 return false;
126 memset(buf,0,max_len);
127 if (read(fd,buf,max_len) < 8) /* min is 8 bytes,magic, ver, vars, crc32 */
128 return false;
129 close(fd);
130 #else
131 memset(buf,0,max_len);
132 /* read rtc block */
133 for (i=0; i < max_len; i++ )
134 buf[i] = rtc_read(0x14+i);
135 #endif
136 /* check magic, version */
137 if ((buf[0] != 'R') || (buf[1] != 'b')
138 || (buf[2] != NVRAM_CONFIG_VERSION))
139 return false;
140 /* check crc32 */
141 crc32 = crc_32(&buf[NVRAM_DATA_START],
142 max_len-NVRAM_DATA_START-1,0xffffffff);
143 if (memcmp(&crc32,&buf[4],4))
144 return false;
145 /* all good, so read in the settings */
146 var_count = buf[3];
147 buf_pos = NVRAM_DATA_START;
148 for(i=0; (i<nb_settings) && (var_count>0) && (buf_pos<max_len); i++)
150 int nvram_bytes = (settings[i].flags&F_NVRAM_BYTES_MASK)
151 >>F_NVRAM_MASK_SHIFT;
152 if (nvram_bytes)
154 memcpy(settings[i].setting,&buf[buf_pos],nvram_bytes);
155 buf_pos += nvram_bytes;
156 var_count--;
159 return true;
161 static bool write_nvram_data(char* buf, int max_len)
163 unsigned crc32 = 0xffffffff;
164 int i = 0, buf_pos = 0;
165 char var_count = 0;
166 #ifndef HAVE_RTC_RAM
167 int fd;
168 #endif
169 memset(buf,0,max_len);
170 /* magic, version */
171 buf[0] = 'R'; buf[1] = 'b';
172 buf[2] = NVRAM_CONFIG_VERSION;
173 buf_pos = NVRAM_DATA_START;
174 for(i=0; (i<nb_settings) && (buf_pos<max_len); i++)
176 int nvram_bytes = (settings[i].flags&F_NVRAM_BYTES_MASK)
177 >>F_NVRAM_MASK_SHIFT;
178 if (nvram_bytes)
180 memcpy(&buf[buf_pos],settings[i].setting,nvram_bytes);
181 buf_pos += nvram_bytes;
182 var_count++;
185 /* count and crc32 */
186 buf[3] = var_count;
187 crc32 = crc_32(&buf[NVRAM_DATA_START],
188 max_len-NVRAM_DATA_START-1,0xffffffff);
189 memcpy(&buf[4],&crc32,4);
190 #ifndef HAVE_RTC_RAM
191 fd = open(NVRAM_FILE,O_CREAT|O_TRUNC|O_WRONLY);
192 if (fd >= 0)
194 int len = write(fd,buf,max_len);
195 close(fd);
196 if (len < 8)
197 return false;
199 #else
200 /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so
201 that it would write a number of bytes at a time since the RTC chip
202 supports that, but this will have to do for now 8-) */
203 for (i=0; i < NVRAM_BLOCK_SIZE; i++ ) {
204 int r = rtc_write(0x14+i, buf[i]);
205 if (r) {
206 DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n",
207 14+i, r );
208 return false;
211 #endif
212 return true;
215 /** Reading from a config file **/
217 * load settings from disk or RTC RAM
219 void settings_load(int which)
221 DEBUGF( "reload_all_settings()\n" );
222 if (which&SETTINGS_RTC)
223 read_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
224 if (which&SETTINGS_HD)
226 settings_load_config(CONFIGFILE,false);
227 settings_load_config(FIXEDSETTINGSFILE,false);
230 #ifdef HAVE_LCD_COLOR
232 * Helper function to convert a string of 6 hex digits to a native colour
235 #define hex2dec(c) (((c) >= '0' && ((c) <= '9')) ? (toupper(c)) - '0' : \
236 (toupper(c)) - 'A' + 10)
238 static int hex_to_rgb(const char* hex)
239 { int ok = 1;
240 int i;
241 int red, green, blue;
243 if (strlen(hex) == 6) {
244 for (i=0; i < 6; i++ ) {
245 if (!isxdigit(hex[i])) {
246 ok=0;
247 break;
251 if (ok) {
252 red = (hex2dec(hex[0]) << 4) | hex2dec(hex[1]);
253 green = (hex2dec(hex[2]) << 4) | hex2dec(hex[3]);
254 blue = (hex2dec(hex[4]) << 4) | hex2dec(hex[5]);
255 return LCD_RGBPACK(red,green,blue);
259 return 0;
261 #endif /* HAVE_LCD_COLOR */
263 static bool cfg_string_to_int(int setting_id, int* out, char* str)
265 const char* start = settings[setting_id].cfg_vals;
266 char* end = NULL;
267 char temp[MAX_PATH];
268 int count = 0;
269 while (1)
271 end = strchr(start, ',');
272 if (!end)
274 if (!strcmp(str, start))
276 *out = count;
277 return true;
279 else return false;
281 strncpy(temp, start, end-start);
282 temp[end-start] = '\0';
283 if (!strcmp(str, temp))
285 *out = count;
286 return true;
288 start = end +1;
289 count++;
291 return false;
294 bool settings_load_config(const char* file, bool apply)
296 int fd;
297 char line[128];
298 char* name;
299 char* value;
300 int i;
301 fd = open(file, O_RDONLY);
302 if (fd < 0)
303 return false;
305 while (read_line(fd, line, sizeof line) > 0)
307 if (!settings_parseline(line, &name, &value))
308 continue;
309 for(i=0; i<nb_settings; i++)
311 if (settings[i].cfg_name == NULL)
312 continue;
313 if (!strcasecmp(name,settings[i].cfg_name))
315 switch (settings[i].flags&F_T_MASK)
317 case F_T_INT:
318 case F_T_UINT:
319 #ifdef HAVE_LCD_COLOR
320 if (settings[i].flags&F_RGB)
321 *(int*)settings[i].setting = hex_to_rgb(value);
322 else
323 #endif
324 if (settings[i].cfg_vals == NULL)
326 *(int*)settings[i].setting = atoi(value);
328 else
330 cfg_string_to_int(i,(int*)settings[i].setting,value);
332 break;
333 case F_T_BOOL:
335 int temp;
336 if (cfg_string_to_int(i,&temp,value))
337 *(bool*)settings[i].setting = (temp==0?false:true);
338 break;
340 case F_T_CHARPTR:
341 case F_T_UCHARPTR:
343 char storage[MAX_PATH];
344 if (settings[i].filename_setting->prefix)
346 int len = strlen(settings[i].filename_setting->prefix);
347 if (!strncasecmp(value,
348 settings[i].filename_setting->prefix,
349 len))
351 strncpy(storage,&value[len],MAX_PATH);
353 else strncpy(storage,value,MAX_PATH);
355 else strncpy(storage,value,MAX_PATH);
356 if (settings[i].filename_setting->suffix)
358 char *s = strcasestr(storage,settings[i].filename_setting->suffix);
359 if (s) *s = '\0';
361 strncpy((char*)settings[i].setting,storage,
362 settings[i].filename_setting->max_len);
363 ((char*)settings[i].setting)
364 [settings[i].filename_setting->max_len-1] = '\0';
365 break;
368 break;
369 } /* if (!strcmp(name,settings[i].cfg_name)) */
370 } /* for(...) */
371 } /* while(...) */
373 close(fd);
374 settings_save();
375 if (apply)
376 settings_apply();
377 return true;
380 /** Writing to a config file and saving settings **/
382 bool cfg_int_to_string(int setting_id, int val, char* buf, int buf_len)
384 const char* start = settings[setting_id].cfg_vals;
385 char* end = NULL;
386 int count = 0;
387 while (count < val)
389 start = strchr(start,',');
390 if (!start)
391 return false;
392 count++;
393 start++;
395 end = strchr(start,',');
396 if (end == NULL)
397 strncpy(buf, start, buf_len);
398 else
400 int len = (buf_len > (end-start))? end-start: buf_len;
401 strncpy(buf, start, len);
402 buf[len] = '\0';
404 return true;
406 static bool is_changed(int setting_id)
408 const struct settings_list *setting = &settings[setting_id];
409 switch (setting->flags&F_T_MASK)
411 case F_T_INT:
412 case F_T_UINT:
413 if (setting->flags&F_DEF_ISFUNC)
415 if (*(int*)setting->setting == setting->default_val.func())
416 return false;
418 else if (setting->flags&F_T_SOUND)
420 if (*(int*)setting->setting ==
421 sound_default(setting->sound_setting->setting))
422 return false;
424 else if (*(int*)setting->setting == setting->default_val.int_)
425 return false;
426 break;
427 case F_T_BOOL:
428 if (*(bool*)setting->setting == setting->default_val.bool_)
429 return false;
430 break;
431 case F_T_CHARPTR:
432 case F_T_UCHARPTR:
433 if (!strcmp((char*)setting->setting, setting->default_val.charptr))
434 return false;
435 break;
437 return true;
440 static bool settings_write_config(char* filename, int options)
442 int i;
443 int fd;
444 char value[MAX_PATH];
445 fd = open(filename,O_CREAT|O_TRUNC|O_WRONLY);
446 if (fd < 0)
447 return false;
448 fdprintf(fd, "# .cfg file created by rockbox %s - "
449 "http://www.rockbox.org\r\n\r\n", appsversion);
450 for(i=0; i<nb_settings; i++)
452 if (settings[i].cfg_name == NULL)
453 continue;
454 value[0] = '\0';
456 if ((options == SETTINGS_SAVE_CHANGED) &&
457 !is_changed(i))
458 continue;
459 else if ((options == SETTINGS_SAVE_THEME) &&
460 ((settings[i].flags&F_THEMESETTING) == 0))
461 continue;
462 #ifdef HAVE_RECORDING
463 else if ((options == SETTINGS_SAVE_RECPRESETS) &&
464 ((settings[i].flags&F_RECSETTING) == 0))
465 continue;
466 #endif
467 switch (settings[i].flags&F_T_MASK)
469 case F_T_INT:
470 case F_T_UINT:
471 #ifdef HAVE_LCD_COLOR
472 if (settings[i].flags&F_RGB)
474 int colour = *(int*)settings[i].setting;
475 snprintf(value,MAX_PATH,"%02x%02x%02x",
476 (int)RGB_UNPACK_RED(colour),
477 (int)RGB_UNPACK_GREEN(colour),
478 (int)RGB_UNPACK_BLUE(colour));
480 else
481 #endif
482 if (settings[i].cfg_vals == NULL)
484 snprintf(value,MAX_PATH,"%d",*(int*)settings[i].setting);
486 else
488 cfg_int_to_string(i, *(int*)settings[i].setting,
489 value, MAX_PATH);
491 break;
492 case F_T_BOOL:
493 cfg_int_to_string(i,
494 *(bool*)settings[i].setting==false?0:1, value, MAX_PATH);
495 break;
496 case F_T_CHARPTR:
497 case F_T_UCHARPTR:
498 if (((char*)settings[i].setting)[0] == '\0')
499 break;
500 if (settings[i].filename_setting->prefix)
502 snprintf(value,MAX_PATH,"%s%s%s",
503 settings[i].filename_setting->prefix,
504 (char*)settings[i].setting,
505 settings[i].filename_setting->suffix);
507 else strncpy(value,(char*)settings[i].setting,
508 settings[i].filename_setting->max_len);
509 break;
510 } /* switch () */
511 if (value[0])
512 fdprintf(fd,"%s: %s\r\n",settings[i].cfg_name,value);
513 } /* for(...) */
514 close(fd);
515 return true;
517 #ifndef HAVE_RTC_RAM
518 static bool flush_global_status_callback(void)
520 return write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
522 #endif
523 static bool flush_config_block_callback(void)
525 bool r1, r2;
526 r1 = write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
527 r2 = settings_write_config(CONFIGFILE, SETTINGS_SAVE_CHANGED);
528 return r1 || r2;
532 * persist all runtime user settings to disk or RTC RAM
534 static void update_runtime(void)
536 int elapsed_secs;
538 elapsed_secs = (current_tick - lasttime) / HZ;
539 global_status.runtime += elapsed_secs;
540 lasttime += (elapsed_secs * HZ);
542 if ( global_status.runtime > global_status.topruntime )
543 global_status.topruntime = global_status.runtime;
546 void status_save( void )
548 update_runtime();
549 #ifdef HAVE_RTC_RAM
550 /* this will be done in the ata_callback if
551 target doesnt have rtc ram */
552 write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
553 #else
554 register_ata_idle_func(flush_global_status_callback);
555 #endif
558 int settings_save( void )
560 update_runtime();
561 #ifdef HAVE_RTC_RAM
562 /* this will be done in the ata_callback if
563 target doesnt have rtc ram */
564 write_nvram_data(nvram_buffer,NVRAM_BLOCK_SIZE);
565 #endif
566 if(!register_ata_idle_func(flush_config_block_callback))
568 int i;
569 FOR_NB_SCREENS(i)
571 screens[i].clear_display();
572 #ifdef HAVE_LCD_CHARCELLS
573 screens[i].puts(0, 0, str(LANG_SETTINGS_SAVE_PLAYER));
574 screens[i].puts(0, 1, str(LANG_SETTINGS_BATTERY_PLAYER));
575 #else
576 screens[i].puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
577 screens[i].puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
578 screens[i].update();
579 #endif
581 sleep(HZ*2);
582 return -1;
584 return 0;
586 bool settings_save_config(int options)
588 char filename[MAX_PATH];
589 char *folder;
590 switch (options)
592 case SETTINGS_SAVE_THEME:
593 folder = THEME_DIR;
594 break;
595 #ifdef HAVE_RECORDING
596 case SETTINGS_SAVE_RECPRESETS:
597 folder = RECPRESETS_DIR;
598 break;
599 #endif
600 default:
601 folder = ROCKBOX_DIR;
603 create_numbered_filename(filename, folder, "config", ".cfg", 2
604 IF_CNFN_NUM_(, NULL));
606 /* allow user to modify filename */
607 while (true) {
608 if (!kbd_input(filename, sizeof filename)) {
609 break;
611 else {
612 gui_syncsplash(HZ, str(LANG_MENU_SETTING_CANCEL));
613 return false;
617 if (settings_write_config(filename, options))
618 gui_syncsplash(HZ, str(LANG_SETTINGS_SAVED));
619 else
620 gui_syncsplash(HZ, str(LANG_FAILED));
621 return true;
624 /** Apply and Reset settings **/
627 #ifdef HAVE_LCD_BITMAP
629 * Applies the range infos stored in global_settings to
630 * the peak meter.
632 void settings_apply_pm_range(void)
634 int pm_min, pm_max;
636 /* depending on the scale mode (dBfs or percent) the values
637 of global_settings.peak_meter_dbfs have different meanings */
638 if (global_settings.peak_meter_dbfs)
640 /* convert to dBfs * 100 */
641 pm_min = -(((int)global_settings.peak_meter_min) * 100);
642 pm_max = -(((int)global_settings.peak_meter_max) * 100);
644 else
646 /* percent is stored directly -> no conversion */
647 pm_min = global_settings.peak_meter_min;
648 pm_max = global_settings.peak_meter_max;
651 /* apply the range */
652 peak_meter_init_range(global_settings.peak_meter_dbfs, pm_min, pm_max);
654 #endif /* HAVE_LCD_BITMAP */
656 void sound_settings_apply(void)
658 #if CONFIG_CODEC == SWCODEC
659 sound_set_dsp_callback(dsp_callback);
660 #endif
661 sound_set(SOUND_BASS, global_settings.bass);
662 sound_set(SOUND_TREBLE, global_settings.treble);
663 sound_set(SOUND_BALANCE, global_settings.balance);
664 sound_set(SOUND_VOLUME, global_settings.volume);
665 sound_set(SOUND_CHANNELS, global_settings.channel_config);
666 sound_set(SOUND_STEREO_WIDTH, global_settings.stereo_width);
667 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
668 sound_set(SOUND_LOUDNESS, global_settings.loudness);
669 sound_set(SOUND_AVC, global_settings.avc);
670 sound_set(SOUND_MDB_STRENGTH, global_settings.mdb_strength);
671 sound_set(SOUND_MDB_HARMONICS, global_settings.mdb_harmonics);
672 sound_set(SOUND_MDB_CENTER, global_settings.mdb_center);
673 sound_set(SOUND_MDB_SHAPE, global_settings.mdb_shape);
674 sound_set(SOUND_MDB_ENABLE, global_settings.mdb_enable);
675 sound_set(SOUND_SUPERBASS, global_settings.superbass);
676 #endif
678 #ifdef HAVE_USB_POWER
679 #if CONFIG_CHARGING
680 usb_charging_enable(global_settings.usb_charging);
681 #endif
682 #endif
685 void settings_apply(void)
687 char buf[64];
688 #if CONFIG_CODEC == SWCODEC
689 int i;
690 #endif
692 DEBUGF( "settings_apply()\n" );
693 sound_settings_apply();
695 audio_set_buffer_margin(global_settings.buffer_margin);
697 #ifdef HAVE_LCD_CONTRAST
698 lcd_set_contrast(global_settings.contrast);
699 #endif
700 lcd_scroll_speed(global_settings.scroll_speed);
701 #ifdef HAVE_REMOTE_LCD
702 lcd_remote_set_contrast(global_settings.remote_contrast);
703 lcd_remote_set_invert_display(global_settings.remote_invert);
704 lcd_remote_set_flip(global_settings.remote_flip_display);
705 lcd_remote_scroll_speed(global_settings.remote_scroll_speed);
706 lcd_remote_scroll_step(global_settings.remote_scroll_step);
707 lcd_remote_scroll_delay(global_settings.remote_scroll_delay);
708 lcd_remote_bidir_scroll(global_settings.remote_bidir_limit);
709 #ifdef HAVE_REMOTE_LCD_TICKING
710 lcd_remote_emireduce(global_settings.remote_reduce_ticking);
711 #endif
712 remote_backlight_set_timeout(global_settings.remote_backlight_timeout);
713 #if CONFIG_CHARGING
714 remote_backlight_set_timeout_plugged(global_settings.remote_backlight_timeout_plugged);
715 #endif
716 #ifdef HAS_REMOTE_BUTTON_HOLD
717 remote_backlight_set_on_button_hold(global_settings.remote_backlight_on_button_hold);
718 #endif
719 #endif /* HAVE_REMOTE_LCD */
720 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
721 backlight_set_brightness(global_settings.brightness);
722 #endif
723 #ifdef HAVE_BACKLIGHT
724 backlight_set_timeout(global_settings.backlight_timeout);
725 #if CONFIG_CHARGING
726 backlight_set_timeout_plugged(global_settings.backlight_timeout_plugged);
727 #endif
728 #if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)
729 backlight_set_fade_in(global_settings.backlight_fade_in);
730 backlight_set_fade_out(global_settings.backlight_fade_out);
731 #endif
732 #endif
733 #ifdef HAVE_BUTTONLIGHT_BRIGHTNESS
734 buttonlight_set_brightness(global_settings.buttonlight_brightness);
735 #endif
736 #ifdef HAVE_BUTTON_LIGHT
737 button_backlight_set_timeout(global_settings.button_light_timeout);
738 #endif
739 ata_spindown(global_settings.disk_spindown);
740 #if (CONFIG_CODEC == MAS3507D) && !defined(SIMULATOR)
741 dac_line_in(global_settings.line_in);
742 #endif
743 mpeg_id3_options(global_settings.id3_v1_first);
745 set_poweroff_timeout(global_settings.poweroff);
747 set_battery_capacity(global_settings.battery_capacity);
748 #if BATTERY_TYPES_COUNT > 1
749 set_battery_type(global_settings.battery_type);
750 #endif
752 #ifdef HAVE_LCD_BITMAP
753 lcd_set_invert_display(global_settings.invert);
754 lcd_set_flip(global_settings.flip_display);
755 button_set_flip(global_settings.flip_display);
756 lcd_update(); /* refresh after flipping the screen */
757 settings_apply_pm_range();
758 peak_meter_init_times(
759 global_settings.peak_meter_release, global_settings.peak_meter_hold,
760 global_settings.peak_meter_clip_hold);
761 #endif
763 #if LCD_DEPTH > 1
764 unload_wps_backdrop();
765 #endif
766 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
767 unload_remote_wps_backdrop();
768 #endif
769 if ( global_settings.wps_file[0] &&
770 global_settings.wps_file[0] != 0xff ) {
771 snprintf(buf, sizeof buf, WPS_DIR "/%s.wps",
772 global_settings.wps_file);
773 wps_data_load(gui_wps[0].data, buf, true);
775 else
777 wps_data_init(gui_wps[0].data);
778 #ifdef HAVE_REMOTE_LCD
779 gui_wps[0].data->remote_wps = false;
780 #endif
783 #if LCD_DEPTH > 1
784 if ( global_settings.backdrop_file[0] &&
785 global_settings.backdrop_file[0] != 0xff ) {
786 snprintf(buf, sizeof buf, BACKDROP_DIR "/%s.bmp",
787 global_settings.backdrop_file);
788 load_main_backdrop(buf);
789 } else {
790 unload_main_backdrop();
792 show_main_backdrop();
793 #endif
794 #if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
795 show_remote_main_backdrop();
796 #endif
798 #ifdef HAVE_LCD_COLOR
799 screens[SCREEN_MAIN].set_foreground(global_settings.fg_color);
800 screens[SCREEN_MAIN].set_background(global_settings.bg_color);
801 #endif
803 #if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
804 if ( global_settings.rwps_file[0]) {
805 snprintf(buf, sizeof buf, WPS_DIR "/%s.rwps",
806 global_settings.rwps_file);
807 wps_data_load(gui_wps[1].data, buf, true);
809 else
811 wps_data_init(gui_wps[1].data);
812 gui_wps[1].data->remote_wps = true;
814 #endif
816 #ifdef HAVE_LCD_BITMAP
817 if ( global_settings.font_file[0]) {
818 snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
819 global_settings.font_file);
820 font_load(buf);
822 else
823 font_reset();
825 if ( global_settings.kbd_file[0]) {
826 snprintf(buf, sizeof buf, ROCKBOX_DIR "/%s.kbd",
827 global_settings.kbd_file);
828 load_kbd(buf);
830 else
831 load_kbd(NULL);
833 lcd_scroll_step(global_settings.scroll_step);
834 gui_list_screen_scroll_step(global_settings.screen_scroll_step);
835 gui_list_screen_scroll_out_of_view(global_settings.offset_out_of_view);
836 #else
837 lcd_jump_scroll(global_settings.jump_scroll);
838 lcd_jump_scroll_delay(global_settings.jump_scroll_delay);
839 #endif
840 lcd_bidir_scroll(global_settings.bidir_limit);
841 lcd_scroll_delay(global_settings.scroll_delay);
843 if ( global_settings.lang_file[0]) {
844 snprintf(buf, sizeof buf, LANG_DIR "/%s.lng",
845 global_settings.lang_file);
846 lang_load(buf);
847 talk_init(); /* use voice of same language */
850 set_codepage(global_settings.default_codepage);
852 #if CONFIG_CODEC == SWCODEC
853 audio_set_crossfade(global_settings.crossfade);
854 dsp_set_replaygain();
855 dsp_set_crossfeed(global_settings.crossfeed);
856 dsp_set_crossfeed_direct_gain(global_settings.crossfeed_direct_gain);
857 dsp_set_crossfeed_cross_params(global_settings.crossfeed_cross_gain,
858 global_settings.crossfeed_hf_attenuation,
859 global_settings.crossfeed_hf_cutoff);
861 /* Configure software equalizer, hardware eq is handled in audio_init() */
862 dsp_set_eq(global_settings.eq_enabled);
863 dsp_set_eq_precut(global_settings.eq_precut);
864 for(i = 0; i < 5; i++) {
865 dsp_set_eq_coefs(i);
868 dsp_dither_enable(global_settings.dithering_enabled);
869 #endif
871 #ifdef HAVE_SPDIF_POWER
872 spdif_power_enable(global_settings.spdif_enable);
873 #endif
875 #ifdef HAVE_BACKLIGHT
876 set_backlight_filter_keypress(global_settings.bl_filter_first_keypress);
877 #ifdef HAVE_REMOTE_LCD
878 set_remote_backlight_filter_keypress(global_settings.remote_bl_filter_first_keypress);
879 #endif
880 #ifdef HAS_BUTTON_HOLD
881 backlight_set_on_button_hold(global_settings.backlight_on_button_hold);
882 #endif
883 #ifdef HAVE_LCD_SLEEP
884 lcd_set_sleep_after_backlight_off(global_settings.lcd_sleep_after_backlight_off);
885 #endif
886 #endif /* HAVE_BACKLIGHT */
888 /* This should stay last */
889 #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
890 enc_global_settings_apply();
891 #endif
892 /* load the icon set */
893 icons_init();
901 * reset all settings to their default value
903 void settings_reset(void) {
905 int i;
906 DEBUGF( "settings_reset()\n" );
908 for(i=0; i<nb_settings; i++)
910 switch (settings[i].flags&F_T_MASK)
912 case F_T_INT:
913 case F_T_UINT:
914 if (settings[i].flags&F_DEF_ISFUNC)
915 *(int*)settings[i].setting = settings[i].default_val.func();
916 else if (settings[i].flags&F_T_SOUND)
917 *(int*)settings[i].setting =
918 sound_default(settings[i].sound_setting->setting);
919 else *(int*)settings[i].setting = settings[i].default_val.int_;
920 break;
921 case F_T_BOOL:
922 *(bool*)settings[i].setting = settings[i].default_val.bool_;
923 break;
924 case F_T_CHARPTR:
925 case F_T_UCHARPTR:
926 strncpy((char*)settings[i].setting,
927 settings[i].default_val.charptr,MAX_FILENAME);
928 break;
930 } /* for(...) */
931 #if defined (HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
932 enc_global_settings_reset();
933 #endif
936 /** Changing setting values **/
937 const struct settings_list* find_setting(void* variable, int *id)
939 int i;
940 for(i=0;i<nb_settings;i++)
942 if (settings[i].setting == variable)
944 if (id)
945 *id = i;
946 return &settings[i];
949 return NULL;
952 void talk_setting(void *global_settings_variable)
954 const struct settings_list *setting;
955 if (!talk_menus_enabled())
956 return;
957 setting = find_setting(global_settings_variable, NULL);
958 if (setting == NULL)
959 return;
960 if (setting->lang_id)
961 talk_id(setting->lang_id,false);
964 static int selected_setting; /* Used by the callback */
966 static void dec_sound_formatter(char *buffer, int buffer_size,
967 int val, const char *unit)
969 val = sound_val2phys(selected_setting, val);
970 char sign = ' ';
971 if(val < 0)
973 sign = '-';
974 val = abs(val);
976 int integer = val / 10;
977 int dec = val % 10;
978 snprintf(buffer, buffer_size, "%c%d.%d %s", sign, integer, dec, unit);
981 bool set_sound(const unsigned char * string,
982 int* variable,
983 int setting)
985 int talkunit = UNIT_INT;
986 const char* unit = sound_unit(setting);
987 int numdec = sound_numdecimals(setting);
988 int steps = sound_steps(setting);
989 int min = sound_min(setting);
990 int max = sound_max(setting);
991 sound_set_type* sound_callback = sound_get_fn(setting);
992 if (*unit == 'd') /* crude reconstruction */
993 talkunit = UNIT_DB;
994 else if (*unit == '%')
995 talkunit = UNIT_PERCENT;
996 else if (*unit == 'H')
997 talkunit = UNIT_HERTZ;
998 if (!numdec)
999 return set_int(string, unit, talkunit, variable, sound_callback,
1000 steps, min, max, NULL );
1001 else
1002 {/* Decimal number */
1003 selected_setting=setting;
1004 return set_int(string, unit, talkunit, variable, sound_callback,
1005 steps, min, max, &dec_sound_formatter );
1009 bool set_bool(const char* string, bool* variable )
1011 return set_bool_options(string, variable,
1012 (char *)STR(LANG_SET_BOOL_YES),
1013 (char *)STR(LANG_SET_BOOL_NO),
1014 NULL);
1017 /* wrapper to convert from int param to bool param in set_option */
1018 static void (*boolfunction)(bool);
1019 static void bool_funcwrapper(int value)
1021 if (value)
1022 boolfunction(true);
1023 else
1024 boolfunction(false);
1027 bool set_bool_options(const char* string, bool* variable,
1028 const char* yes_str, int yes_voice,
1029 const char* no_str, int no_voice,
1030 void (*function)(bool))
1032 struct opt_items names[] = {
1033 {(unsigned char *)no_str, no_voice},
1034 {(unsigned char *)yes_str, yes_voice}
1036 bool result;
1038 boolfunction = function;
1039 result = set_option(string, variable, BOOL, names, 2,
1040 function ? bool_funcwrapper : NULL);
1041 return result;
1044 static void talk_unit(int unit, int value, long (*get_talk_id)(int value))
1046 if (talk_menus_enabled())
1048 if (get_talk_id)
1050 talk_id(get_talk_id(value),false);
1052 else if (unit < UNIT_LAST)
1053 { /* use the available unit definition */
1054 talk_value(value, unit, false);
1056 else
1057 { /* say the number, followed by an arbitrary voice ID */
1058 talk_number(value, false);
1059 talk_id(unit, true);
1064 struct value_setting_data {
1065 enum optiontype type;
1066 /* used for "value" settings.. */
1067 int max;
1068 int step;
1069 int voice_unit;
1070 const char * unit;
1071 void (*formatter)(char* dest, int dest_length,
1072 int value, const char* unit);
1073 long (*get_talk_id)(int value);
1074 /* used for BOOL and "choice" settings */
1075 struct opt_items* options;
1078 static char * value_setting_get_name_cb(int selected_item,void * data, char *buffer)
1080 struct value_setting_data* cb_data =
1081 (struct value_setting_data*)data;
1082 if (cb_data->type == INT && !cb_data->options)
1084 int item = cb_data->max -(selected_item*cb_data->step);
1085 if (cb_data->formatter)
1086 cb_data->formatter(buffer, MAX_PATH,item,cb_data->unit);
1087 else
1088 snprintf(buffer, MAX_PATH,"%d %s",item,cb_data->unit);
1090 else strcpy(buffer,P2STR(cb_data->options[selected_item].string));
1091 return buffer;
1093 #define type_fromvoidptr(type, value) \
1094 (type == INT)? \
1095 (int)(*(int*)(value)) \
1097 (bool)(*(bool*)(value))
1098 static bool do_set_setting(const unsigned char* string, void *variable,
1099 int nb_items,int selected,
1100 struct value_setting_data *cb_data,
1101 void (*function)(int))
1103 int action;
1104 bool done = false;
1105 struct gui_synclist lists;
1106 int oldvalue;
1107 bool allow_wrap = true;
1109 if (cb_data->type == INT)
1111 oldvalue = *(int*)variable;
1112 if (variable == &global_settings.volume)
1113 allow_wrap = false;
1115 else oldvalue = *(bool*)variable;
1117 gui_synclist_init(&lists,value_setting_get_name_cb,(void*)cb_data,false,1);
1118 gui_synclist_set_title(&lists, (char*)string,Icon_Questionmark);
1119 gui_synclist_set_icon_callback(&lists,NULL);
1120 gui_synclist_set_nb_items(&lists,nb_items);
1121 gui_synclist_limit_scroll(&lists,true);
1122 gui_synclist_select_item(&lists, selected);
1124 if (talk_menus_enabled())
1126 if (cb_data->type == INT && !cb_data->options)
1127 talk_unit(cb_data->voice_unit, *(int*)variable, cb_data->get_talk_id);
1128 else
1129 talk_id(cb_data->options[selected].voice_id, false);
1132 gui_synclist_draw(&lists);
1133 action_signalscreenchange();
1134 while (!done)
1137 action = get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
1138 if (action == ACTION_NONE)
1139 continue;
1140 if (gui_synclist_do_button(&lists,action,
1141 allow_wrap?LIST_WRAP_UNLESS_HELD:LIST_WRAP_OFF))
1143 if (talk_menus_enabled())
1145 int value;
1146 if (cb_data->type == INT && !cb_data->options)
1148 value = cb_data->max -
1149 gui_synclist_get_sel_pos(&lists)*cb_data->step;
1150 talk_unit(cb_data->voice_unit, value, cb_data->get_talk_id);
1152 else
1154 value = gui_synclist_get_sel_pos(&lists);
1155 talk_id(cb_data->options[value].voice_id, false);
1158 if (cb_data->type == INT && !cb_data->options)
1159 *(int*)variable = cb_data->max -
1160 gui_synclist_get_sel_pos(&lists)*cb_data->step;
1161 else if (cb_data->type == BOOL)
1162 *(bool*)variable = gui_synclist_get_sel_pos(&lists) ? true : false;
1163 else *(int*)variable = gui_synclist_get_sel_pos(&lists);
1165 else if (action == ACTION_STD_CANCEL)
1167 if (cb_data->type == INT)
1169 if (*(int*)variable != oldvalue)
1171 gui_syncsplash(HZ/2, str(LANG_MENU_SETTING_CANCEL));
1172 *(int*)variable = oldvalue;
1175 else
1177 if (*(bool*)variable != (bool)oldvalue)
1179 gui_syncsplash(HZ/2, str(LANG_MENU_SETTING_CANCEL));
1180 *(bool*)variable = (bool)oldvalue;
1183 done = true;
1185 else if (action == ACTION_STD_OK)
1187 done = true;
1189 else if(default_event_handler(action) == SYS_USB_CONNECTED)
1190 return true;
1191 gui_syncstatusbar_draw(&statusbars, false);
1192 if ( function )
1193 function(type_fromvoidptr(cb_data->type,variable));
1195 if (cb_data->type == INT)
1197 if (oldvalue != *(int*)variable)
1198 settings_save();
1200 else if (oldvalue != *(bool*)variable)
1201 settings_save();
1203 action_signalscreenchange();
1204 return false;
1206 static const char *unit_strings[] =
1208 [UNIT_INT]
1209 = "",
1210 [UNIT_MS]
1211 = "ms",
1212 [UNIT_SEC]
1213 = "s",
1214 [UNIT_MIN]
1215 = "min",
1216 [UNIT_HOUR]
1217 = "hr",
1218 [UNIT_KHZ]
1219 = "KHz",
1220 [UNIT_DB]
1221 = "dB",
1222 [UNIT_PERCENT]
1223 = "%",
1224 [UNIT_MAH]
1225 = "mAh",
1226 [UNIT_PIXEL]
1227 = "px",
1228 [UNIT_PER_SEC]
1229 = "per sec",
1230 [UNIT_HERTZ]
1231 = "Hz",
1232 [UNIT_MB]
1233 = "MB",
1234 [UNIT_KBIT]
1235 = "kb/s",
1237 bool set_int_ex(const unsigned char* string,
1238 const char* unit,
1239 int voice_unit,
1240 int* variable,
1241 void (*function)(int),
1242 int step,
1243 int min,
1244 int max,
1245 void (*formatter)(char*, int, int, const char*),
1246 long (*get_talk_id)(int))
1248 int count = (max-min)/step + 1;
1249 #if CONFIG_KEYPAD != PLAYER_PAD
1250 struct value_setting_data data = {
1251 INT,max, step, voice_unit,unit,formatter,get_talk_id,NULL };
1252 if (voice_unit < UNIT_LAST)
1253 data.unit = unit_strings[voice_unit];
1254 else
1255 data.unit = str(voice_unit);
1256 return do_set_setting(string,variable,count,
1257 (max-*variable)/step, &data,function);
1258 #else
1259 struct value_setting_data data = {
1260 INT,min, -step, voice_unit,unit,formatter,get_talk_id,NULL };
1261 if (voice_unit < UNIT_LAST)
1262 data.unit = unit_strings[voice_unit];
1263 else
1264 data.unit = str(voice_unit);
1265 return do_set_setting(string,variable,count,
1266 (*variable-min)/step, &data,function);
1267 #endif
1269 bool set_int(const unsigned char* string,
1270 const char* unit,
1271 int voice_unit,
1272 int* variable,
1273 void (*function)(int),
1274 int step,
1275 int min,
1276 int max,
1277 void (*formatter)(char*, int, int, const char*) )
1279 return set_int_ex(string, unit, voice_unit, variable, function,
1280 step, min, max, formatter, NULL);
1282 /* NOTE: the 'type' parameter specifies the actual type of the variable
1283 that 'variable' points to. not the value within. Only variables with
1284 type 'bool' should use parameter BOOL.
1286 The type separation is necessary since int and bool are fundamentally
1287 different and bit-incompatible types and can not share the same access
1288 code. */
1289 bool set_option(const char* string, void* variable, enum optiontype type,
1290 const struct opt_items* options, int numoptions, void (*function)(int))
1292 struct value_setting_data data = {
1293 type,0, 0, 0,NULL,NULL,NULL,(struct opt_items*)options };
1294 int selected;
1295 if (type == BOOL)
1296 selected = *(bool*)variable ? 1 : 0;
1297 else selected = *(int*)variable;
1298 return do_set_setting(string,variable,numoptions,
1299 selected, &data,function);
1302 /** extra stuff which is probably misplaced **/
1304 void set_file(char* filename, char* setting, int maxlen)
1306 char* fptr = strrchr(filename,'/');
1307 int len;
1308 int extlen = 0;
1309 char* ptr;
1311 if (!fptr)
1312 return;
1314 *fptr = 0;
1315 fptr++;
1317 len = strlen(fptr);
1318 ptr = fptr + len;
1319 while ((*ptr != '.') && (ptr != fptr)) {
1320 extlen++;
1321 ptr--;
1323 if(ptr == fptr) extlen = 0;
1325 if (strncasecmp(ROCKBOX_DIR, filename ,strlen(ROCKBOX_DIR)) ||
1326 (len-extlen > maxlen))
1327 return;
1329 strncpy(setting, fptr, len-extlen);
1330 setting[len-extlen]=0;
1332 settings_save();
1335 #ifdef HAVE_RECORDING
1336 /* This array holds the record timer interval lengths, in seconds */
1337 static const unsigned long rec_timer_seconds[] =
1339 0, /* 0 means OFF */
1340 5*60, /* 00:05 */
1341 10*60, /* 00:10 */
1342 15*60, /* 00:15 */
1343 30*60, /* 00:30 */
1344 60*60, /* 01:00 */
1345 74*60, /* 74:00 */
1346 80*60, /* 80:00 */
1347 2*60*60, /* 02:00 */
1348 4*60*60, /* 04:00 */
1349 6*60*60, /* 06:00 */
1350 8*60*60, /* 08:00 */
1351 10L*60*60, /* 10:00 */
1352 12L*60*60, /* 12:00 */
1353 18L*60*60, /* 18:00 */
1354 24L*60*60 /* 24:00 */
1357 unsigned int rec_timesplit_seconds(void)
1359 return rec_timer_seconds[global_settings.rec_timesplit];
1362 /* This array holds the record size interval lengths, in bytes */
1363 static const unsigned long rec_size_bytes[] =
1365 0, /* 0 means OFF */
1366 5*1024*1024, /* 5MB */
1367 10*1024*1024, /* 10MB */
1368 15*1024*1024, /* 15MB */
1369 32*1024*1024, /* 32MB */
1370 64*1024*1024, /* 64MB */
1371 75*1024*1024, /* 75MB */
1372 100*1024*1024, /* 100MB */
1373 128*1024*1024, /* 128MB */
1374 256*1024*1024, /* 256MB */
1375 512*1024*1024, /* 512MB */
1376 650*1024*1024, /* 650MB */
1377 700*1024*1024, /* 700MB */
1378 1024*1024*1024, /* 1GB */
1379 1536*1024*1024, /* 1.5GB */
1380 1792*1024*1024, /* 1.75GB */
1383 unsigned long rec_sizesplit_bytes(void)
1385 return rec_size_bytes[global_settings.rec_sizesplit];
1388 * Time strings used for the trigger durations.
1389 * Keep synchronous to trigger_times in settings_apply_trigger
1391 const char * const trig_durations[TRIG_DURATION_COUNT] =
1393 "0s", "1s", "2s", "5s",
1394 "10s", "15s", "20s", "25s", "30s",
1395 "1min", "2min", "5min", "10min"
1398 void settings_apply_trigger(void)
1400 /* Keep synchronous to trig_durations and trig_durations_conf*/
1401 static const long trigger_times[TRIG_DURATION_COUNT] = {
1402 0, HZ, 2*HZ, 5*HZ,
1403 10*HZ, 15*HZ, 20*HZ, 25*HZ, 30*HZ,
1404 60*HZ, 2*60*HZ, 5*60*HZ, 10*60*HZ
1407 peak_meter_define_trigger(
1408 global_settings.rec_start_thres,
1409 trigger_times[global_settings.rec_start_duration],
1410 MIN(trigger_times[global_settings.rec_start_duration] / 2, 2*HZ),
1411 global_settings.rec_stop_thres,
1412 trigger_times[global_settings.rec_stop_postrec],
1413 trigger_times[global_settings.rec_stop_gap]
1416 #endif