Add optional icon to list title, current path display shows a dir icon, and list...
[Rockbox.git] / apps / settings.c
blob49b8f9826b48067e4334b934ab2ece8baa0e5edd
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 <limits.h>
23 #include "inttypes.h"
24 #include "config.h"
25 #include "kernel.h"
26 #include "thread.h"
27 #include "action.h"
28 #include "settings.h"
29 #include "disk.h"
30 #include "panic.h"
31 #include "debug.h"
32 #include "usb.h"
33 #include "backlight.h"
34 #include "lcd.h"
35 #include "audio.h"
36 #include "mp3_playback.h"
37 #include "mpeg.h"
38 #include "talk.h"
39 #include "string.h"
40 #include "ata.h"
41 #include "fat.h"
42 #include "power.h"
43 #include "powermgmt.h"
44 #include "status.h"
45 #include "atoi.h"
46 #include "screens.h"
47 #include "ctype.h"
48 #include "file.h"
49 #include "errno.h"
50 #include "system.h"
51 #include "misc.h"
52 #include "timefuncs.h"
53 #ifdef HAVE_LCD_BITMAP
54 #include "icons.h"
55 #include "font.h"
56 #include "peakmeter.h"
57 #include "hwcompat.h"
58 #endif
59 #include "lang.h"
60 #include "language.h"
61 #include "gwps.h"
62 #include "powermgmt.h"
63 #include "bookmark.h"
64 #include "sprintf.h"
65 #include "keyboard.h"
66 #include "version.h"
67 #include "rtc.h"
68 #include "sound.h"
69 #include "rbunicode.h"
70 #include "dircache.h"
71 #include "statusbar.h"
72 #include "splash.h"
73 #include "list.h"
74 #ifdef HAVE_LCD_COLOR
75 #include "backdrop.h"
76 #endif
78 #ifdef CONFIG_TUNER
79 #include "radio.h"
80 #endif
82 #if CONFIG_CODEC == MAS3507D
83 void dac_line_in(bool enable);
84 #endif
85 struct user_settings global_settings;
86 #ifdef HAVE_RECORDING
87 const char rec_base_directory[] = REC_BASE_DIR;
88 #endif
89 #if CONFIG_CODEC == SWCODEC
90 #include "pcmbuf.h"
91 #include "pcm_playback.h"
92 #include "dsp.h"
93 #endif
95 #define CONFIG_BLOCK_VERSION 50
96 #define CONFIG_BLOCK_SIZE 512
97 #define RTC_BLOCK_SIZE 44
99 #ifdef HAVE_LCD_BITMAP
100 #define MAX_LINES 10
101 #else
102 #define MAX_LINES 2
103 #endif
105 #ifdef HAVE_REMOTE_LCD
106 #include "lcd-remote.h"
107 #endif
109 long lasttime = 0;
110 static long config_sector = 0; /* mark uninitialized */
111 static unsigned char config_block[CONFIG_BLOCK_SIZE];
114 /* descriptor for a configuration value */
115 /* (watch the struct packing and member sizes to keep this small) */
116 struct bit_entry
118 /* how many bits within the bitfield (1-32), MSB set if value is signed */
119 unsigned char bit_size; /* min 6+1 bit */
120 /* how many bytes in the global_settings struct (1,2,4) */
121 unsigned char byte_size; /* min 3 bits */
122 /* store position in global_settings struct */
123 short settings_offset; /* min 9 bit, better 10 */
124 /* default value */
125 int default_val; /* min 15 bit */
126 /* variable name in a .cfg file, NULL if not to be saved */
127 const char* cfg_name;
128 /* set of values, "rgb" for a color, or NULL for a numerical value */
129 const char* cfg_val;
132 /********************************************
134 Config block as saved on the battery-packed RTC user RAM memory block
135 of 44 bytes, starting at offset 0x14 of the RTC memory space.
137 offset abs
138 0x00 0x14 "Roc" header signature: 0x52 0x6f 0x63
139 0x03 0x17 <version byte: 0x0>
140 0x04 0x18 start of bit-table
142 0x28,0x29 unused, not reachable by set_bits() without disturbing the next 2
143 0x2A,0x2B <checksum 2 bytes: xor of 0x00-0x29>
145 Config memory is reset to 0xff and initialized with 'factory defaults' if
146 a valid header & checksum is not found. Config version number is only
147 increased when information is _relocated_ or space is _reused_ so that old
148 versions can read and modify configuration changed by new versions.
149 Memory locations not used by a given version should not be
150 modified unless the header & checksum test fails.
152 Rest of config block, only saved to disk:
153 0x2C start of 2nd bit-table
155 0xA4 (char[20]) FMR Preset file
156 0xB8 (char[20]) WPS file
157 0xCC (char[20]) Lang file
158 0xE0 (char[20]) Font file
159 ... (char[20]) RWPS file (on targets supporting a Remote WPS)
160 ... (char[20]) Main backdrop file (on color LCD targets)
162 ... to 0x200 <unused>
164 *************************************/
166 /* The persistence of the global_settings members is now controlled by
167 the two tables below, rtc_bits and hd_bits.
168 New values can just be added to the end, it will be backwards
169 compatible. If you however change order, bitsize, etc. of existing
170 entries, you need to bump CONFIG_BLOCK_VERSION to break compatibility.
174 /* convenience macro for both size and offset of global_settings member */
175 #define S_O(val) sizeof(global_settings.val), offsetof(struct user_settings, val)
176 #define SIGNED 0x80 /* for bitsize value with signed attribute */
178 /* some sets of values which are used more than once, to save memory */
179 static const char off_on[] = "off,on";
180 static const char off_on_ask[] = "off,on,ask";
181 static const char off_number_spell_hover[] = "off,number,spell,hover";
182 #ifdef HAVE_LCD_BITMAP
183 static const char graphic_numeric[] = "graphic,numeric";
184 #endif
186 #ifdef HAVE_RECORDING
187 /* keep synchronous to trig_durations and
188 trigger_times in settings_apply_trigger */
189 static const char trig_durations_conf [] =
190 "0s,1s,2s,5s,10s,15s,20s,25s,30s,1min,2min,5min,10min";
191 #endif
193 #if defined(CONFIG_BACKLIGHT)
194 static const char backlight_times_conf [] =
195 "off,on,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60,90";
196 #endif
198 /* the part of the settings which ends up in the RTC RAM, where available
199 (those we either need early, save frequently, or without spinup) */
200 static const struct bit_entry rtc_bits[] =
202 /* placeholder, containing the size information */
203 {9, 0, 0, 0, NULL, NULL }, /* 9 bit to tell how far this is populated */
205 /* # of bits, offset+size, default, .cfg name, .cfg values */
206 /* sound */
207 #if CONFIG_CODEC == MAS3507D
208 {8 | SIGNED, S_O(volume), -18, "volume", NULL }, /* -78...+18 */
209 #else
210 {8 | SIGNED, S_O(volume), -25, "volume", NULL }, /* -100...+12 / -84...0 */
211 #endif
212 {8 | SIGNED, S_O(balance), 0, "balance", NULL }, /* -100...100 */
213 #if CONFIG_CODEC != SWCODEC /* any MAS */
214 {5 | SIGNED, S_O(bass), 0, "bass", NULL }, /* -15..+15 / -12..+12 */
215 {5 | SIGNED, S_O(treble), 0, "treble", NULL }, /* -15..+15 / -12..+12 */
216 #elif defined HAVE_UDA1380
217 {5, S_O(bass), 0, "bass", NULL }, /* 0..+24 */
218 {3, S_O(treble), 0, "treble", NULL }, /* 0..+6 */
219 #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
220 || defined(HAVE_WM8731) || defined(HAVE_WM8721)
221 {5 | SIGNED, S_O(bass), 0, "bass", NULL }, /* -6..+9 */
222 {5 | SIGNED, S_O(treble), 0, "treble", NULL }, /* -6..+9 */
223 #endif
224 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
225 {5, S_O(loudness), 0, "loudness", NULL }, /* 0...17 */
226 {3, S_O(avc), 0, "auto volume", "off,20ms,2,4,8" },
227 {1, S_O(superbass), false, "superbass", off_on },
228 #endif
229 {3, S_O(channel_config), 0, "channels",
230 "stereo,mono,custom,mono left,mono right,karaoke" },
231 {8, S_O(stereo_width), 100, "stereo width", NULL},
232 /* playback */
233 {1, S_O(resume), false, "resume", off_on },
234 {1, S_O(playlist_shuffle), false, "shuffle", off_on },
235 {16 | SIGNED, S_O(resume_index), -1, NULL, NULL },
236 {16 | SIGNED, S_O(resume_first_index), 0, NULL, NULL },
237 {32 | SIGNED, S_O(resume_offset), -1, NULL, NULL },
238 {32 | SIGNED, S_O(resume_seed), -1, NULL, NULL },
239 {3, S_O(repeat_mode), REPEAT_ALL, "repeat", "off,all,one,shuffle,ab" },
240 /* LCD */
241 #ifdef HAVE_LCD_CONTRAST
242 {6, S_O(contrast), DEFAULT_CONTRAST_SETTING, "contrast", NULL },
243 #endif
244 #ifdef CONFIG_BACKLIGHT
245 {5, S_O(backlight_timeout), 6, "backlight timeout", backlight_times_conf },
246 #ifdef CONFIG_CHARGING
247 {5, S_O(backlight_timeout_plugged), 11, "backlight timeout plugged",
248 backlight_times_conf },
249 #endif
250 #endif /* CONFIG_BACKLIGHT */
251 #ifdef HAVE_LCD_BITMAP
252 {1, S_O(invert), false, "invert", off_on },
253 {1, S_O(flip_display), false, "flip display", off_on },
254 /* display */
255 {1, S_O(invert_cursor), true, "invert cursor", off_on },
256 {1, S_O(statusbar), true, "statusbar", off_on },
257 {1, S_O(scrollbar), true, "scrollbar", off_on },
258 #if CONFIG_KEYPAD == RECORDER_PAD
259 {1, S_O(buttonbar), true, "buttonbar", off_on },
260 #endif
261 {1, S_O(volume_type), 0, "volume display", graphic_numeric },
262 {1, S_O(battery_display), 0, "battery display", graphic_numeric },
263 {1, S_O(timeformat), 0, "time format", "24hour,12hour" },
264 #endif /* HAVE_LCD_BITMAP */
265 {1, S_O(show_icons), true, "show icons", off_on },
266 /* system */
267 {4, S_O(poweroff), 10,
268 "idle poweroff", "off,1,2,3,4,5,6,7,8,9,10,15,30,45,60" },
269 {18, S_O(runtime), 0, NULL, NULL },
270 {18, S_O(topruntime), 0, NULL, NULL },
271 #if MEM > 1
272 {15, S_O(max_files_in_playlist), 10000,
273 "max files in playlist", NULL }, /* 1000...20000 */
274 {14, S_O(max_files_in_dir), 400,
275 "max files in dir", NULL }, /* 50...10000 */
276 #else
277 {15, S_O(max_files_in_playlist), 1000,
278 "max files in playlist", NULL }, /* 1000...20000 */
279 {14, S_O(max_files_in_dir), 200,
280 "max files in dir", NULL }, /* 50...10000 */
281 #endif
282 /* battery */
283 {12, S_O(battery_capacity), BATTERY_CAPACITY_DEFAULT, "battery capacity",
284 NULL }, /* 1500...3200 for NiMH, 2200...3200 for LiIon,
285 500...1500 for Alkaline */
286 #ifdef CONFIG_CHARGING
287 {1, S_O(car_adapter_mode), false, "car adapter mode", off_on },
288 #endif
289 /* tuner */
290 #ifdef CONFIG_TUNER
291 {1, S_O(fm_force_mono), false, "force fm mono", off_on },
292 {8, S_O(last_frequency), 0, NULL, NULL }, /* Default: MIN_FREQ */
293 #endif
295 #if BATTERY_TYPES_COUNT > 1
296 {1, S_O(battery_type), 0, "battery type", "alkaline,nimh" },
297 #endif
299 #ifdef HAVE_REMOTE_LCD
300 /* remote lcd */
301 {6, S_O(remote_contrast), 42, "remote contrast", NULL },
302 {1, S_O(remote_invert), false, "remote invert", off_on },
303 {1, S_O(remote_flip_display), false, "remote flip display", off_on },
304 {5, S_O(remote_backlight_timeout), 6, "remote backlight timeout",
305 backlight_times_conf },
306 #ifdef CONFIG_CHARGING
307 {5, S_O(remote_backlight_timeout_plugged), 11,
308 "remote backlight timeout plugged", backlight_times_conf },
309 #endif
310 #ifdef HAVE_REMOTE_LCD_TICKING
311 {1, S_O(remote_reduce_ticking), false, "remote reduce ticking", off_on },
312 #endif
313 #endif
315 #ifdef CONFIG_BACKLIGHT
316 {1, S_O(bl_filter_first_keypress), false,
317 "backlight filters first keypress", off_on },
318 #ifdef HAVE_REMOTE_LCD
319 {1, S_O(remote_bl_filter_first_keypress), false,
320 "backlight filters first remote keypress", off_on },
321 #endif
322 #endif /* CONFIG_BACKLIGHT */
324 /* new stuff to be added here */
325 /* If values are just added to the end, no need to bump the version. */
327 /* Current sum of bits: 277 (worst case, but w/o remote lcd) */
328 /* Sum of all bit sizes must not grow beyond 288! */
332 /* the part of the settings which ends up in HD sector only */
333 static const struct bit_entry hd_bits[] =
335 /* This table starts after the 44 RTC bytes = 352 bits. */
336 /* Here we need 11 bits to tell how far this is populated. */
338 /* placeholder, containing the size information */
339 {11, 0, 0, 0, NULL, NULL }, /* 11 bit to tell how far this is populated */
341 /* # of bits, offset+size, default, .cfg name, .cfg values */
342 /* more display */
343 #ifdef CONFIG_BACKLIGHT
344 {1, S_O(caption_backlight), false, "caption backlight", off_on },
345 #endif
346 #ifdef HAVE_REMOTE_LCD
347 {1, S_O(remote_caption_backlight), false,
348 "remote caption backlight", off_on },
349 #endif
350 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
351 {4, S_O(brightness), DEFAULT_BRIGHTNESS_SETTING, "brightness", NULL },
352 #endif
353 #ifdef HAVE_BACKLIGHT_PWM_FADING
354 /* backlight fading */
355 {2, S_O(backlight_fade_in), 1, "backlight fade in", "off,500ms,1s,2s"},
356 {3, S_O(backlight_fade_out), 3, "backlight fade out",
357 "off,500ms,1s,2s,3s,4s,5s,10s"},
358 #endif
360 {4, S_O(scroll_speed), 9, "scroll speed", NULL }, /* 0...15 */
361 {8, S_O(scroll_delay), 100, "scroll delay", NULL }, /* 0...250 */
362 {8, S_O(bidir_limit), 50, "bidir limit", NULL }, /* 0...200 */
364 #ifdef HAVE_REMOTE_LCD
365 {4, S_O(remote_scroll_speed), 9, "remote scroll speed", NULL }, /* 0...15 */
366 {8, S_O(remote_scroll_step), 6, "remote scroll step", NULL }, /* 1...160 */
367 {8, S_O(remote_scroll_delay), 100, "remote scroll delay", NULL }, /* 0...250 */
368 {8, S_O(remote_bidir_limit), 50, "remote bidir limit", NULL }, /* 0...200 */
369 #endif
371 #ifdef HAVE_LCD_BITMAP
372 {1, S_O(offset_out_of_view), false, "Screen Scrolls Out Of View", off_on },
373 #if LCD_WIDTH > 255
374 {9, S_O(scroll_step), 6, "scroll step", NULL },
375 {9, S_O(screen_scroll_step), 16, "screen scroll step", NULL },
376 #elif LCD_WIDTH > 127
377 {8, S_O(scroll_step), 6, "scroll step", NULL },
378 {8, S_O(screen_scroll_step), 16, "screen scroll step", NULL },
379 #else
380 {7, S_O(scroll_step), 6, "scroll step", NULL },
381 {7, S_O(screen_scroll_step), 16, "screen scroll step", NULL },
382 #endif
383 #endif /* HAVE_LCD_BITMAP */
384 #ifdef HAVE_LCD_CHARCELLS
385 {3, S_O(jump_scroll), 0, "jump scroll", NULL }, /* 0...5 */
386 {8, S_O(jump_scroll_delay), 50, "jump scroll delay", NULL }, /* 0...250 */
387 #endif
388 {1, S_O(scroll_paginated), false, "scroll paginated", off_on },
390 #ifdef HAVE_LCD_COLOR
391 {LCD_DEPTH,S_O(fg_color),LCD_DEFAULT_FG,"foreground color","rgb"},
392 {LCD_DEPTH,S_O(bg_color),LCD_DEFAULT_BG,"background color","rgb"},
393 #endif
395 /* more playback */
396 {1, S_O(play_selected), true, "play selected", off_on },
397 {1, S_O(fade_on_stop), true, "volume fade", off_on },
398 {4, S_O(ff_rewind_min_step), FF_REWIND_1000,
399 "scan min step", "1,2,3,4,5,6,8,10,15,20,25,30,45,60" },
400 {4, S_O(ff_rewind_accel), 3, "scan accel", NULL },
401 #if CONFIG_CODEC == SWCODEC
402 {3, S_O(buffer_margin), 0, "antiskip",
403 "5s,15s,30s,1min,2min,3min,5min,10min" },
404 #else
405 {3, S_O(buffer_margin), 0, "antiskip", NULL },
406 #endif
407 /* disk */
408 #ifndef HAVE_MMC
409 #ifdef HAVE_ATA_POWER_OFF
410 {1, S_O(disk_poweroff), false, "disk poweroff", off_on },
411 #endif
412 {8, S_O(disk_spindown), 5, "disk spindown", NULL },
413 #endif /* HAVE_MMC */
415 /* browser */
416 {3, S_O(dirfilter), SHOW_SUPPORTED,
417 "show files", "all,supported,music,playlists,id3 database" },
418 {1, S_O(sort_case), false, "sort case", off_on },
419 {1, S_O(browse_current), false, "follow playlist", off_on },
420 /* playlist */
421 {1, S_O(playlist_viewer_icons), true, "playlist viewer icons", off_on },
422 {1, S_O(playlist_viewer_indices), true,
423 "playlist viewer indices", off_on },
424 {1, S_O(playlist_viewer_track_display), 0,
425 "playlist viewer track display", "track name,full path" },
426 {2, S_O(recursive_dir_insert), RECURSE_OFF,
427 "recursive directory insert", off_on_ask },
428 /* bookmarks */
429 {3, S_O(autocreatebookmark), BOOKMARK_NO, "autocreate bookmarks",
430 "off,on,ask,recent only - on,recent only - ask" },
431 {2, S_O(autoloadbookmark), BOOKMARK_NO,
432 "autoload bookmarks", off_on_ask },
433 {2, S_O(usemrb), BOOKMARK_NO,
434 "use most-recent-bookmarks", "off,on,unique only" },
435 #ifdef HAVE_LCD_BITMAP
436 /* peak meter */
437 {5, S_O(peak_meter_clip_hold), 16, "peak meter clip hold", /* 0...25 */
438 "on,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60,90,2min,3min,5min,10min,20min,45min,90min" },
439 {5, S_O(peak_meter_hold), 3, "peak meter hold",
440 "off,200ms,300ms,500ms,1,2,3,4,5,6,7,8,9,10,15,20,30,1min" },
441 {7, S_O(peak_meter_release), 8, "peak meter release", NULL }, /* 0...126 */
442 {1, S_O(peak_meter_dbfs), true, "peak meter dbfs", off_on },
443 {7, S_O(peak_meter_min), 60, "peak meter min", NULL }, /* 0...100 */
444 {7, S_O(peak_meter_max), 0, "peak meter max", NULL }, /* 0...100 */
445 #endif
446 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
447 {7, S_O(mdb_strength), 0, "mdb strength", NULL},
448 {7, S_O(mdb_harmonics), 0, "mdb harmonics", NULL},
449 {9, S_O(mdb_center), 0, "mdb center", NULL},
450 {9, S_O(mdb_shape), 0, "mdb shape", NULL},
451 {1, S_O(mdb_enable), 0, "mdb enable", off_on},
452 #endif
453 #if CONFIG_CODEC == MAS3507D
454 {1, S_O(line_in), false, "line in", off_on },
455 #endif
456 /* voice */
457 {2, S_O(talk_dir), 0, "talk dir", off_number_spell_hover },
458 {2, S_O(talk_file), 0, "talk file", off_number_spell_hover },
459 {1, S_O(talk_menu), true, "talk menu", off_on },
461 {2, S_O(sort_file), 0, "sort files", "alpha,oldest,newest,type" },
462 {2, S_O(sort_dir), 0, "sort dirs", "alpha,oldest,newest" },
463 {1, S_O(id3_v1_first), 0, "id3 tag priority", "v2-v1,v1-v2"},
465 #ifdef HAVE_RECORDING
466 /* recording */
467 {1, S_O(rec_startup), false, "rec screen on startup", off_on },
468 {4, S_O(rec_timesplit), 0, "rec timesplit", /* 0...15 */
469 "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" },
470 {4, S_O(rec_sizesplit), 0, "rec sizesplit", /* 0...15 */
471 "off,5MB,10MB,15MB,32MB,64MB,75MB,100MB,128MB,256MB,512MB,650MB,700MB,1GB,1.5GB,1.75GB" },
472 {1, S_O(rec_channels), 0, "rec channels", "stereo,mono" },
473 {1, S_O(rec_split_type), 0, "rec split type", "Split, Stop" },
474 {1, S_O(rec_split_method), 0, "rec split method", "Time,Filesize" },
476 #ifdef HAVE_SPDIF_IN
477 {2, S_O(rec_source), 0 /* 0=mic */, "rec source", "mic,line,spdif" },
478 #else
479 {1, S_O(rec_source), 0 /* 0=mic */, "rec source", "mic,line" },
480 #endif
481 {5, S_O(rec_prerecord_time), 0, "prerecording time", NULL }, /* 0...30 */
482 {1, S_O(rec_directory), 0, /* rec_base_directory */
483 "rec directory", REC_BASE_DIR ",current" },
484 #ifdef CONFIG_BACKLIGHT
485 {2, S_O(cliplight), 0, "cliplight", "off,main,both,remote" },
486 #endif
487 #if CONFIG_CODEC == MAS3587F
488 {4, S_O(rec_mic_gain), 8, "rec mic gain", NULL },
489 {4, S_O(rec_left_gain), 2 /* 0dB */, "rec left gain", NULL }, /* 0...15 */
490 {4, S_O(rec_right_gain), 2 /* 0dB */, "rec right gain", NULL }, /* 0...15 */
491 {3, S_O(rec_frequency), 0, /* 0=44.1kHz */
492 "rec frequency", "44,48,32,22,24,16" },
493 {1, S_O(rec_editable), false, "editable recordings", off_on },
494 {3, S_O(rec_quality), 5, "rec quality", NULL },
495 #elif defined(HAVE_UDA1380)
496 {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
497 {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
498 {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
499 {3, S_O(rec_frequency), 0, /* 0=44.1kHz */
500 "rec frequency", "44,48,32,22,24,16" },
501 #endif
503 /* values for the trigger */
504 {8 | SIGNED, S_O(rec_start_thres), -35, "trigger start threshold", NULL},
505 {8 | SIGNED, S_O(rec_stop_thres), -45, "trigger stop threshold", NULL},
506 {4, S_O(rec_start_duration), 0, "trigger start duration", trig_durations_conf},
507 {4, S_O(rec_stop_postrec), 2, "trigger stop postrec", trig_durations_conf},
508 {4, S_O(rec_stop_gap), 1, "trigger min gap", trig_durations_conf},
509 {4, S_O(rec_trigger_mode ), 0, "trigger mode", "off,once,repeat"},
510 #endif /* HAVE_RECORDING */
512 #ifdef HAVE_SPDIF_POWER
513 {1, S_O(spdif_enable), false, "spdif enable", off_on},
514 #endif
516 {1, S_O(next_folder), false, "folder navigation", off_on },
517 {1, S_O(runtimedb), false, "gather runtime data", off_on },
519 #if CONFIG_CODEC == SWCODEC
520 {1, S_O(replaygain), false, "replaygain", off_on },
521 {2, S_O(replaygain_type), REPLAYGAIN_ALBUM, "replaygain type",
522 "track,album,track shuffle" },
523 {1, S_O(replaygain_noclip), false, "replaygain noclip", off_on },
524 {8 | SIGNED, S_O(replaygain_preamp), 0, "replaygain preamp", NULL },
525 {2, S_O(beep), 0, "beep", "off,weak,moderate,strong" },
526 {2, S_O(crossfade), 0, "crossfade", "off,shuffle,track skip,always"},
527 {3, S_O(crossfade_fade_in_delay), 0, "crossfade fade in delay", NULL},
528 {3, S_O(crossfade_fade_out_delay), 0, "crossfade fade out delay", NULL},
529 {4, S_O(crossfade_fade_in_duration), 0, "crossfade fade in duration", NULL},
530 {4, S_O(crossfade_fade_out_duration), 0, "crossfade fade out duration", NULL},
531 {1, S_O(crossfade_fade_out_mixmode), 0, "crossfade fade out mode", "crossfade,mix"},
532 {1, S_O(crossfeed), false, "crossfeed", off_on },
533 {6, S_O(crossfeed_direct_gain), 15, "crossfeed direct gain", NULL },
534 {7, S_O(crossfeed_cross_gain), 60, "crossfeed cross gain", NULL },
535 {8, S_O(crossfeed_hf_attenuation), 160, "crossfeed hf attenuation", NULL },
536 {11, S_O(crossfeed_hf_cutoff), 700, "crossfeed hf cutoff", NULL },
538 /* equalizer */
539 {1, S_O(eq_enabled), false, "eq enabled", off_on },
540 {8, S_O(eq_precut), 0, "eq precut", NULL },
541 /* 0..32768 Hz */
542 {15, S_O(eq_band0_cutoff), 60, "eq band 0 cutoff", NULL },
543 {15, S_O(eq_band1_cutoff), 200, "eq band 1 cutoff", NULL },
544 {15, S_O(eq_band2_cutoff), 800, "eq band 2 cutoff", NULL },
545 {15, S_O(eq_band3_cutoff), 4000, "eq band 3 cutoff", NULL },
546 {15, S_O(eq_band4_cutoff), 12000, "eq band 4 cutoff", NULL },
547 /* 0..64 (or 0.0 to 6.4) */
548 {6, S_O(eq_band0_q), 7, "eq band 0 q", NULL },
549 {6, S_O(eq_band1_q), 10, "eq band 1 q", NULL },
550 {6, S_O(eq_band2_q), 10, "eq band 2 q", NULL },
551 {6, S_O(eq_band3_q), 10, "eq band 3 q", NULL },
552 {6, S_O(eq_band4_q), 7, "eq band 4 q", NULL },
553 /* -240..240 (or -24db to +24db) */
554 {9|SIGNED, S_O(eq_band0_gain), 0, "eq band 0 gain", NULL },
555 {9|SIGNED, S_O(eq_band1_gain), 0, "eq band 1 gain", NULL },
556 {9|SIGNED, S_O(eq_band2_gain), 0, "eq band 2 gain", NULL },
557 {9|SIGNED, S_O(eq_band3_gain), 0, "eq band 3 gain", NULL },
558 {9|SIGNED, S_O(eq_band4_gain), 0, "eq band 4 gain", NULL },
559 #endif
561 #ifdef HAVE_DIRCACHE
562 {1, S_O(dircache), false, "dircache", off_on },
563 {22, S_O(dircache_size), 0, NULL, NULL },
564 #endif
565 #ifdef HAVE_TC_RAMCACHE
566 {1, S_O(tagcache_ram), 0, "tagcache_ram", off_on },
567 #endif
568 {1, S_O(tagcache_autoupdate), 0, "tagcache_autoupdate", off_on },
570 {4, S_O(default_codepage), 0, "default codepage",
571 "iso8859-1,iso8859-7,iso8859-8,cp1251,iso8859-11,cp1256,iso8859-9,iso8859-2,sjis,gb2312,ksx1001,big5,utf-8,cp1256" },
573 {1, S_O(warnon_erase_dynplaylist), false,
574 "warn when erasing dynamic playlist", off_on },
576 #ifdef CONFIG_BACKLIGHT
577 #ifdef HAS_BUTTON_HOLD
578 {2, S_O(backlight_on_button_hold), 0, "backlight on button hold",
579 "normal,off,on" },
580 #endif
582 #ifdef HAVE_LCD_SLEEP
583 {4, S_O(lcd_sleep_after_backlight_off), 3,
584 "lcd sleep after backlight off",
585 "always,never,5,10,15,20,30,45,60,90" },
586 #endif
587 #endif /* CONFIG_BACKLIGHT */
589 #ifdef HAVE_WM8758
590 {1, S_O(eq_hw_enabled), false, "eq hardware enabled", off_on },
592 {2, S_O(eq_hw_band0_cutoff), 1, "eq hardware band 0 cutoff", "80Hz,105Hz,135Hz,175Hz" },
593 {5|SIGNED, S_O(eq_hw_band0_gain), 12, "eq hardware band 0 gain", NULL },
595 {2, S_O(eq_hw_band1_center), 1, "eq hardware band 1 center", "230Hz,300Hz,385Hz,500Hz" },
596 {1, S_O(eq_hw_band1_bandwidth), 0, "eq hardware band 1 bandwidth", "narrow,wide" },
597 {5|SIGNED, S_O(eq_hw_band1_gain), 12, "eq hardware band 1 gain", NULL },
599 {2, S_O(eq_hw_band2_center), 1, "eq hardware band 2 center", "650Hz,850Hz,1.1kHz,1.4kHz" },
600 {1, S_O(eq_hw_band2_bandwidth), 0, "eq hardware band 2 bandwidth", "narrow,wide" },
601 {5|SIGNED, S_O(eq_hw_band2_gain), 12, "eq hardware band 2 gain", NULL },
603 {2, S_O(eq_hw_band3_center), 1, "eq hardware band 3 center", "1.8kHz,2.4kHz,3.2kHz,4.1kHz" },
604 {1, S_O(eq_hw_band3_bandwidth), 0, "eq hardware band 3 bandwidth", "narrow,wide" },
605 {5|SIGNED, S_O(eq_hw_band3_gain), 12, "eq hardware band 3 gain", NULL },
607 {2, S_O(eq_hw_band4_cutoff), 1, "eq hardware band 4 cutoff", "5.3kHz,6.9kHz,9kHz,11.7kHz" },
608 {5|SIGNED, S_O(eq_hw_band4_gain), 12, "eq hardware band 4 gain", NULL },
609 #endif
610 {1, S_O(hold_lr_for_scroll_in_list), true, "hold_lr_for_scroll_in_list", off_on },
612 {2, S_O(show_path_in_browser), 0, "show path in browser", "off,current directory,full path" },
613 #ifdef HAVE_AGC
614 {4, S_O(rec_agc_preset_mic), 1, "agc mic preset", NULL}, /* 0...5 */
615 {4, S_O(rec_agc_preset_line), 1, "agc line preset", NULL}, /* 0...5 */
616 {8|SIGNED, S_O(rec_agc_maxgain_mic), 104, "agc maximum mic gain", NULL},
617 {8|SIGNED, S_O(rec_agc_maxgain_line), 96, "agc maximum line gain", NULL},
618 {3, S_O(rec_agc_cliptime), 1, "agc cliptime", "0.2s,0.4s,0.6s,0.8,1s"},
619 #endif
620 /* If values are just added to the end, no need to bump the version. */
621 /* new stuff to be added at the end */
623 /* Sum of all bit sizes must not grow beyond 0xB8*8 = 1472 */
626 /* helper function to extract n (<=32) bits from an arbitrary position
627 * counting from LSB to MSB */
628 static uint32_t get_bits(
629 const uint32_t *p, /* the start of the bitfield array */
630 unsigned int from, /* bit no. to start reading from */
631 unsigned int size) /* how many bits to read */
633 unsigned int long_index = from / 32;
634 unsigned int bit_index = from % 32;
635 uint32_t result;
637 result = p[long_index] >> bit_index;
639 if (bit_index + size > 32) /* crossing longword boundary */
640 result |= p[long_index+1] << (32 - bit_index);
642 result &= 0xFFFFFFFF >> (32 - size);
644 return result;
647 /* helper function to set n (<=32) bits to an arbitrary position,
648 * counting from LSB to MSB */
649 static void set_bits(
650 uint32_t *p, /* the start of the bitfield array */
651 unsigned int from, /* bit no. to start writing into */
652 unsigned int size, /* how many bits to change */
653 uint32_t value) /* content (LSBs will be taken) */
655 unsigned int long_index = from / 32;
656 unsigned int bit_index = from % 32;
657 uint32_t mask;
659 mask = 0xFFFFFFFF >> (32 - size);
660 value &= mask;
661 mask <<= bit_index;
663 if (bit_index + size > 32)
664 p[long_index+1] =
665 (p[long_index+1] & (0xFFFFFFFF << (bit_index + size - 32)))
666 | (value >> (32 - bit_index));
668 p[long_index] = (p[long_index] & ~mask) | (value << bit_index);
671 #ifdef HAVE_LCD_COLOR
673 * Helper function to convert a string of 6 hex digits to a native colour
676 #define hex2dec(c) (((c) >= '0' && ((c) <= '9')) ? (toupper(c)) - '0' : \
677 (toupper(c)) - 'A' + 10)
679 int hex_to_rgb(const char* hex)
680 { int ok = 1;
681 int i;
682 int red, green, blue;
684 if (strlen(hex) == 6) {
685 for (i=0; i < 6; i++ ) {
686 if (!isxdigit(hex[i])) {
687 ok=0;
688 break;
692 if (ok) {
693 red = (hex2dec(hex[0]) << 4) | hex2dec(hex[1]);
694 green = (hex2dec(hex[2]) << 4) | hex2dec(hex[3]);
695 blue = (hex2dec(hex[4]) << 4) | hex2dec(hex[5]);
696 return LCD_RGBPACK(red,green,blue);
700 return 0;
702 #endif
705 * Calculates the checksum for the config block and returns it
708 static unsigned short calculate_config_checksum(const unsigned char* buf)
710 unsigned int i;
711 unsigned char cksum[2];
712 cksum[0] = cksum[1] = 0;
714 for (i=0; i < RTC_BLOCK_SIZE - 2; i+=2 ) {
715 cksum[0] ^= buf[i];
716 cksum[1] ^= buf[i+1];
719 return (cksum[0] << 8) | cksum[1];
723 * initialize the config block buffer
725 static void init_config_buffer( void )
727 DEBUGF( "init_config_buffer()\n" );
729 /* reset to 0 - all unused */
730 memset(config_block, 0, CONFIG_BLOCK_SIZE);
731 /* insert header */
732 config_block[0] = 'R';
733 config_block[1] = 'o';
734 config_block[2] = 'c';
735 config_block[3] = CONFIG_BLOCK_VERSION;
739 * save the config block buffer to disk or RTC RAM
741 static int save_config_buffer( void )
743 unsigned short chksum;
744 #ifdef HAVE_RTC_RAM
745 unsigned int i;
746 #endif
748 /* update the checksum in the end of the block before saving */
749 chksum = calculate_config_checksum(config_block);
750 config_block[ RTC_BLOCK_SIZE - 2 ] = chksum >> 8;
751 config_block[ RTC_BLOCK_SIZE - 1 ] = chksum & 0xff;
753 #ifdef HAVE_RTC_RAM
754 /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so
755 that it would write a number of bytes at a time since the RTC chip
756 supports that, but this will have to do for now 8-) */
757 for (i=0; i < RTC_BLOCK_SIZE; i++ ) {
758 int r = rtc_write(0x14+i, config_block[i]);
759 if (r) {
760 DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n",
761 14+i, r );
762 return r;
766 #endif
768 if (config_sector != 0)
769 ata_delayed_write( config_sector, config_block);
770 else
771 return -1;
773 return 0;
777 * load the config block buffer from disk or RTC RAM
779 static int load_config_buffer(int which)
781 unsigned short chksum;
782 bool correct = false;
785 DEBUGF( "load_config_buffer()\n" );
787 if (which & SETTINGS_HD)
789 if (config_sector != 0) {
790 ata_read_sectors(IF_MV2(0,) config_sector, 1, config_block);
791 /* calculate the checksum, check it and the header */
792 chksum = calculate_config_checksum(config_block);
794 if (config_block[0] == 'R' &&
795 config_block[1] == 'o' &&
796 config_block[2] == 'c' &&
797 config_block[3] == CONFIG_BLOCK_VERSION &&
798 (chksum >> 8) == config_block[RTC_BLOCK_SIZE - 2] &&
799 (chksum & 0xff) == config_block[RTC_BLOCK_SIZE - 1])
801 DEBUGF( "load_config_buffer: header & checksum test ok\n" );
802 correct = true;
807 #ifdef HAVE_RTC_RAM
808 if(!correct)
810 /* If the disk sector was incorrect, reinit the buffer */
811 memset(config_block, 0, CONFIG_BLOCK_SIZE);
814 if (which & SETTINGS_RTC)
816 unsigned int i;
817 unsigned char rtc_block[RTC_BLOCK_SIZE];
819 /* read rtc block */
820 for (i=0; i < RTC_BLOCK_SIZE; i++ )
821 rtc_block[i] = rtc_read(0x14+i);
823 chksum = calculate_config_checksum(rtc_block);
825 /* if rtc block is ok, use that */
826 if (rtc_block[0] == 'R' &&
827 rtc_block[1] == 'o' &&
828 rtc_block[2] == 'c' &&
829 rtc_block[3] == CONFIG_BLOCK_VERSION &&
830 (chksum >> 8) == rtc_block[RTC_BLOCK_SIZE - 2] &&
831 (chksum & 0xff) == rtc_block[RTC_BLOCK_SIZE - 1])
833 memcpy(config_block, rtc_block, RTC_BLOCK_SIZE);
834 correct = true;
837 #endif
839 if ( !correct ) {
840 /* if checksum is not valid, clear the config buffer */
841 DEBUGF( "load_config_buffer: header & checksum test failed\n" );
842 init_config_buffer();
843 return -1;
846 return 0;
850 /* helper to save content of global_settings into a bitfield,
851 as described per table */
852 static void save_bit_table(const struct bit_entry* p_table, int count, int bitstart)
854 uint32_t *p_bitfield = (uint32_t *)config_block; /* 32 bit addr. */
855 uint32_t value; /* 32 bit content */
856 int i;
857 const struct bit_entry* p_run = p_table; /* start after the size info */
858 int curr_bit = bitstart + p_table->bit_size;
859 count--; /* first is excluded from loop */
861 for (i=0; i<count; i++)
863 p_run++;
864 /* could do a memcpy, but that would be endian-dependent */
865 switch(p_run->byte_size)
867 case 1:
868 value = ((uint8_t *)&global_settings)[p_run->settings_offset];
869 break;
870 case 2:
871 value = ((uint16_t *)&global_settings)[p_run->settings_offset/2];
872 break;
873 case 4:
874 value = ((uint32_t *)&global_settings)[p_run->settings_offset/4];
875 break;
876 default:
877 DEBUGF( "save_bit_table: illegal size!\n" );
878 continue;
880 set_bits(p_bitfield, curr_bit, p_run->bit_size & 0x3F, value);
881 curr_bit += p_run->bit_size & 0x3F;
883 set_bits(p_bitfield, bitstart, p_table->bit_size, /* write size */
884 curr_bit); /* = position after last element */
888 * figure out the config sector from the partition table and the
889 * mounted file system
891 void settings_calc_config_sector(void)
893 #ifdef SIMULATOR
894 config_sector = 61;
895 #else
896 int i;
897 long partition_start;
898 long sector = 0;
900 if (fat_startsector(IF_MV(0)) != 0) /* There is a partition table */
902 sector = 61;
903 for (i = 0; i < 4; i++)
905 partition_start = disk_partinfo(i)->start;
906 if (partition_start != 0 && (partition_start - 2) < sector)
907 sector = partition_start - 2;
909 if (sector < 0)
910 sector = 0;
913 config_sector = sector;
914 #endif
918 * persist all runtime user settings to disk or RTC RAM
920 int settings_save( void )
922 int i;
925 int elapsed_secs;
927 elapsed_secs = (current_tick - lasttime) / HZ;
928 global_settings.runtime += elapsed_secs;
929 lasttime += (elapsed_secs * HZ);
931 if ( global_settings.runtime > global_settings.topruntime )
932 global_settings.topruntime = global_settings.runtime;
935 /* serialize scalar values into RTC and HD sector, specified via table */
936 save_bit_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), 4*8);
937 save_bit_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]), RTC_BLOCK_SIZE*8);
939 i = 0xb8;
940 strncpy((char *)&config_block[i], (char *)global_settings.wps_file,
941 MAX_FILENAME);
942 i+= MAX_FILENAME;
943 strncpy((char *)&config_block[i], (char *)global_settings.lang_file,
944 MAX_FILENAME);
945 i+= MAX_FILENAME;
946 strncpy((char *)&config_block[i], (char *)global_settings.font_file,
947 MAX_FILENAME);
948 i+= MAX_FILENAME;
949 #ifdef HAVE_REMOTE_LCD
950 strncpy((char *)&config_block[i], (char *)global_settings.rwps_file,
951 MAX_FILENAME);
952 i+= MAX_FILENAME;
953 #endif
955 #ifdef CONFIG_TUNER
956 strncpy((char *)&config_block[i], (char *)global_settings.fmr_file,
957 MAX_FILENAME);
958 i+= MAX_FILENAME;
959 #endif
961 #ifdef HAVE_LCD_COLOR
962 strncpy((char *)&config_block[i], (char *)global_settings.backdrop_file,
963 MAX_FILENAME);
964 i+= MAX_FILENAME;
965 #endif
966 #ifdef HAVE_LCD_BITMAP
967 strncpy((char *)&config_block[i], (char *)global_settings.kbd_file,
968 MAX_FILENAME);
969 i+= MAX_FILENAME;
970 #endif
972 if(save_config_buffer())
974 lcd_clear_display();
975 #ifdef HAVE_REMOTE_LCD
976 lcd_remote_clear_display();
977 #endif
978 #ifdef HAVE_LCD_CHARCELLS
979 lcd_puts(0, 0, str(LANG_SETTINGS_SAVE_PLAYER));
980 lcd_puts(0, 1, str(LANG_SETTINGS_BATTERY_PLAYER));
981 #else
982 lcd_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
983 lcd_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
984 lcd_update();
985 #ifdef HAVE_REMOTE_LCD
986 lcd_remote_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
987 lcd_remote_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
988 lcd_remote_update();
989 #endif
990 #endif
991 sleep(HZ*2);
992 return -1;
994 return 0;
997 #ifdef HAVE_LCD_BITMAP
999 * Applies the range infos stored in global_settings to
1000 * the peak meter.
1002 void settings_apply_pm_range(void)
1004 int pm_min, pm_max;
1006 /* depending on the scale mode (dBfs or percent) the values
1007 of global_settings.peak_meter_dbfs have different meanings */
1008 if (global_settings.peak_meter_dbfs)
1010 /* convert to dBfs * 100 */
1011 pm_min = -(((int)global_settings.peak_meter_min) * 100);
1012 pm_max = -(((int)global_settings.peak_meter_max) * 100);
1014 else
1016 /* percent is stored directly -> no conversion */
1017 pm_min = global_settings.peak_meter_min;
1018 pm_max = global_settings.peak_meter_max;
1021 /* apply the range */
1022 peak_meter_init_range(global_settings.peak_meter_dbfs, pm_min, pm_max);
1024 #endif /* HAVE_LCD_BITMAP */
1026 void sound_settings_apply(void)
1028 sound_set(SOUND_BASS, global_settings.bass);
1029 sound_set(SOUND_TREBLE, global_settings.treble);
1030 sound_set(SOUND_BALANCE, global_settings.balance);
1031 sound_set(SOUND_VOLUME, global_settings.volume);
1032 #if CONFIG_CODEC == SWCODEC
1033 channels_set(global_settings.channel_config);
1034 stereo_width_set(global_settings.stereo_width);
1035 #else
1036 sound_set(SOUND_CHANNELS, global_settings.channel_config);
1037 sound_set(SOUND_STEREO_WIDTH, global_settings.stereo_width);
1038 #endif
1039 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
1040 sound_set(SOUND_LOUDNESS, global_settings.loudness);
1041 sound_set(SOUND_AVC, global_settings.avc);
1042 sound_set(SOUND_MDB_STRENGTH, global_settings.mdb_strength);
1043 sound_set(SOUND_MDB_HARMONICS, global_settings.mdb_harmonics);
1044 sound_set(SOUND_MDB_CENTER, global_settings.mdb_center);
1045 sound_set(SOUND_MDB_SHAPE, global_settings.mdb_shape);
1046 sound_set(SOUND_MDB_ENABLE, global_settings.mdb_enable);
1047 sound_set(SOUND_SUPERBASS, global_settings.superbass);
1048 #endif
1051 void settings_apply(void)
1053 char buf[64];
1054 #if CONFIG_CODEC == SWCODEC
1055 int i;
1056 #endif
1058 sound_settings_apply();
1060 audio_set_buffer_margin(global_settings.buffer_margin);
1062 #ifdef HAVE_LCD_CONTRAST
1063 lcd_set_contrast(global_settings.contrast);
1064 #endif
1065 lcd_scroll_speed(global_settings.scroll_speed);
1066 #ifdef HAVE_REMOTE_LCD
1067 lcd_remote_set_contrast(global_settings.remote_contrast);
1068 lcd_remote_set_invert_display(global_settings.remote_invert);
1069 lcd_remote_set_flip(global_settings.remote_flip_display);
1070 lcd_remote_scroll_speed(global_settings.remote_scroll_speed);
1071 lcd_remote_scroll_step(global_settings.remote_scroll_step);
1072 lcd_remote_scroll_delay(global_settings.remote_scroll_delay * (HZ/10));
1073 lcd_remote_bidir_scroll(global_settings.remote_bidir_limit);
1074 #ifdef HAVE_REMOTE_LCD_TICKING
1075 lcd_remote_emireduce(global_settings.remote_reduce_ticking);
1076 #endif
1077 remote_backlight_set_timeout(global_settings.remote_backlight_timeout);
1078 #ifdef CONFIG_CHARGING
1079 remote_backlight_set_timeout_plugged(global_settings.remote_backlight_timeout_plugged);
1080 #endif
1081 #endif
1082 #ifdef CONFIG_BACKLIGHT
1083 backlight_set_timeout(global_settings.backlight_timeout);
1084 #ifdef CONFIG_CHARGING
1085 backlight_set_timeout_plugged(global_settings.backlight_timeout_plugged);
1086 #endif
1087 #if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)
1088 backlight_set_fade_in(global_settings.backlight_fade_in);
1089 backlight_set_fade_out(global_settings.backlight_fade_out);
1090 #endif
1091 #endif
1092 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
1093 backlight_set_brightness(global_settings.brightness);
1094 #endif
1095 ata_spindown(global_settings.disk_spindown);
1096 #if (CONFIG_CODEC == MAS3507D) && !defined(SIMULATOR)
1097 dac_line_in(global_settings.line_in);
1098 #endif
1099 mpeg_id3_options(global_settings.id3_v1_first);
1100 #ifdef HAVE_ATA_POWER_OFF
1101 ata_poweroff(global_settings.disk_poweroff);
1102 #endif
1104 set_poweroff_timeout(global_settings.poweroff);
1106 set_battery_capacity(global_settings.battery_capacity);
1107 #if BATTERY_TYPES_COUNT > 1
1108 set_battery_type(global_settings.battery_type);
1109 #endif
1111 #ifdef HAVE_LCD_BITMAP
1112 lcd_set_invert_display(global_settings.invert);
1113 lcd_set_flip(global_settings.flip_display);
1114 button_set_flip(global_settings.flip_display);
1115 lcd_update(); /* refresh after flipping the screen */
1116 settings_apply_pm_range();
1117 peak_meter_init_times(
1118 global_settings.peak_meter_release, global_settings.peak_meter_hold,
1119 global_settings.peak_meter_clip_hold);
1120 #endif
1122 #ifdef HAVE_LCD_COLOR
1123 unload_wps_backdrop();
1124 #endif
1125 if ( global_settings.wps_file[0] &&
1126 global_settings.wps_file[0] != 0xff ) {
1127 snprintf(buf, sizeof buf, WPS_DIR "/%s.wps",
1128 global_settings.wps_file);
1129 wps_data_load(gui_wps[0].data, buf, true);
1131 else
1133 wps_data_init(gui_wps[0].data);
1136 #ifdef HAVE_LCD_COLOR
1137 if ( global_settings.backdrop_file[0] &&
1138 global_settings.backdrop_file[0] != 0xff ) {
1139 snprintf(buf, sizeof buf, BACKDROP_DIR "/%s.bmp",
1140 global_settings.backdrop_file);
1141 load_main_backdrop(buf);
1142 } else {
1143 unload_main_backdrop();
1145 show_main_backdrop();
1147 screens[SCREEN_MAIN].set_foreground(global_settings.fg_color);
1148 screens[SCREEN_MAIN].set_background(global_settings.bg_color);
1149 #endif
1151 #if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
1152 if ( global_settings.rwps_file[0] &&
1153 global_settings.rwps_file[0] != 0xff ) {
1154 snprintf(buf, sizeof buf, WPS_DIR "/%s.rwps",
1155 global_settings.rwps_file);
1156 wps_data_load(gui_wps[1].data, buf, true);
1158 else
1159 wps_data_init(gui_wps[1].data);
1160 #endif
1162 #ifdef HAVE_LCD_BITMAP
1163 if ( global_settings.font_file[0] &&
1164 global_settings.font_file[0] != 0xff ) {
1165 snprintf(buf, sizeof buf, ROCKBOX_DIR FONT_DIR "/%s.fnt",
1166 global_settings.font_file);
1167 font_load(buf);
1169 else
1170 font_reset();
1172 if ( global_settings.kbd_file[0] &&
1173 global_settings.kbd_file[0] != 0xff ) {
1174 snprintf(buf, sizeof buf, ROCKBOX_DIR "/%s.kbd",
1175 global_settings.kbd_file);
1176 load_kbd(buf);
1178 else
1179 load_kbd(NULL);
1181 lcd_scroll_step(global_settings.scroll_step);
1182 gui_list_screen_scroll_step(global_settings.screen_scroll_step);
1183 gui_list_screen_scroll_out_of_view(global_settings.offset_out_of_view);
1184 #else
1185 lcd_jump_scroll(global_settings.jump_scroll);
1186 lcd_jump_scroll_delay(global_settings.jump_scroll_delay * (HZ/10));
1187 #endif
1188 lcd_bidir_scroll(global_settings.bidir_limit);
1189 lcd_scroll_delay(global_settings.scroll_delay * (HZ/10));
1191 if ( global_settings.lang_file[0] &&
1192 global_settings.lang_file[0] != 0xff ) {
1193 snprintf(buf, sizeof buf, ROCKBOX_DIR LANG_DIR "/%s.lng",
1194 global_settings.lang_file);
1195 lang_load(buf);
1196 talk_init(); /* use voice of same language */
1199 set_codepage(global_settings.default_codepage);
1201 #if CONFIG_CODEC == SWCODEC
1202 audio_set_crossfade(global_settings.crossfade);
1203 dsp_set_replaygain(true);
1204 dsp_set_crossfeed(global_settings.crossfeed);
1205 dsp_set_crossfeed_direct_gain(global_settings.crossfeed_direct_gain);
1206 dsp_set_crossfeed_cross_params(global_settings.crossfeed_cross_gain,
1207 global_settings.crossfeed_cross_gain
1208 + global_settings.crossfeed_hf_attenuation,
1209 global_settings.crossfeed_hf_cutoff);
1211 dsp_set_eq(global_settings.eq_enabled);
1212 dsp_set_eq_precut(global_settings.eq_precut);
1213 /* Update all EQ bands */
1214 for(i = 0; i < 5; i++) {
1215 dsp_set_eq_coefs(i);
1217 #endif
1219 #ifdef HAVE_SPDIF_POWER
1220 spdif_power_enable(global_settings.spdif_enable);
1221 #endif
1223 #ifdef CONFIG_BACKLIGHT
1224 set_backlight_filter_keypress(global_settings.bl_filter_first_keypress);
1225 #ifdef HAVE_REMOTE_LCD
1226 set_remote_backlight_filter_keypress(global_settings.remote_bl_filter_first_keypress);
1227 #endif
1228 #ifdef HAS_BUTTON_HOLD
1229 backlight_set_on_button_hold(global_settings.backlight_on_button_hold);
1230 #endif
1231 #ifdef HAVE_LCD_SLEEP
1232 lcd_set_sleep_after_backlight_off(global_settings.lcd_sleep_after_backlight_off);
1233 #endif
1234 #endif /* CONFIG_BACKLIGHT */
1238 /* helper to load global_settings from a bitfield, as described per table */
1239 static void load_bit_table(const struct bit_entry* p_table, int count, int bitstart)
1241 uint32_t *p_bitfield = (uint32_t *)config_block; /* 32 bit addr. */
1242 uint32_t value; /* 32 bit content */
1243 int i;
1244 int maxbit; /* how many bits are valid in the saved part */
1245 const struct bit_entry* p_run = p_table; /* start after the size info */
1246 count--; /* first is excluded from loop */
1247 maxbit = get_bits(p_bitfield, bitstart, p_table->bit_size);
1248 bitstart += p_table->bit_size;
1250 for (i=0; i<count; i++)
1252 int size;
1253 p_run++;
1255 size = p_run->bit_size & 0x3F; /* mask off abused bits */
1256 if (bitstart + size > maxbit)
1257 break; /* exit if this is not valid any more in bitfield */
1259 value = get_bits(p_bitfield, bitstart, size);
1260 bitstart += size;
1261 if (p_run->bit_size & SIGNED)
1262 { // sign extend the read value
1263 unsigned long mask = 0xFFFFFFFF << (size - 1);
1264 if (value & mask) /* true if MSB of value is set */
1265 value |= mask;
1268 /* could do a memcpy, but that would be endian-dependent */
1269 switch(p_run->byte_size)
1271 case 1:
1272 ((uint8_t *)&global_settings)[p_run->settings_offset] =
1273 (unsigned char)value;
1274 break;
1275 case 2:
1276 ((uint16_t *)&global_settings)[p_run->settings_offset/2] =
1277 (unsigned short)value;
1278 break;
1279 case 4:
1280 ((uint32_t *)&global_settings)[p_run->settings_offset/4] =
1281 (unsigned int)value;
1282 break;
1283 default:
1284 DEBUGF( "load_bit_table: illegal size!\n" );
1285 continue;
1292 * load settings from disk or RTC RAM
1294 void settings_load(int which)
1296 int i;
1297 DEBUGF( "reload_all_settings()\n" );
1299 /* load the buffer from the RTC (resets it to all-unused if the block
1300 is invalid) and decode the settings which are set in the block */
1301 if (!load_config_buffer(which))
1303 /* load scalar values from RTC and HD sector, specified via table */
1304 if (which & SETTINGS_RTC)
1306 load_bit_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), 4*8);
1308 if (which & SETTINGS_HD)
1310 load_bit_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]),
1311 RTC_BLOCK_SIZE*8);
1314 #ifdef HAVE_LCD_CONTRAST
1315 if ( global_settings.contrast < MIN_CONTRAST_SETTING )
1316 global_settings.contrast = lcd_default_contrast();
1317 #endif
1319 i = 0xb8;
1320 strncpy((char *)global_settings.wps_file, (char *)&config_block[i],
1321 MAX_FILENAME);
1322 i+= MAX_FILENAME;
1323 strncpy((char *)global_settings.lang_file, (char *)&config_block[i],
1324 MAX_FILENAME);
1325 i+= MAX_FILENAME;
1326 strncpy((char *)global_settings.font_file, (char *)&config_block[i],
1327 MAX_FILENAME);
1328 i+= MAX_FILENAME;
1329 #ifdef HAVE_REMOTE_LCD
1330 strncpy((char *)global_settings.rwps_file, (char *)&config_block[i],
1331 MAX_FILENAME);
1332 i+= MAX_FILENAME;
1333 #endif
1335 #ifdef CONFIG_TUNER
1336 strncpy((char *)global_settings.fmr_file, (char *)&config_block[i],
1337 MAX_FILENAME);
1338 i+= MAX_FILENAME;
1339 #endif
1341 #ifdef HAVE_LCD_COLOR
1342 strncpy((char *)global_settings.backdrop_file, (char *)&config_block[i],
1343 MAX_FILENAME);
1344 i+= MAX_FILENAME;
1345 #endif
1346 #ifdef HAVE_LCD_BITMAP
1347 strncpy((char *)global_settings.kbd_file, (char *)&config_block[i],
1348 MAX_FILENAME);
1349 i+= MAX_FILENAME;
1350 #endif
1354 void set_file(char* filename, char* setting, int maxlen)
1356 char* fptr = strrchr(filename,'/');
1357 int len;
1358 int extlen = 0;
1359 char* ptr;
1361 if (!fptr)
1362 return;
1364 *fptr = 0;
1365 fptr++;
1367 len = strlen(fptr);
1368 ptr = fptr + len;
1369 while ((*ptr != '.') && (ptr != fptr)) {
1370 extlen++;
1371 ptr--;
1373 if(ptr == fptr) extlen = 0;
1375 if (strncasecmp(ROCKBOX_DIR, filename ,strlen(ROCKBOX_DIR)) ||
1376 (len-extlen > maxlen))
1377 return;
1379 strncpy(setting, fptr, len-extlen);
1380 setting[len-extlen]=0;
1382 settings_save();
1385 /* helper to sort a .cfg file entry into a global_settings member,
1386 as described per table. Returns the position if found, else 0. */
1387 static int load_cfg_table(
1388 const struct bit_entry* p_table, /* the table which describes the entries */
1389 int count, /* number of entries in the table, including the first */
1390 const char* name, /* the item to be searched */
1391 const char* value, /* the value which got loaded for that item */
1392 int hint) /* position to start looking */
1394 int i = hint;
1398 if (p_table[i].cfg_name != NULL && !strcasecmp(name, p_table[i].cfg_name))
1399 { /* found */
1400 int val = 0;
1401 if (p_table[i].cfg_val == NULL)
1402 { /* numerical value, just convert the string */
1403 val = atoi(value);
1405 #if HAVE_LCD_COLOR
1406 else if (!strncasecmp(p_table[i].cfg_val,"rgb",4))
1408 val = hex_to_rgb(value);
1410 #endif
1411 else
1412 { /* set of string values, find the index */
1413 const char* item;
1414 const char* run;
1415 int len = strlen(value);
1417 item = run = p_table[i].cfg_val;
1419 while(1)
1421 /* count the length of the field */
1422 while (*run != ',' && *run != '\0')
1423 run++;
1425 if (!strncasecmp(value, item, MAX(run-item, len)))
1426 break; /* match, exit the search */
1428 if (*run == '\0') /* reached the end of the choices */
1429 return i; /* return the position, but don't update */
1431 val++; /* count the item up */
1432 run++; /* behind the ',' */
1433 item = run;
1437 /* could do a memcpy, but that would be endian-dependent */
1438 switch(p_table[i].byte_size)
1440 case 1:
1441 ((unsigned char*)&global_settings)[p_table[i].settings_offset] =
1442 (unsigned char)val;
1443 break;
1444 case 2:
1445 ((unsigned short*)&global_settings)[p_table[i].settings_offset/2] =
1446 (unsigned short)val;
1447 break;
1448 case 4:
1449 ((unsigned int*)&global_settings)[p_table[i].settings_offset/4] =
1450 (unsigned int)val;
1451 break;
1452 default:
1453 DEBUGF( "illegal size!" );
1454 continue;
1457 return i; /* return the position */
1460 i++;
1461 if (i==count)
1462 i=1; /* wraparound */
1463 } while (i != hint); /* back where we started, all searched */
1465 return 0; /* indicate not found */
1469 bool settings_load_config(const char* file)
1471 int fd;
1472 char line[128];
1474 fd = open(file, O_RDONLY);
1475 if (fd < 0)
1476 return false;
1478 while (read_line(fd, line, sizeof line) > 0)
1480 char* name;
1481 char* value;
1482 const struct bit_entry* table[2] = { rtc_bits, hd_bits };
1483 const int ta_size[2] = {
1484 sizeof(rtc_bits)/sizeof(rtc_bits[0]),
1485 sizeof(hd_bits)/sizeof(hd_bits[0])
1487 int last_table = 0; /* which table was used last round */
1488 int last_pos = 1; /* at which position did we succeed */
1489 int pos; /* currently returned position */
1491 if (!settings_parseline(line, &name, &value))
1492 continue;
1494 /* check for the string values */
1495 if (!strcasecmp(name, "wps")) {
1496 #ifdef HAVE_LCD_COLOR
1497 unload_wps_backdrop();
1498 #endif
1499 if (wps_data_load(gui_wps[0].data, value, true))
1500 set_file(value, (char *)global_settings.wps_file, MAX_FILENAME);
1502 #if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
1503 else if (!strcasecmp(name, "rwps")) {
1504 if (wps_data_load(gui_wps[1].data, value, true))
1505 set_file(value, (char *)global_settings.rwps_file, MAX_FILENAME);
1507 #endif
1508 else if (!strcasecmp(name, "lang")) {
1509 if (!lang_load(value))
1511 set_file(value, (char *)global_settings.lang_file, MAX_FILENAME);
1512 talk_init(); /* use voice of same language */
1515 #ifdef CONFIG_TUNER
1516 else if (!strcasecmp(name, "fmr")) {
1517 set_file(value, global_settings.fmr_file, MAX_FILENAME);
1519 #endif
1520 #ifdef HAVE_LCD_BITMAP
1521 else if (!strcasecmp(name, "font")) {
1522 if (font_load(value))
1523 set_file(value, (char *)global_settings.font_file, MAX_FILENAME);
1525 #endif
1526 #ifdef HAVE_LCD_COLOR
1527 else if (!strcasecmp(name, "backdrop")) {
1528 if (load_main_backdrop(value)) {
1529 set_file(value, (char *)global_settings.backdrop_file, MAX_FILENAME);
1530 show_main_backdrop();
1533 #endif
1534 #ifdef HAVE_LCD_BITMAP
1535 else if (!strcasecmp(name, "keyboard")) {
1536 if (!load_kbd(value))
1537 set_file(value, (char *)global_settings.kbd_file, MAX_FILENAME);
1539 #endif
1542 /* check for scalar values, using the two tables */
1543 pos = load_cfg_table(table[last_table], ta_size[last_table],
1544 name, value, last_pos);
1545 if (pos) /* success */
1547 last_pos = pos; /* remember as a position hint for next round */
1548 continue;
1551 last_table = 1-last_table; /* try other table */
1552 last_pos = 1; /* search from start */
1553 pos = load_cfg_table(table[last_table], ta_size[last_table],
1554 name, value, last_pos);
1555 if (pos) /* success */
1557 last_pos = pos; /* remember as a position hint for next round */
1558 continue;
1562 close(fd);
1563 settings_apply();
1564 settings_save();
1565 return true;
1569 /* helper to save content of global_settings into a file,
1570 as described per table */
1571 static void save_cfg_table(const struct bit_entry* p_table, int count, int fd)
1573 long value; /* 32 bit content */
1574 int i;
1575 const struct bit_entry* p_run = p_table; /* start after the size info */
1576 count--; /* first is excluded from loop */
1578 for (i=0; i<count; i++)
1580 p_run++;
1582 if (p_run->cfg_name == NULL)
1583 continue; /* this value is not to be saved */
1585 /* could do a memcpy, but that would be endian-dependent */
1586 switch(p_run->byte_size)
1588 case 1:
1589 if (p_run->bit_size & SIGNED) /* signed? */
1590 value = ((char*)&global_settings)[p_run->settings_offset];
1591 else
1592 value = ((unsigned char*)&global_settings)[p_run->settings_offset];
1593 break;
1594 case 2:
1595 if (p_run->bit_size & SIGNED) /* signed? */
1596 value = ((short*)&global_settings)[p_run->settings_offset/2];
1597 else
1598 value = ((unsigned short*)&global_settings)[p_run->settings_offset/2];
1599 break;
1600 case 4:
1601 value = ((unsigned int*)&global_settings)[p_run->settings_offset/4];
1602 break;
1603 default:
1604 DEBUGF( "illegal size!" );
1605 continue;
1608 if (p_run->cfg_val == NULL) /* write as number */
1610 fdprintf(fd, "%s: %ld\r\n", p_run->cfg_name, value);
1612 #ifdef HAVE_LCD_COLOR
1613 else if (!strcasecmp(p_run->cfg_val, "rgb"))
1615 fdprintf(fd, "%s: %02x%02x%02x\r\n", p_run->cfg_name,
1616 (int)RGB_UNPACK_RED(value),
1617 (int)RGB_UNPACK_GREEN(value),
1618 (int)RGB_UNPACK_BLUE(value));
1620 #endif
1621 else /* write as item */
1623 const char* p = p_run->cfg_val;
1625 fdprintf(fd, "%s: ", p_run->cfg_name);
1627 while(value >= 0)
1629 char c = *p++; /* currently processed char */
1630 if (c == ',') /* separator */
1631 value--;
1632 else if (c == '\0') /* end of string */
1633 break; /* not found */
1634 else if (value == 0) /* the right place */
1635 write(fd, &c, 1); /* char by char, this is lame, OK */
1638 fdprintf(fd, "\r\n");
1639 if (p_run->cfg_val != off_on) /* explaination for non-bool */
1640 fdprintf(fd, "# (possible values: %s)\r\n", p_run->cfg_val);
1646 bool settings_save_config(void)
1648 int fd;
1649 char filename[MAX_PATH];
1651 create_numbered_filename(filename, ROCKBOX_DIR, "config", ".cfg", 2);
1653 /* allow user to modify filename */
1654 while (true) {
1655 if (!kbd_input(filename, sizeof filename)) {
1656 fd = creat(filename, O_WRONLY);
1657 if (fd < 0)
1658 gui_syncsplash(HZ, true, str(LANG_FAILED));
1659 else
1660 break;
1662 else {
1663 gui_syncsplash(HZ, true, str(LANG_MENU_SETTING_CANCEL));
1664 return false;
1668 fdprintf(fd, "# .cfg file created by rockbox %s - "
1669 "http://www.rockbox.org\r\n#\r\n#\r\n# wps / rwps / language"
1670 " / font / fmpreset / backdrop \r\n#\r\n", appsversion);
1672 if (global_settings.wps_file[0] != 0)
1673 fdprintf(fd, "wps: %s/%s.wps\r\n", WPS_DIR,
1674 global_settings.wps_file);
1676 #ifdef HAVE_REMOTE_LCD
1677 if (global_settings.rwps_file[0] != 0)
1678 fdprintf(fd, "rwps: %s/%s.rwps\r\n", WPS_DIR,
1679 global_settings.rwps_file);
1680 #endif
1682 if (global_settings.lang_file[0] != 0)
1683 fdprintf(fd, "lang: %s/%s.lng\r\n", ROCKBOX_DIR LANG_DIR,
1684 global_settings.lang_file);
1686 #ifdef HAVE_LCD_BITMAP
1687 if (global_settings.font_file[0] != 0)
1688 fdprintf(fd, "font: %s/%s.fnt\r\n", ROCKBOX_DIR FONT_DIR,
1689 global_settings.font_file);
1690 #endif
1692 #ifdef HAVE_LCD_COLOR
1693 if (global_settings.backdrop_file[0] != 0)
1694 fdprintf(fd, "backdrop: %s/%s.bmp\r\n", BACKDROP_DIR,
1695 global_settings.backdrop_file);
1696 #endif
1698 #ifdef CONFIG_TUNER
1699 if (global_settings.fmr_file[0] != 0)
1700 fdprintf(fd, "fmr: %s/%s.fmr\r\n", FMPRESET_PATH,
1701 global_settings.fmr_file);
1702 #endif
1704 #ifdef HAVE_LCD_BITMAP
1705 if (global_settings.kbd_file[0] != 0)
1706 fdprintf(fd, "keyboard: %s/%s.kbd\r\n", ROCKBOX_DIR,
1707 global_settings.kbd_file);
1708 #endif
1710 /* here's the action: write values to file, specified via table */
1711 save_cfg_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), fd);
1712 save_cfg_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]), fd);
1714 close(fd);
1716 gui_syncsplash(HZ, true, str(LANG_SETTINGS_SAVED));
1717 return true;
1721 /* helper to load defaults from table into global_settings members */
1722 static void default_table(const struct bit_entry* p_table, int count)
1724 int i;
1726 for (i=1; i<count; i++) /* exclude the first, the size placeholder */
1728 /* could do a memcpy, but that would be endian-dependent */
1729 switch(p_table[i].byte_size)
1731 case 1:
1732 ((unsigned char*)&global_settings)[p_table[i].settings_offset] =
1733 (unsigned char)p_table[i].default_val;
1734 break;
1735 case 2:
1736 ((unsigned short*)&global_settings)[p_table[i].settings_offset/2] =
1737 (unsigned short)p_table[i].default_val;
1738 break;
1739 case 4:
1740 ((unsigned int*)&global_settings)[p_table[i].settings_offset/4] =
1741 (unsigned int)p_table[i].default_val;
1742 break;
1743 default:
1744 DEBUGF( "illegal size!" );
1745 continue;
1752 * reset all settings to their default value
1754 void settings_reset(void) {
1756 DEBUGF( "settings_reset()\n" );
1758 /* read defaults from table(s) into global_settings */
1759 default_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]));
1760 default_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]));
1762 /* do some special cases not covered by table */
1763 global_settings.volume = sound_default(SOUND_VOLUME);
1764 global_settings.balance = sound_default(SOUND_BALANCE);
1765 global_settings.bass = sound_default(SOUND_BASS);
1766 global_settings.treble = sound_default(SOUND_TREBLE);
1767 global_settings.channel_config = sound_default(SOUND_CHANNELS);
1768 global_settings.stereo_width = sound_default(SOUND_STEREO_WIDTH);
1769 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
1770 global_settings.loudness = sound_default(SOUND_LOUDNESS);
1771 global_settings.avc = sound_default(SOUND_AVC);
1772 global_settings.mdb_strength = sound_default(SOUND_MDB_STRENGTH);
1773 global_settings.mdb_harmonics = sound_default(SOUND_MDB_HARMONICS);
1774 global_settings.mdb_center = sound_default(SOUND_MDB_CENTER);
1775 global_settings.mdb_shape = sound_default(SOUND_MDB_SHAPE);
1776 global_settings.mdb_enable = sound_default(SOUND_MDB_ENABLE);
1777 global_settings.superbass = sound_default(SOUND_SUPERBASS);
1778 #endif
1779 #ifdef HAVE_LCD_CONTRAST
1780 global_settings.contrast = lcd_default_contrast();
1781 #endif
1782 #ifdef HAVE_LCD_REMOTE
1783 global_settings.remote_contrast = lcd_remote_default_contrast();
1784 #endif
1786 #ifdef CONFIG_TUNER
1787 global_settings.fmr_file[0] = '\0';
1788 #endif
1789 global_settings.wps_file[0] = '\0';
1790 #ifdef HAVE_REMOTE_LCD
1791 global_settings.rwps_file[0] = '\0';
1792 #endif
1793 global_settings.font_file[0] = '\0';
1794 global_settings.lang_file[0] = '\0';
1795 #ifdef HAVE_LCD_COLOR
1796 global_settings.backdrop_file[0] = '\0';
1798 global_settings.fg_color = LCD_DEFAULT_FG;
1799 global_settings.bg_color = LCD_DEFAULT_BG;
1800 #endif
1801 #ifdef HAVE_LCD_BITMAP
1802 global_settings.kbd_file[0] = '\0';
1803 #endif
1804 global_settings.hold_lr_for_scroll_in_list = true;
1807 bool set_bool(const char* string, bool* variable )
1809 return set_bool_options(string, variable,
1810 (char *)STR(LANG_SET_BOOL_YES),
1811 (char *)STR(LANG_SET_BOOL_NO),
1812 NULL);
1815 /* wrapper to convert from int param to bool param in set_option */
1816 static void (*boolfunction)(bool);
1817 void bool_funcwrapper(int value)
1819 if (value)
1820 boolfunction(true);
1821 else
1822 boolfunction(false);
1825 bool set_bool_options(const char* string, bool* variable,
1826 const char* yes_str, int yes_voice,
1827 const char* no_str, int no_voice,
1828 void (*function)(bool))
1830 struct opt_items names[] = {
1831 {(unsigned char *)no_str, no_voice},
1832 {(unsigned char *)yes_str, yes_voice}
1834 bool result;
1836 boolfunction = function;
1837 result = set_option(string, variable, BOOL, names, 2,
1838 function ? bool_funcwrapper : NULL);
1839 return result;
1842 void talk_unit(int unit, int value)
1844 if (global_settings.talk_menu)
1846 if (unit < UNIT_LAST)
1847 { /* use the available unit definition */
1848 talk_value(value, unit, false);
1850 else
1851 { /* say the number, followed by an arbitrary voice ID */
1852 talk_number(value, false);
1853 talk_id(unit, true);
1858 struct value_setting_data {
1859 enum optiontype type;
1860 /* used for "value" settings.. */
1861 int max;
1862 int step;
1863 int voice_unit;
1864 const char * unit;
1865 void (*formatter)(char* dest, int dest_length,
1866 int variable, const char* unit);
1867 /* used for BOOL and "choice" settings */
1868 struct opt_items* options;
1871 char * value_setting_get_name_cb(int selected_item,void * data, char *buffer)
1873 struct value_setting_data* cb_data =
1874 (struct value_setting_data*)data;
1875 if (cb_data->type == INT && !cb_data->options)
1877 int item = cb_data->max -(selected_item*cb_data->step);
1878 if (cb_data->formatter)
1879 cb_data->formatter(buffer, MAX_PATH,item,cb_data->unit);
1880 else
1881 snprintf(buffer, MAX_PATH,"%d %s",item,cb_data->unit);
1883 else strcpy(buffer,P2STR(cb_data->options[selected_item].string));
1884 return buffer;
1886 #define type_fromvoidptr(type, value) \
1887 (type == INT)? \
1888 (int)(*(int*)(value)) \
1890 (bool)(*(bool*)(value))
1891 bool do_set_setting(const unsigned char* string, void *variable,
1892 int nb_items,int selected,
1893 struct value_setting_data *cb_data,
1894 void (*function)(int))
1896 int action;
1897 bool done = false;
1898 struct gui_synclist lists;
1899 int oldvalue;
1901 if (cb_data->type == INT)
1902 oldvalue = *(int*)variable;
1903 else oldvalue = *(bool*)variable;
1905 gui_synclist_init(&lists,value_setting_get_name_cb,(void*)cb_data,false,1);
1906 gui_synclist_set_title(&lists, (char*)string, NOICON);
1907 gui_synclist_set_icon_callback(&lists,NULL);
1908 gui_synclist_set_nb_items(&lists,nb_items);
1909 gui_synclist_limit_scroll(&lists,true);
1910 gui_synclist_select_item(&lists, selected);
1912 if (global_settings.talk_menu)
1914 if (cb_data->type == INT && !cb_data->options)
1915 talk_unit(cb_data->voice_unit, *(int*)variable);
1916 else talk_id(cb_data->options[selected].voice_id, false);
1919 gui_synclist_draw(&lists);
1920 while (!done)
1923 action = get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
1924 if (action == ACTION_NONE)
1925 continue;
1927 if (gui_synclist_do_button(&lists,action))
1929 if (global_settings.talk_menu)
1931 int value;
1932 if (cb_data->type == INT && !cb_data->options)
1934 value = cb_data->max -
1935 gui_synclist_get_sel_pos(&lists)*cb_data->step;
1936 talk_unit(cb_data->voice_unit, value);
1938 else
1940 value = gui_synclist_get_sel_pos(&lists);
1941 talk_id(cb_data->options[value].voice_id, false);
1944 if (cb_data->type == INT && !cb_data->options)
1945 *(int*)variable = cb_data->max -
1946 gui_synclist_get_sel_pos(&lists)*cb_data->step;
1947 else if (cb_data->type == BOOL)
1948 *(bool*)variable = gui_synclist_get_sel_pos(&lists) ? true : false;
1949 else *(int*)variable = gui_synclist_get_sel_pos(&lists);
1951 else if (action == ACTION_STD_CANCEL)
1953 gui_syncsplash(HZ/2,true,str(LANG_MENU_SETTING_CANCEL));
1954 if (cb_data->type == INT)
1955 *(int*)variable = oldvalue;
1956 else *(bool*)variable = (bool)oldvalue;
1957 done = true;
1959 else if (action == ACTION_STD_OK)
1961 done = true;
1963 else if(default_event_handler(action) == SYS_USB_CONNECTED)
1964 return true;
1965 gui_syncstatusbar_draw(&statusbars, false);
1966 if ( function )
1967 function(type_fromvoidptr(cb_data->type,variable));
1969 return false;
1971 bool set_int(const unsigned char* string,
1972 const char* unit,
1973 int voice_unit,
1974 int* variable,
1975 void (*function)(int),
1976 int step,
1977 int min,
1978 int max,
1979 void (*formatter)(char*, int, int, const char*) )
1981 struct value_setting_data data = {
1982 INT,max, step, voice_unit,unit,formatter,NULL };
1983 return do_set_setting(string,variable,(max-min)/step + 1,
1984 (max-*variable)/step, &data,function);
1987 /* NOTE: the 'type' parameter specifies the actual type of the variable
1988 that 'variable' points to. not the value within. Only variables with
1989 type 'bool' should use parameter BOOL.
1991 The type separation is necessary since int and bool are fundamentally
1992 different and bit-incompatible types and can not share the same access
1993 code. */
1994 bool set_option(const char* string, void* variable, enum optiontype type,
1995 const struct opt_items* options, int numoptions, void (*function)(int))
1997 struct value_setting_data data = {
1998 type,0, 0, 0,NULL,NULL,(struct opt_items*)options };
1999 int selected;
2000 if (type == BOOL)
2001 selected = *(bool*)variable ? 1 : 0;
2002 else selected = *(int*)variable;
2003 return do_set_setting(string,variable,numoptions,
2004 selected, &data,function);
2007 #ifdef HAVE_RECORDING
2008 /* This array holds the record timer interval lengths, in seconds */
2009 static const unsigned long rec_timer_seconds[] =
2011 0, /* 0 means OFF */
2012 5*60, /* 00:05 */
2013 10*60, /* 00:10 */
2014 15*60, /* 00:15 */
2015 30*60, /* 00:30 */
2016 60*60, /* 01:00 */
2017 74*60, /* 74:00 */
2018 80*60, /* 80:00 */
2019 2*60*60, /* 02:00 */
2020 4*60*60, /* 04:00 */
2021 6*60*60, /* 06:00 */
2022 8*60*60, /* 08:00 */
2023 10L*60*60, /* 10:00 */
2024 12L*60*60, /* 12:00 */
2025 18L*60*60, /* 18:00 */
2026 24L*60*60 /* 24:00 */
2029 unsigned int rec_timesplit_seconds(void)
2031 return rec_timer_seconds[global_settings.rec_timesplit];
2034 /* This array holds the record size interval lengths, in bytes */
2035 static const unsigned long rec_size_bytes[] =
2037 0, /* 0 means OFF */
2038 5*1024*1024, /* 5MB */
2039 10*1024*1024, /* 10MB */
2040 15*1024*1024, /* 15MB */
2041 32*1024*1024, /* 32MB */
2042 64*1024*1024, /* 64MB */
2043 75*1024*1024, /* 75MB */
2044 100*1024*1024, /* 100MB */
2045 128*1024*1024, /* 128MB */
2046 256*1024*1024, /* 256MB */
2047 512*1024*1024, /* 512MB */
2048 650*1024*1024, /* 650MB */
2049 700*1024*1024, /* 700MB */
2050 1024*1024*1024, /* 1GB */
2051 1536*1024*1024, /* 1.5GB */
2052 1792*1024*1024, /* 1.75GB */
2055 unsigned long rec_sizesplit_bytes(void)
2057 return rec_size_bytes[global_settings.rec_sizesplit];
2060 * Time strings used for the trigger durations.
2061 * Keep synchronous to trigger_times in settings_apply_trigger
2063 const char * const trig_durations[TRIG_DURATION_COUNT] =
2065 "0s", "1s", "2s", "5s",
2066 "10s", "15s", "20s", "25s", "30s",
2067 "1min", "2min", "5min", "10min"
2070 void settings_apply_trigger(void)
2072 /* Keep synchronous to trig_durations and trig_durations_conf*/
2073 static const long trigger_times[TRIG_DURATION_COUNT] = {
2074 0, HZ, 2*HZ, 5*HZ,
2075 10*HZ, 15*HZ, 20*HZ, 25*HZ, 30*HZ,
2076 60*HZ, 2*60*HZ, 5*60*HZ, 10*60*HZ
2079 peak_meter_define_trigger(
2080 global_settings.rec_start_thres,
2081 trigger_times[global_settings.rec_start_duration],
2082 MIN(trigger_times[global_settings.rec_start_duration] / 2, 2*HZ),
2083 global_settings.rec_stop_thres,
2084 trigger_times[global_settings.rec_stop_postrec],
2085 trigger_times[global_settings.rec_stop_gap]
2088 #endif