/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: settings.c,v 1.409 2006-08-23 20:02:05 lowlight Exp $ * * Copyright (C) 2002 by wavey@wavey.org * RTC config saving code (C) 2002 by hessu@hes.iki.fi * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include #include #include #include "inttypes.h" #include "config.h" #include "kernel.h" #include "thread.h" #include "action.h" #include "settings.h" #include "disk.h" #include "panic.h" #include "debug.h" #include "usb.h" #include "backlight.h" #include "lcd.h" #include "audio.h" #include "mp3_playback.h" #include "mpeg.h" #include "talk.h" #include "string.h" #include "ata.h" #include "fat.h" #include "power.h" #include "powermgmt.h" #include "status.h" #include "atoi.h" #include "screens.h" #include "ctype.h" #include "file.h" #include "errno.h" #include "system.h" #include "misc.h" #include "timefuncs.h" #ifdef HAVE_LCD_BITMAP #include "icons.h" #include "font.h" #include "peakmeter.h" #include "hwcompat.h" #endif #include "lang.h" #include "language.h" #include "gwps.h" #include "powermgmt.h" #include "bookmark.h" #include "sprintf.h" #include "keyboard.h" #include "version.h" #include "rtc.h" #include "sound.h" #include "rbunicode.h" #include "dircache.h" #include "statusbar.h" #include "splash.h" #include "list.h" #ifdef HAVE_LCD_COLOR #include "backdrop.h" #endif #include "sound_menu.h" #ifdef CONFIG_TUNER #include "radio.h" #endif #include "setting_struct.h" #if CONFIG_CODEC == MAS3507D void dac_line_in(bool enable); #endif struct user_settings global_settings; #ifdef HAVE_RECORDING const char rec_base_directory[] = REC_BASE_DIR; #endif #if CONFIG_CODEC == SWCODEC #include "pcmbuf.h" #include "pcm_playback.h" #include "dsp.h" #endif #ifdef HAVE_WM8758 #include "eq_menu.h" #endif /* this only needs to be bumped if you add a RTC setting before other existing rtc settings */ #define RTC_RAM_CONFIG_VERSION 0 #ifdef HAVE_LCD_BITMAP #define MAX_LINES 10 #else #define MAX_LINES 2 #endif #ifdef HAVE_REMOTE_LCD #include "lcd-remote.h" #endif long lasttime = 0; #if 0 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) {7, S_O(mdb_strength), 0, "mdb strength", NULL}, {7, S_O(mdb_harmonics), 0, "mdb harmonics", NULL}, {9, S_O(mdb_center), 0, "mdb center", NULL}, {9, S_O(mdb_shape), 0, "mdb shape", NULL}, {1, S_O(mdb_enable), 0, "mdb enable", off_on}, #endif #if CONFIG_CODEC == MAS3507D {1, S_O(line_in), false, "line in", off_on }, #endif /* voice */ {2, S_O(talk_dir), 0, "talk dir", off_number_spell_hover }, {2, S_O(talk_file), 0, "talk file", off_number_spell_hover }, {1, S_O(talk_menu), true, "talk menu", off_on }, {2, S_O(sort_file), 0, "sort files", "alpha,oldest,newest,type" }, {2, S_O(sort_dir), 0, "sort dirs", "alpha,oldest,newest" }, {1, S_O(id3_v1_first), 0, "id3 tag priority", "v2-v1,v1-v2"}, #ifdef HAVE_RECORDING /* recording */ {1, S_O(recscreen_on), false, "recscreen on", off_on }, {1, S_O(rec_startup), false, "rec screen on startup", off_on }, {4, S_O(rec_timesplit), 0, "rec timesplit", /* 0...15 */ "off,00:05,00:10,00:15,00:30,01:00,01:14,01:20,02:00,04:00,06:00,08:00,10:00,12:00,18:00,24:00" }, {4, S_O(rec_sizesplit), 0, "rec sizesplit", /* 0...15 */ "off,5MB,10MB,15MB,32MB,64MB,75MB,100MB,128MB,256MB,512MB,650MB,700MB,1GB,1.5GB,1.75GB" }, {1, S_O(rec_channels), 0, "rec channels", "stereo,mono" }, {1, S_O(rec_split_type), 0, "rec split type", "Split, Stop" }, {1, S_O(rec_split_method), 0, "rec split method", "Time,Filesize" }, { #if defined(HAVE_SPDIF_IN) || defined(HAVE_FMRADIO_IN) 2, #else 1, #endif S_O(rec_source), 0 /* 0=mic */, "rec source", "mic,line" #ifdef HAVE_SPDIF_IN ",spdif" #endif #ifdef HAVE_FMRADIO_IN ",fmradio" #endif }, {5, S_O(rec_prerecord_time), 0, "prerecording time", NULL }, /* 0...30 */ {1, S_O(rec_directory), 0, /* rec_base_directory */ "rec directory", REC_BASE_DIR ",current" }, #ifdef CONFIG_BACKLIGHT {2, S_O(cliplight), 0, "cliplight", "off,main,both,remote" }, #endif #if CONFIG_CODEC == MAS3587F {4, S_O(rec_mic_gain), 8, "rec mic gain", NULL }, {4, S_O(rec_left_gain), 2 /* 0dB */, "rec left gain", NULL }, /* 0...15 */ {4, S_O(rec_right_gain), 2 /* 0dB */, "rec right gain", NULL }, /* 0...15 */ {3, S_O(rec_frequency), 0, /* 0=44.1kHz */ "rec frequency", "44,48,32,22,24,16" }, {3, S_O(rec_quality), 5 /* 192 kBit/s max */, "rec quality", NULL }, {1, S_O(rec_editable), false, "editable recordings", off_on }, #endif /* CONFIG_CODEC == MAS3587F */ #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) #ifdef HAVE_UDA1380 {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */ #endif #ifdef HAVE_TLV320 /* TLV320 only has no mic boost or 20db mic boost */ {1, S_O(rec_mic_gain), 0 /* 0 dB */, "rec mic gain", NULL }, /* 0db or 20db */ #endif {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */ {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */ #if 0 /* Till samplerates are added for SWCODEC */ {3, S_O(rec_frequency), 0, /* 0=44.1kHz */ "rec frequency", "44,48,32,22,24,16" }, #else {3, S_O(rec_frequency), 0, /* 0=44.1kHz */ "rec frequency", "44" }, #endif {4, S_O(rec_quality), 4 /* MP3 L3 192 kBit/s */, "rec quality", NULL }, #endif /* CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) */ /* values for the trigger */ {8 | SIGNED, S_O(rec_start_thres), -35, "trigger start threshold", NULL}, {8 | SIGNED, S_O(rec_stop_thres), -45, "trigger stop threshold", NULL}, {4, S_O(rec_start_duration), 0, "trigger start duration", trig_durations_conf}, {4, S_O(rec_stop_postrec), 2, "trigger stop postrec", trig_durations_conf}, {4, S_O(rec_stop_gap), 1, "trigger min gap", trig_durations_conf}, {4, S_O(rec_trigger_mode ), 0, "trigger mode", "off,once,repeat"}, #endif /* HAVE_RECORDING */ #ifdef HAVE_SPDIF_POWER {1, S_O(spdif_enable), false, "spdif enable", off_on}, #endif {1, S_O(next_folder), false, "folder navigation", off_on }, {1, S_O(runtimedb), false, "gather runtime data", off_on }, #if CONFIG_CODEC == SWCODEC {1, S_O(replaygain), false, "replaygain", off_on }, {2, S_O(replaygain_type), REPLAYGAIN_ALBUM, "replaygain type", "track,album,track shuffle" }, {1, S_O(replaygain_noclip), false, "replaygain noclip", off_on }, {8 | SIGNED, S_O(replaygain_preamp), 0, "replaygain preamp", NULL }, {2, S_O(beep), 0, "beep", "off,weak,moderate,strong" }, {2, S_O(crossfade), 0, "crossfade", "off,shuffle,track skip,always"}, {3, S_O(crossfade_fade_in_delay), 0, "crossfade fade in delay", NULL}, {3, S_O(crossfade_fade_out_delay), 0, "crossfade fade out delay", NULL}, {4, S_O(crossfade_fade_in_duration), 0, "crossfade fade in duration", NULL}, {4, S_O(crossfade_fade_out_duration), 0, "crossfade fade out duration", NULL}, {1, S_O(crossfade_fade_out_mixmode), 0, "crossfade fade out mode", "crossfade,mix"}, {1, S_O(crossfeed), false, "crossfeed", off_on }, {6, S_O(crossfeed_direct_gain), 15, "crossfeed direct gain", NULL }, {7, S_O(crossfeed_cross_gain), 60, "crossfeed cross gain", NULL }, {8, S_O(crossfeed_hf_attenuation), 160, "crossfeed hf attenuation", NULL }, {11, S_O(crossfeed_hf_cutoff), 700, "crossfeed hf cutoff", NULL }, /* equalizer */ {1, S_O(eq_enabled), false, "eq enabled", off_on }, {8, S_O(eq_precut), 0, "eq precut", NULL }, /* 0..32768 Hz */ {15, S_O(eq_band0_cutoff), 60, "eq band 0 cutoff", NULL }, {15, S_O(eq_band1_cutoff), 200, "eq band 1 cutoff", NULL }, {15, S_O(eq_band2_cutoff), 800, "eq band 2 cutoff", NULL }, {15, S_O(eq_band3_cutoff), 4000, "eq band 3 cutoff", NULL }, {15, S_O(eq_band4_cutoff), 12000, "eq band 4 cutoff", NULL }, /* 0..64 (or 0.0 to 6.4) */ {6, S_O(eq_band0_q), 7, "eq band 0 q", NULL }, {6, S_O(eq_band1_q), 10, "eq band 1 q", NULL }, {6, S_O(eq_band2_q), 10, "eq band 2 q", NULL }, {6, S_O(eq_band3_q), 10, "eq band 3 q", NULL }, {6, S_O(eq_band4_q), 7, "eq band 4 q", NULL }, /* -240..240 (or -24db to +24db) */ {9|SIGNED, S_O(eq_band0_gain), 0, "eq band 0 gain", NULL }, {9|SIGNED, S_O(eq_band1_gain), 0, "eq band 1 gain", NULL }, {9|SIGNED, S_O(eq_band2_gain), 0, "eq band 2 gain", NULL }, {9|SIGNED, S_O(eq_band3_gain), 0, "eq band 3 gain", NULL }, {9|SIGNED, S_O(eq_band4_gain), 0, "eq band 4 gain", NULL }, #endif #ifdef HAVE_DIRCACHE {1, S_O(dircache), false, "dircache", off_on }, {22, S_O(dircache_size), 0, NULL, NULL }, #endif #ifdef HAVE_TC_RAMCACHE {1, S_O(tagcache_ram), 0, "tagcache_ram", off_on }, #endif {1, S_O(tagcache_autoupdate), 0, "tagcache_autoupdate", off_on }, {4, S_O(default_codepage), 0, "default codepage", "iso8859-1,iso8859-7,iso8859-8,cp1251,iso8859-11,cp1256,iso8859-9,iso8859-2,sjis,gb2312,ksx1001,big5,utf-8,cp1256" }, {1, S_O(warnon_erase_dynplaylist), false, "warn when erasing dynamic playlist", off_on }, #ifdef CONFIG_BACKLIGHT #ifdef HAS_BUTTON_HOLD {2, S_O(backlight_on_button_hold), 0, "backlight on button hold", "normal,off,on" }, #endif #ifdef HAVE_LCD_SLEEP {4, S_O(lcd_sleep_after_backlight_off), 3, "lcd sleep after backlight off", "always,never,5,10,15,20,30,45,60,90" }, #endif #endif /* CONFIG_BACKLIGHT */ #ifdef HAVE_WM8758 {1, S_O(eq_hw_enabled), false, "eq hardware enabled", off_on }, {2, S_O(eq_hw_band0_cutoff), 1, "eq hardware band 0 cutoff", "80Hz,105Hz,135Hz,175Hz" }, {5|SIGNED, S_O(eq_hw_band0_gain), 12, "eq hardware band 0 gain", NULL }, {2, S_O(eq_hw_band1_center), 1, "eq hardware band 1 center", "230Hz,300Hz,385Hz,500Hz" }, {1, S_O(eq_hw_band1_bandwidth), 0, "eq hardware band 1 bandwidth", "narrow,wide" }, {5|SIGNED, S_O(eq_hw_band1_gain), 12, "eq hardware band 1 gain", NULL }, {2, S_O(eq_hw_band2_center), 1, "eq hardware band 2 center", "650Hz,850Hz,1.1kHz,1.4kHz" }, {1, S_O(eq_hw_band2_bandwidth), 0, "eq hardware band 2 bandwidth", "narrow,wide" }, {5|SIGNED, S_O(eq_hw_band2_gain), 12, "eq hardware band 2 gain", NULL }, {2, S_O(eq_hw_band3_center), 1, "eq hardware band 3 center", "1.8kHz,2.4kHz,3.2kHz,4.1kHz" }, {1, S_O(eq_hw_band3_bandwidth), 0, "eq hardware band 3 bandwidth", "narrow,wide" }, {5|SIGNED, S_O(eq_hw_band3_gain), 12, "eq hardware band 3 gain", NULL }, {2, S_O(eq_hw_band4_cutoff), 1, "eq hardware band 4 cutoff", "5.3kHz,6.9kHz,9kHz,11.7kHz" }, {5|SIGNED, S_O(eq_hw_band4_gain), 12, "eq hardware band 4 gain", NULL }, #endif {1, S_O(hold_lr_for_scroll_in_list), true, "hold_lr_for_scroll_in_list", off_on }, {2, S_O(show_path_in_browser), 0, "show path in browser", "off,current directory,full path" }, #ifdef HAVE_AGC {4, S_O(rec_agc_preset_mic), 1, "agc mic preset", NULL}, /* 0...5 */ {4, S_O(rec_agc_preset_line), 1, "agc line preset", NULL}, /* 0...5 */ {8|SIGNED, S_O(rec_agc_maxgain_mic), 104, "agc maximum mic gain", NULL}, {8|SIGNED, S_O(rec_agc_maxgain_line), 96, "agc maximum line gain", NULL}, {3, S_O(rec_agc_cliptime), 1, "agc cliptime", "0.2s,0.4s,0.6s,0.8,1s"}, #endif /* If values are just added to the end, no need to bump the version. */ /* new stuff to be added at the end */ /* Sum of all bit sizes must not grow beyond 0xB8*8 = 1472 */ }; #endif #ifdef HAVE_LCD_COLOR /* * Helper function to convert a string of 6 hex digits to a native colour */ #define hex2dec(c) (((c) >= '0' && ((c) <= '9')) ? (toupper(c)) - '0' : \ (toupper(c)) - 'A' + 10) int hex_to_rgb(const char* hex) { int ok = 1; int i; int red, green, blue; if (strlen(hex) == 6) { for (i=0; i < 6; i++ ) { if (!isxdigit(hex[i])) { ok=0; break; } } if (ok) { red = (hex2dec(hex[0]) << 4) | hex2dec(hex[1]); green = (hex2dec(hex[2]) << 4) | hex2dec(hex[3]); blue = (hex2dec(hex[4]) << 4) | hex2dec(hex[5]); return LCD_RGBPACK(red,green,blue); } } return 0; } #endif int settings_save( void ) { return 0; } #ifdef HAVE_LCD_BITMAP /** * Applies the range infos stored in global_settings to * the peak meter. */ void settings_apply_pm_range(void) { int pm_min, pm_max; /* depending on the scale mode (dBfs or percent) the values of global_settings.peak_meter_dbfs have different meanings */ if (global_settings.peak_meter_dbfs) { /* convert to dBfs * 100 */ pm_min = -(((int)global_settings.peak_meter_min) * 100); pm_max = -(((int)global_settings.peak_meter_max) * 100); } else { /* percent is stored directly -> no conversion */ pm_min = global_settings.peak_meter_min; pm_max = global_settings.peak_meter_max; } /* apply the range */ peak_meter_init_range(global_settings.peak_meter_dbfs, pm_min, pm_max); } #endif /* HAVE_LCD_BITMAP */ void sound_settings_apply(void) { sound_set(SOUND_BASS, global_settings.bass); sound_set(SOUND_TREBLE, global_settings.treble); sound_set(SOUND_BALANCE, global_settings.balance); sound_set(SOUND_VOLUME, global_settings.volume); #if CONFIG_CODEC == SWCODEC channels_set(global_settings.channel_config); stereo_width_set(global_settings.stereo_width); #else sound_set(SOUND_CHANNELS, global_settings.channel_config); sound_set(SOUND_STEREO_WIDTH, global_settings.stereo_width); #endif #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) sound_set(SOUND_LOUDNESS, global_settings.loudness); sound_set(SOUND_AVC, global_settings.avc); sound_set(SOUND_MDB_STRENGTH, global_settings.mdb_strength); sound_set(SOUND_MDB_HARMONICS, global_settings.mdb_harmonics); sound_set(SOUND_MDB_CENTER, global_settings.mdb_center); sound_set(SOUND_MDB_SHAPE, global_settings.mdb_shape); sound_set(SOUND_MDB_ENABLE, global_settings.mdb_enable); sound_set(SOUND_SUPERBASS, global_settings.superbass); #endif } void settings_apply(void) { char buf[64]; #if CONFIG_CODEC == SWCODEC int i; #endif DEBUGF( "settings_apply()\n" ); sound_settings_apply(); audio_set_buffer_margin(global_settings.buffer_margin); #ifdef HAVE_LCD_CONTRAST lcd_set_contrast(global_settings.contrast); #endif lcd_scroll_speed(global_settings.scroll_speed); #ifdef HAVE_REMOTE_LCD lcd_remote_set_contrast(global_settings.remote_contrast); lcd_remote_set_invert_display(global_settings.remote_invert); lcd_remote_set_flip(global_settings.remote_flip_display); lcd_remote_scroll_speed(global_settings.remote_scroll_speed); lcd_remote_scroll_step(global_settings.remote_scroll_step); lcd_remote_scroll_delay(global_settings.remote_scroll_delay * (HZ/10)); lcd_remote_bidir_scroll(global_settings.remote_bidir_limit); #ifdef HAVE_REMOTE_LCD_TICKING lcd_remote_emireduce(global_settings.remote_reduce_ticking); #endif remote_backlight_set_timeout(global_settings.remote_backlight_timeout); #ifdef CONFIG_CHARGING remote_backlight_set_timeout_plugged(global_settings.remote_backlight_timeout_plugged); #endif #endif #ifdef CONFIG_BACKLIGHT backlight_set_timeout(global_settings.backlight_timeout); #ifdef CONFIG_CHARGING backlight_set_timeout_plugged(global_settings.backlight_timeout_plugged); #endif #if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR) backlight_set_fade_in(global_settings.backlight_fade_in); backlight_set_fade_out(global_settings.backlight_fade_out); #endif #endif #ifdef HAVE_BACKLIGHT_BRIGHTNESS backlight_set_brightness(global_settings.brightness); #endif ata_spindown(global_settings.disk_spindown); #if (CONFIG_CODEC == MAS3507D) && !defined(SIMULATOR) dac_line_in(global_settings.line_in); #endif mpeg_id3_options(global_settings.id3_v1_first); #ifdef HAVE_ATA_POWER_OFF ata_poweroff(global_settings.disk_poweroff); #endif set_poweroff_timeout(global_settings.poweroff); set_battery_capacity(global_settings.battery_capacity); #if BATTERY_TYPES_COUNT > 1 set_battery_type(global_settings.battery_type); #endif #ifdef HAVE_LCD_BITMAP lcd_set_invert_display(global_settings.invert); lcd_set_flip(global_settings.flip_display); button_set_flip(global_settings.flip_display); lcd_update(); /* refresh after flipping the screen */ settings_apply_pm_range(); peak_meter_init_times( global_settings.peak_meter_release, global_settings.peak_meter_hold, global_settings.peak_meter_clip_hold); #endif #ifdef HAVE_LCD_COLOR unload_wps_backdrop(); #endif if ( global_settings.wps_file[0] && global_settings.wps_file[0] != 0xff ) { snprintf(buf, sizeof buf, WPS_DIR "/%s.wps", global_settings.wps_file); wps_data_load(gui_wps[0].data, buf, true); } else { wps_data_init(gui_wps[0].data); } #ifdef HAVE_LCD_COLOR if ( global_settings.backdrop_file[0] && global_settings.backdrop_file[0] != 0xff ) { snprintf(buf, sizeof buf, BACKDROP_DIR "/%s.bmp", global_settings.backdrop_file); load_main_backdrop(buf); } else { unload_main_backdrop(); } show_main_backdrop(); screens[SCREEN_MAIN].set_foreground(global_settings.fg_color); screens[SCREEN_MAIN].set_background(global_settings.bg_color); #endif #if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1) if ( global_settings.rwps_file[0] && global_settings.rwps_file[0] != 0xff ) { snprintf(buf, sizeof buf, WPS_DIR "/%s.rwps", global_settings.rwps_file); wps_data_load(gui_wps[1].data, buf, true); } else wps_data_init(gui_wps[1].data); #endif #ifdef HAVE_LCD_BITMAP if ( global_settings.font_file[0] && global_settings.font_file[0] != 0xff ) { snprintf(buf, sizeof buf, ROCKBOX_DIR FONT_DIR "/%s.fnt", global_settings.font_file); font_load(buf); } else font_reset(); if ( global_settings.kbd_file[0] && global_settings.kbd_file[0] != 0xff ) { snprintf(buf, sizeof buf, ROCKBOX_DIR "/%s.kbd", global_settings.kbd_file); load_kbd(buf); } else load_kbd(NULL); lcd_scroll_step(global_settings.scroll_step); gui_list_screen_scroll_step(global_settings.screen_scroll_step); gui_list_screen_scroll_out_of_view(global_settings.offset_out_of_view); #else lcd_jump_scroll(global_settings.jump_scroll); lcd_jump_scroll_delay(global_settings.jump_scroll_delay * (HZ/10)); #endif lcd_bidir_scroll(global_settings.bidir_limit); lcd_scroll_delay(global_settings.scroll_delay * (HZ/10)); if ( global_settings.lang_file[0] && global_settings.lang_file[0] != 0xff ) { snprintf(buf, sizeof buf, ROCKBOX_DIR LANG_DIR "/%s.lng", global_settings.lang_file); lang_load(buf); talk_init(); /* use voice of same language */ } set_codepage(global_settings.default_codepage); #if CONFIG_CODEC == SWCODEC audio_set_crossfade(global_settings.crossfade); dsp_set_replaygain(true); dsp_set_crossfeed(global_settings.crossfeed); dsp_set_crossfeed_direct_gain(global_settings.crossfeed_direct_gain); dsp_set_crossfeed_cross_params(global_settings.crossfeed_cross_gain, global_settings.crossfeed_cross_gain + global_settings.crossfeed_hf_attenuation, global_settings.crossfeed_hf_cutoff); dsp_set_eq(global_settings.eq_enabled); dsp_set_eq_precut(global_settings.eq_precut); /* Update all EQ bands */ for(i = 0; i < 5; i++) { dsp_set_eq_coefs(i); } #endif #ifdef HAVE_WM8758 eq_hw_enable(global_settings.eq_hw_enabled); #endif #ifdef HAVE_SPDIF_POWER spdif_power_enable(global_settings.spdif_enable); #endif #ifdef CONFIG_BACKLIGHT set_backlight_filter_keypress(global_settings.bl_filter_first_keypress); #ifdef HAVE_REMOTE_LCD set_remote_backlight_filter_keypress(global_settings.remote_bl_filter_first_keypress); #endif #ifdef HAS_BUTTON_HOLD backlight_set_on_button_hold(global_settings.backlight_on_button_hold); #endif #ifdef HAVE_LCD_SLEEP lcd_set_sleep_after_backlight_off(global_settings.lcd_sleep_after_backlight_off); #endif #endif /* CONFIG_BACKLIGHT */ } #define get_pointer_to_gs(v) &((uint8_t *)&global_settings)[v] #ifdef HAVE_RTC_RAM bool load_from_rtc(int rtc_item, int *value) { if (!rtc_read_multiple(0x14+(rtc_item*4),(char*)value,4)) return true; return false; } bool save_to_rtc(int rtc_item, int value) { union { int i; char c[4]; } storage; int j = 0; int ret=0, address = 0x14+(rtc_item*4); storage.i = value; for(j=0; j<4 && ret==0;j++) { ret = rtc_write(address+j, storage.c[j]); } return (ret==0) ? true : false; } #endif /* * load settings from disk or RTC RAM */ void settings_load(int which) { DEBUGF( "reload_all_settings()\n" ); #ifdef HAVE_RTC_RAM if (which&SETTINGS_RTC) { int i, value, rtc_item = 0; bool config_ok = false; if (load_from_rtc(rtc_item,&value) == true) { if (value == RTC_RAM_CONFIG_VERSION) config_ok = true; } rtc_item++; for (i=0; i maxlen)) return; strncpy(setting, fptr, len-extlen); setting[len-extlen]=0; settings_save(); } void save_item_to_gs(const struct settings_list *item, char* new_val) { switch (item->flags&F_T_MASK) { case F_T_INT: #ifdef HAVE_LCD_COLOR if (item->flags&F_STORERGB) { *(int*)get_pointer_to_gs(item->setting_offset) = hex_to_rgb(new_val); } else #endif *(int*)get_pointer_to_gs(item->setting_offset) = atoi(new_val); break; case F_T_UINT: *(unsigned int*)get_pointer_to_gs(item->setting_offset) = (unsigned int)atoi(new_val); break; case F_T_BOOL: if (!strcmp(new_val,"on")) *(bool*)get_pointer_to_gs(item->setting_offset) = true; else *(bool*)get_pointer_to_gs(item->setting_offset) = false; break; case F_T_CHARPTR: case F_T_UCHARPTR: strcpy(*(char**)get_pointer_to_gs(item->setting_offset),new_val); break; } } bool settings_load_config(const char* file) { int fd; char line[256]; char* name; char* value; int pos; /* currently returned position */ const struct settings_list *item; int len_remote = strlen("remote "); fd = open(file, O_RDONLY); if (fd < 0) return false; while (read_line(fd, line, sizeof line) > 0) { if (!settings_parseline(line, &name, &value)) continue; for (pos = 0; pos < nb_settings ; pos++) { item = &settings[pos]; /* check if the item is a remote item, ignore it if it is and remote doesnt match */ if (item->flags&F_LANG_REMOTE) { if (strncmp(name,"remote ",len_remote)) continue; name += len_remote; } if (item->flags&(F_SYSTEMSETTING|F_STORERGB)) { if (!strcmp(name,item->cfg_string)) { save_item_to_gs(item,value); break; } } else { if (!strcmp(name,english_str(item->cfg_lang_id))) { save_item_to_gs(item,value); break; } } } /* for (...) */ } close(fd); // settings_apply(); // settings_save(); return true; } bool settings_save_config(void) { int fd_cfg, fd_dat, fd; int i, value = 0, type; char *name, *char_value; const struct settings_list *item; #ifdef HAVE_RTC_RAM fd = 0; save_to_rtc(fd, RTC_RAM_CONFIG_VERSION); fd++; for (i=0; iflags&F_T_MASK; if (item->flags&F_SYSTEMSETTING) { name = item->cfg_string; fd = fd_dat; } #ifdef HAVE_LCD_COLOR else if (item->flags&F_STORERGB) { name = item->cfg_string; fd = fd_cfg; } #endif else { name = english_str(item->cfg_lang_id); fd = fd_cfg; } DEBUGF("%d, %s\n",i,name); char_value = NULL; switch (type) { case F_T_INT: value = *(int*)get_pointer_to_gs(item->setting_offset); if ((item->flags&(F_T_CHOICE|F_SYSTEMSETTING|F_STORERGB|F_T_SOUND)) == 0) fdprintf(fd,"# %s - min=%d, max=%d, step=%d\r\n",name, item->values[0],item->values[1],item->values[2]); break; case F_T_UINT: value = *(unsigned int*)get_pointer_to_gs(item->setting_offset); if ((item->flags&(F_T_CHOICE|F_SYSTEMSETTING|F_STORERGB|F_T_SOUND)) == 0) fdprintf(fd,"# %s - min=%d, max=%d, step=%d\r\n",name, item->values[0],item->values[1],item->values[2]); break; case F_T_BOOL: char_value = (*(bool*)get_pointer_to_gs(item->setting_offset)==true)?"on":"off"; fdprintf(fd,"# %s - on, off\r\n",name); break; case F_T_CHARPTR: case F_T_UCHARPTR: char_value = *(char**)get_pointer_to_gs(item->setting_offset); break; } if (item->flags&F_T_CHOICE) { int j; fdprintf(fd,"# %s%s - ",(item->flags&F_LANG_REMOTE)?"remote ":"", name); for(j=0; j < item->nb_values; j++) { fdprintf(fd,"%s%c ",(item->flags&F_LANG_STRING) ? item->strings[j] : english_str(item->values[j]),(j+1 < item->nb_values)?',':'\0' ); } fdprintf(fd,"\r\n"); if (item->flags&F_LANG_STRING) char_value = item->strings[value]; else char_value = english_str(item->values[value]); } #ifdef HAVE_LCD_COLOR if (item->flags&F_STORERGB) { fdprintf(fd, "%s: %02x%02x%02x\r\n", name, (int)RGB_UNPACK_RED(value), (int)RGB_UNPACK_GREEN(value), (int)RGB_UNPACK_BLUE(value)); } else #endif if (char_value == NULL) { fdprintf(fd,"%s%s: %d\r\n",(item->flags&F_LANG_REMOTE)?"remote ":"", name, value); } else { fdprintf(fd,"%s%s: %s\r\n",(item->flags&F_LANG_REMOTE)?"remote ":"", name, char_value); } } /* for(...) */ close(fd_cfg); close(fd_dat); gui_syncsplash(HZ, true, str(LANG_SETTINGS_SAVED)); return true; } /* * reset all settings to their default value */ void settings_reset(void) { int i; const struct settings_list *item; DEBUGF( "settings_reset()\n" ); for (i = 0; i < nb_settings ; i++) { item = &settings[i]; if (item->flags&F_T_SOUND) { *(int*)get_pointer_to_gs(item->setting_offset) = sound_default(item->values[0]); continue; } switch (item->flags&F_T_MASK) { case F_T_INT: *(int*)get_pointer_to_gs(item->setting_offset) = item->default_val.int_; break; case F_T_UINT: *(unsigned int*)get_pointer_to_gs(item->setting_offset) = item->default_val.uint_; break; case F_T_BOOL: *(bool*)get_pointer_to_gs(item->setting_offset) = item->default_val.bool_; break; case F_T_CHARPTR: case F_T_UCHARPTR: strcpy(*(char**)get_pointer_to_gs(item->setting_offset),item->default_val.charptr); break; } } /* for (...) */ } bool set_bool(const char* string, bool* variable ) { return set_bool_options(string, variable, (char *)STR(LANG_SET_BOOL_YES), (char *)STR(LANG_SET_BOOL_NO), NULL); } /* wrapper to convert from int param to bool param in set_option */ static void (*boolfunction)(bool); void bool_funcwrapper(int value) { if (value) boolfunction(true); else boolfunction(false); } bool set_bool_options(const char* string, bool* variable, const char* yes_str, int yes_voice, const char* no_str, int no_voice, void (*function)(bool)) { struct opt_items names[] = { {(unsigned char *)no_str, no_voice}, {(unsigned char *)yes_str, yes_voice} }; bool result; boolfunction = function; result = set_option(string, variable, BOOL, names, 2, function ? bool_funcwrapper : NULL); return result; } void talk_unit(int unit, int value) { if (global_settings.talk_menu) { if (unit < UNIT_LAST) { /* use the available unit definition */ talk_value(value, unit, false); } else { /* say the number, followed by an arbitrary voice ID */ talk_number(value, false); talk_id(unit, true); } } } struct value_setting_data { enum optiontype type; /* used for "value" settings.. */ int max; int step; int voice_unit; const char * unit; void (*formatter)(char* dest, int dest_length, int variable, const char* unit); /* used for BOOL and "choice" settings */ struct opt_items* options; }; char * value_setting_get_name_cb(int selected_item,void * data, char *buffer) { struct value_setting_data* cb_data = (struct value_setting_data*)data; if (cb_data->type == INT && !cb_data->options) { int item = cb_data->max -(selected_item*cb_data->step); if (cb_data->formatter) cb_data->formatter(buffer, MAX_PATH,item,cb_data->unit); else snprintf(buffer, MAX_PATH,"%d %s",item,cb_data->unit); } else strcpy(buffer,P2STR(cb_data->options[selected_item].string)); return buffer; } #define type_fromvoidptr(type, value) \ (type == INT)? \ (int)(*(int*)(value)) \ : \ (bool)(*(bool*)(value)) bool do_set_setting(const unsigned char* string, void *variable, int nb_items,int selected, struct value_setting_data *cb_data, void (*function)(int)) { int action; bool done = false; struct gui_synclist lists; int oldvalue; if (cb_data->type == INT) oldvalue = *(int*)variable; else oldvalue = *(bool*)variable; gui_synclist_init(&lists,value_setting_get_name_cb,(void*)cb_data,false,1); gui_synclist_set_title(&lists, (char*)string, NOICON); gui_synclist_set_icon_callback(&lists,NULL); gui_synclist_set_nb_items(&lists,nb_items); gui_synclist_limit_scroll(&lists,true); gui_synclist_select_item(&lists, selected); if (global_settings.talk_menu) { if (cb_data->type == INT && !cb_data->options) talk_unit(cb_data->voice_unit, *(int*)variable); else talk_id(cb_data->options[selected].voice_id, false); } gui_synclist_draw(&lists); while (!done) { action = get_action(CONTEXT_LIST,TIMEOUT_BLOCK); if (action == ACTION_NONE) continue; if (gui_synclist_do_button(&lists,action)) { if (global_settings.talk_menu) { int value; if (cb_data->type == INT && !cb_data->options) { value = cb_data->max - gui_synclist_get_sel_pos(&lists)*cb_data->step; talk_unit(cb_data->voice_unit, value); } else { value = gui_synclist_get_sel_pos(&lists); talk_id(cb_data->options[value].voice_id, false); } } if (cb_data->type == INT && !cb_data->options) *(int*)variable = cb_data->max - gui_synclist_get_sel_pos(&lists)*cb_data->step; else if (cb_data->type == BOOL) *(bool*)variable = gui_synclist_get_sel_pos(&lists) ? true : false; else *(int*)variable = gui_synclist_get_sel_pos(&lists); } else if (action == ACTION_STD_CANCEL) { gui_syncsplash(HZ/2,true,str(LANG_MENU_SETTING_CANCEL)); if (cb_data->type == INT) *(int*)variable = oldvalue; else *(bool*)variable = (bool)oldvalue; done = true; } else if (action == ACTION_STD_OK) { done = true; } else if(default_event_handler(action) == SYS_USB_CONNECTED) return true; gui_syncstatusbar_draw(&statusbars, false); if ( function ) function(type_fromvoidptr(cb_data->type,variable)); } return false; } bool set_int(const unsigned char* string, const char* unit, int voice_unit, int* variable, void (*function)(int), int step, int min, int max, void (*formatter)(char*, int, int, const char*) ) { struct value_setting_data data = { INT,max, step, voice_unit,unit,formatter,NULL }; return do_set_setting(string,variable,(max-min)/step + 1, (max-*variable)/step, &data,function); } /* NOTE: the 'type' parameter specifies the actual type of the variable that 'variable' points to. not the value within. Only variables with type 'bool' should use parameter BOOL. The type separation is necessary since int and bool are fundamentally different and bit-incompatible types and can not share the same access code. */ bool set_option(const char* string, void* variable, enum optiontype type, const struct opt_items* options, int numoptions, void (*function)(int)) { struct value_setting_data data = { type,0, 0, 0,NULL,NULL,(struct opt_items*)options }; int selected; if (type == BOOL) selected = *(bool*)variable ? 1 : 0; else selected = *(int*)variable; return do_set_setting(string,variable,numoptions, selected, &data,function); } #define MAX_OPTIONS 64 bool load_setting_screen(struct settings_list *setting) { void* variable; int temp_var = 0; bool ret = false; if(!setting) return false; variable = get_pointer_to_gs(setting->setting_offset); switch (setting->flags&F_T_MASK) { case F_T_BOOL: if (setting->flags&F_TEMPVARIABLE) { variable = (void*)temp_var; *(bool*)variable = *(bool*)get_pointer_to_gs(setting->setting_offset); ret = set_bool(ID2P(setting->cfg_lang_id),(bool*)variable); if (*(bool*)variable != *(bool*)get_pointer_to_gs(setting->setting_offset)) *(bool*)get_pointer_to_gs(setting->setting_offset) = *(bool*)variable; } else ret = set_bool(str(setting->cfg_lang_id),(bool*)variable); break; case F_T_INT: case F_T_UINT: if (setting->flags&F_T_CHOICE) { static struct opt_items options[MAX_OPTIONS]; int i; for (i=0; inb_values && iflags&F_LANG_STRING) { options[i].string = setting->strings[i]; if (settings->talk_id != NULL) options[i].voice_id = settings->talk_id[i]; } else options[i].string = ID2P(setting->values[i]); } if (setting->flags&F_TEMPVARIABLE) { variable = (void*)temp_var; *(int*)variable = *(int*)get_pointer_to_gs(setting->setting_offset); ret = set_option(ID2P(setting->cfg_lang_id),variable,INT, options, i, (void*)setting->function); if (*(int*)variable != *(int*)get_pointer_to_gs(setting->setting_offset)) *(int*)get_pointer_to_gs(setting->setting_offset) = *(int*)variable; } else ret = set_option(str(setting->cfg_lang_id),variable,INT, options, i, (void*)setting->function); } else if (setting->flags&F_T_SOUND) { ret = set_sound(str(setting->cfg_lang_id), (int*)variable,setting->values[0]); } else { if (setting->flags&F_TEMPVARIABLE) { variable = (void*)temp_var; *(int*)variable = *(int*)get_pointer_to_gs(setting->setting_offset); } ret = set_int(str(setting->cfg_lang_id),str(setting->talk_id[0]),setting->talk_id[0], (int*)variable,(void*)setting->function,setting->values[2], setting->values[0],setting->values[1],(void*)setting->values[3]); if (setting->flags&F_TEMPVARIABLE) { if (*(int*)variable != *(int*)get_pointer_to_gs(setting->setting_offset)) *(int*)get_pointer_to_gs(setting->setting_offset) = *(int*)variable; } } break; } return ret; } const struct settings_list *find_setting(void* variable) { int i; void* var; for (i=0; i