Backdrop support for greyscale targets. WPS backdrop is untested.
[Rockbox.git] / apps / settings.c
blobfc0e5248a3ad324868fb18a28fb1b5f6f0c26b27
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 "ata_idle_notify.h"
42 #include "fat.h"
43 #include "power.h"
44 #include "powermgmt.h"
45 #include "status.h"
46 #include "atoi.h"
47 #include "screens.h"
48 #include "ctype.h"
49 #include "file.h"
50 #include "errno.h"
51 #include "system.h"
52 #include "misc.h"
53 #include "timefuncs.h"
54 #ifdef HAVE_LCD_BITMAP
55 #include "icons.h"
56 #include "font.h"
57 #include "peakmeter.h"
58 #include "hwcompat.h"
59 #endif
60 #include "lang.h"
61 #include "language.h"
62 #include "gwps.h"
63 #include "powermgmt.h"
64 #include "bookmark.h"
65 #include "sprintf.h"
66 #include "keyboard.h"
67 #include "version.h"
68 #include "rtc.h"
69 #include "sound.h"
70 #include "rbunicode.h"
71 #include "dircache.h"
72 #include "statusbar.h"
73 #include "splash.h"
74 #include "list.h"
75 #if LCD_DEPTH > 1
76 #include "backdrop.h"
77 #endif
79 #ifdef CONFIG_TUNER
80 #include "radio.h"
81 #endif
83 #if CONFIG_CODEC == MAS3507D
84 void dac_line_in(bool enable);
85 #endif
86 struct user_settings global_settings;
87 #ifdef HAVE_RECORDING
88 const char rec_base_directory[] = REC_BASE_DIR;
89 #endif
90 #if CONFIG_CODEC == SWCODEC
91 #include "pcmbuf.h"
92 #include "pcm_playback.h"
93 #include "dsp.h"
94 #ifdef HAVE_RECORDING
95 #include "enc_config.h"
96 #endif
97 #endif /* CONFIG_CODEC == SWCODEC */
99 #ifdef HAVE_WM8758
100 #include "eq_menu.h"
101 #endif
103 #define CONFIG_BLOCK_VERSION 56
104 #define CONFIG_BLOCK_SIZE 512
105 #define RTC_BLOCK_SIZE 44
107 #ifdef HAVE_LCD_BITMAP
108 #define MAX_LINES 10
109 #else
110 #define MAX_LINES 2
111 #endif
113 #ifdef HAVE_REMOTE_LCD
114 #include "lcd-remote.h"
115 #endif
117 long lasttime = 0;
118 static long config_sector = 0; /* mark uninitialized */
119 static unsigned char config_block[CONFIG_BLOCK_SIZE];
122 /* descriptor for a configuration value */
123 /* (watch the struct packing and member sizes to keep this small) */
124 struct bit_entry
126 /* how many bits within the bitfield (1-32), MSB set if value is signed */
127 unsigned char bit_size; /* min 6+1 bit */
128 /* how many bytes in the global_settings struct (1,2,4) */
129 unsigned char byte_size; /* min 3 bits */
130 /* store position in global_settings struct */
131 short settings_offset; /* min 9 bit, better 10 */
132 /* default value */
133 int default_val; /* min 15 bit */
134 /* variable name in a .cfg file, NULL if not to be saved */
135 const char* cfg_name;
136 /* set of values, "rgb" for a color, or NULL for a numerical value */
137 const char* cfg_val;
140 /********************************************
142 Config block as saved on the battery-packed RTC user RAM memory block
143 of 44 bytes, starting at offset 0x14 of the RTC memory space.
145 offset abs
146 0x00 0x14 "Roc" header signature: 0x52 0x6f 0x63
147 0x03 0x17 <version byte: 0x0>
148 0x04 0x18 start of bit-table
150 0x28,0x29 unused, not reachable by set_bits() without disturbing the next 2
151 0x2A,0x2B <checksum 2 bytes: xor of 0x00-0x29>
153 Config memory is reset to 0xff and initialized with 'factory defaults' if
154 a valid header & checksum is not found. Config version number is only
155 increased when information is _relocated_ or space is _reused_ so that old
156 versions can read and modify configuration changed by new versions.
157 Memory locations not used by a given version should not be
158 modified unless the header & checksum test fails.
160 Rest of config block, only saved to disk:
161 0x2C start of 2nd bit-table
163 0xA4 (char[20]) FMR Preset file
164 0xB8 (char[20]) WPS file
165 0xCC (char[20]) Lang file
166 0xE0 (char[20]) Font file
167 ... (char[20]) RWPS file (on targets supporting a Remote WPS)
168 ... (char[20]) Main backdrop file (on color LCD targets)
170 ... to 0x200 <unused>
172 *************************************/
174 /* The persistence of the global_settings members is now controlled by
175 the two tables below, rtc_bits and hd_bits.
176 New values can just be added to the end, it will be backwards
177 compatible. If you however change order, bitsize, etc. of existing
178 entries, you need to bump CONFIG_BLOCK_VERSION to break compatibility.
182 /* convenience macro for both size and offset of global_settings member */
183 #define S_O(val) sizeof(global_settings.val), offsetof(struct user_settings, val)
184 #define SIGNED 0x80 /* for bitsize value with signed attribute */
186 /* some sets of values which are used more than once, to save memory */
187 static const char off_on[] = "off,on";
188 static const char off_on_ask[] = "off,on,ask";
189 static const char off_number_spell_hover[] = "off,number,spell,hover";
190 #ifdef HAVE_LCD_BITMAP
191 static const char graphic_numeric[] = "graphic,numeric";
192 #endif
194 #ifdef HAVE_RECORDING
195 /* keep synchronous to trig_durations and
196 trigger_times in settings_apply_trigger */
197 static const char trig_durations_conf [] =
198 "0s,1s,2s,5s,10s,15s,20s,25s,30s,1min,2min,5min,10min";
199 #endif
201 #if defined(CONFIG_BACKLIGHT)
202 static const char backlight_times_conf [] =
203 "off,on,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60,90";
204 #endif
206 /* the part of the settings which ends up in the RTC RAM, where available
207 (those we either need early, save frequently, or without spinup) */
208 static const struct bit_entry rtc_bits[] =
210 /* placeholder, containing the size information */
211 {9, 0, 0, 0, NULL, NULL }, /* 9 bit to tell how far this is populated */
213 /* # of bits, offset+size, default, .cfg name, .cfg values */
214 /* sound */
215 #if CONFIG_CODEC == MAS3507D
216 {8 | SIGNED, S_O(volume), -18, "volume", NULL }, /* -78...+18 */
217 #else
218 {8 | SIGNED, S_O(volume), -25, "volume", NULL }, /* -100...+12 / -84...0 */
219 #endif
220 {8 | SIGNED, S_O(balance), 0, "balance", NULL }, /* -100...100 */
221 #if CONFIG_CODEC != SWCODEC /* any MAS */
222 {5 | SIGNED, S_O(bass), 0, "bass", NULL }, /* -15..+15 / -12..+12 */
223 {5 | SIGNED, S_O(treble), 0, "treble", NULL }, /* -15..+15 / -12..+12 */
224 #elif defined HAVE_UDA1380
225 {5, S_O(bass), 0, "bass", NULL }, /* 0..+24 */
226 {3, S_O(treble), 0, "treble", NULL }, /* 0..+6 */
227 #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
228 || defined(HAVE_WM8731) || defined(HAVE_WM8721)
229 {5 | SIGNED, S_O(bass), 0, "bass", NULL }, /* -6..+9 */
230 {5 | SIGNED, S_O(treble), 0, "treble", NULL }, /* -6..+9 */
231 #endif
232 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
233 {5, S_O(loudness), 0, "loudness", NULL }, /* 0...17 */
234 {3, S_O(avc), 0, "auto volume", "off,20ms,2,4,8" },
235 {1, S_O(superbass), false, "superbass", off_on },
236 #endif
237 {3, S_O(channel_config), 0, "channels",
238 "stereo,mono,custom,mono left,mono right,karaoke" },
239 {8, S_O(stereo_width), 100, "stereo width", NULL},
240 /* playback */
241 {1, S_O(resume), false, "resume", off_on },
242 {1, S_O(playlist_shuffle), false, "shuffle", off_on },
243 {16 | SIGNED, S_O(resume_index), -1, NULL, NULL },
244 {16 | SIGNED, S_O(resume_first_index), 0, NULL, NULL },
245 {32 | SIGNED, S_O(resume_offset), -1, NULL, NULL },
246 {32 | SIGNED, S_O(resume_seed), -1, NULL, NULL },
247 {3, S_O(repeat_mode), REPEAT_ALL, "repeat", "off,all,one,shuffle,ab" },
248 /* LCD */
249 #ifdef HAVE_LCD_CONTRAST
250 {6, S_O(contrast), DEFAULT_CONTRAST_SETTING, "contrast", NULL },
251 #endif
252 #ifdef CONFIG_BACKLIGHT
253 {5, S_O(backlight_timeout), 6, "backlight timeout", backlight_times_conf },
254 #ifdef CONFIG_CHARGING
255 {5, S_O(backlight_timeout_plugged), 11, "backlight timeout plugged",
256 backlight_times_conf },
257 #endif
258 #endif /* CONFIG_BACKLIGHT */
259 #ifdef HAVE_LCD_BITMAP
260 {1, S_O(invert), false, "invert", off_on },
261 {1, S_O(flip_display), false, "flip display", off_on },
262 /* display */
263 {1, S_O(invert_cursor), true, "invert cursor", off_on },
264 {1, S_O(statusbar), true, "statusbar", off_on },
265 {1, S_O(scrollbar), true, "scrollbar", off_on },
266 #if CONFIG_KEYPAD == RECORDER_PAD
267 {1, S_O(buttonbar), true, "buttonbar", off_on },
268 #endif
269 {1, S_O(volume_type), 0, "volume display", graphic_numeric },
270 {1, S_O(battery_display), 0, "battery display", graphic_numeric },
271 {1, S_O(timeformat), 0, "time format", "24hour,12hour" },
272 #endif /* HAVE_LCD_BITMAP */
273 {1, S_O(show_icons), true, "show icons", off_on },
274 /* system */
275 {4, S_O(poweroff), 10,
276 "idle poweroff", "off,1,2,3,4,5,6,7,8,9,10,15,30,45,60" },
277 {18, S_O(runtime), 0, NULL, NULL },
278 {18, S_O(topruntime), 0, NULL, NULL },
279 #if MEM > 1
280 {15, S_O(max_files_in_playlist), 10000,
281 "max files in playlist", NULL }, /* 1000...20000 */
282 {14, S_O(max_files_in_dir), 400,
283 "max files in dir", NULL }, /* 50...10000 */
284 #else
285 {15, S_O(max_files_in_playlist), 1000,
286 "max files in playlist", NULL }, /* 1000...20000 */
287 {14, S_O(max_files_in_dir), 200,
288 "max files in dir", NULL }, /* 50...10000 */
289 #endif
290 /* battery */
291 {12, S_O(battery_capacity), BATTERY_CAPACITY_DEFAULT, "battery capacity",
292 NULL }, /* 1500...3200 for NiMH, 2200...3200 for LiIon,
293 500...1500 for Alkaline */
294 #ifdef CONFIG_CHARGING
295 {1, S_O(car_adapter_mode), false, "car adapter mode", off_on },
296 #endif
297 /* tuner */
298 #ifdef CONFIG_TUNER
299 {1, S_O(fm_force_mono), false, "force fm mono", off_on },
300 {9, S_O(last_frequency), 0, NULL, NULL }, /* Default: MIN_FREQ */
301 #endif
303 #if BATTERY_TYPES_COUNT > 1
304 {1, S_O(battery_type), 0, "battery type", "alkaline,nimh" },
305 #endif
307 #ifdef HAVE_REMOTE_LCD
308 /* remote lcd */
309 {6, S_O(remote_contrast), DEFAULT_REMOTE_CONTRAST_SETTING,
310 "remote contrast", NULL },
311 {1, S_O(remote_invert), false, "remote invert", off_on },
312 {1, S_O(remote_flip_display), false, "remote flip display", off_on },
313 {5, S_O(remote_backlight_timeout), 6, "remote backlight timeout",
314 backlight_times_conf },
315 #ifdef CONFIG_CHARGING
316 {5, S_O(remote_backlight_timeout_plugged), 11,
317 "remote backlight timeout plugged", backlight_times_conf },
318 #endif
319 #ifdef HAVE_REMOTE_LCD_TICKING
320 {1, S_O(remote_reduce_ticking), false, "remote reduce ticking", off_on },
321 #endif
322 #endif
324 #ifdef CONFIG_BACKLIGHT
325 {1, S_O(bl_filter_first_keypress), false,
326 "backlight filters first keypress", off_on },
327 #ifdef HAVE_REMOTE_LCD
328 {1, S_O(remote_bl_filter_first_keypress), false,
329 "backlight filters first remote keypress", off_on },
330 #endif
331 #endif /* CONFIG_BACKLIGHT */
333 /* new stuff to be added here */
334 /* If values are just added to the end, no need to bump the version. */
336 /* Current sum of bits: 277 (worst case, but w/o remote lcd) */
337 /* Sum of all bit sizes must not grow beyond 288! */
341 /* the part of the settings which ends up in HD sector only */
342 static const struct bit_entry hd_bits[] =
344 /* This table starts after the 44 RTC bytes = 352 bits. */
345 /* Here we need 11 bits to tell how far this is populated. */
347 /* placeholder, containing the size information */
348 {11, 0, 0, 0, NULL, NULL }, /* 11 bit to tell how far this is populated */
350 /* # of bits, offset+size, default, .cfg name, .cfg values */
351 /* more display */
352 #ifdef CONFIG_BACKLIGHT
353 {1, S_O(caption_backlight), false, "caption backlight", off_on },
354 #endif
355 #ifdef HAVE_REMOTE_LCD
356 {1, S_O(remote_caption_backlight), false,
357 "remote caption backlight", off_on },
358 #endif
359 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
360 {4, S_O(brightness), DEFAULT_BRIGHTNESS_SETTING, "brightness", NULL },
361 #endif
362 #ifdef HAVE_BACKLIGHT_PWM_FADING
363 /* backlight fading */
364 {2, S_O(backlight_fade_in), 1, "backlight fade in", "off,500ms,1s,2s"},
365 {3, S_O(backlight_fade_out), 3, "backlight fade out",
366 "off,500ms,1s,2s,3s,4s,5s,10s"},
367 #endif
369 {4, S_O(scroll_speed), 9, "scroll speed", NULL }, /* 0...15 */
370 {8, S_O(scroll_delay), 100, "scroll delay", NULL }, /* 0...250 */
371 {8, S_O(bidir_limit), 50, "bidir limit", NULL }, /* 0...200 */
373 #ifdef HAVE_REMOTE_LCD
374 {4, S_O(remote_scroll_speed), 9, "remote scroll speed", NULL }, /* 0...15 */
375 {8, S_O(remote_scroll_step), 6, "remote scroll step", NULL }, /* 1...160 */
376 {8, S_O(remote_scroll_delay), 100, "remote scroll delay", NULL }, /* 0...250 */
377 {8, S_O(remote_bidir_limit), 50, "remote bidir limit", NULL }, /* 0...200 */
378 #endif
380 #ifdef HAVE_LCD_BITMAP
381 {1, S_O(offset_out_of_view), false, "Screen Scrolls Out Of View", off_on },
382 #if LCD_WIDTH > 255
383 {9, S_O(scroll_step), 6, "scroll step", NULL },
384 {9, S_O(screen_scroll_step), 16, "screen scroll step", NULL },
385 #elif LCD_WIDTH > 127
386 {8, S_O(scroll_step), 6, "scroll step", NULL },
387 {8, S_O(screen_scroll_step), 16, "screen scroll step", NULL },
388 #else
389 {7, S_O(scroll_step), 6, "scroll step", NULL },
390 {7, S_O(screen_scroll_step), 16, "screen scroll step", NULL },
391 #endif
392 #endif /* HAVE_LCD_BITMAP */
393 #ifdef HAVE_LCD_CHARCELLS
394 {3, S_O(jump_scroll), 0, "jump scroll", NULL }, /* 0...5 */
395 {8, S_O(jump_scroll_delay), 50, "jump scroll delay", NULL }, /* 0...250 */
396 #endif
397 {1, S_O(scroll_paginated), false, "scroll paginated", off_on },
399 #ifdef HAVE_LCD_COLOR
400 {LCD_DEPTH,S_O(fg_color),LCD_DEFAULT_FG,"foreground color","rgb"},
401 {LCD_DEPTH,S_O(bg_color),LCD_DEFAULT_BG,"background color","rgb"},
402 #endif
404 /* more playback */
405 {1, S_O(play_selected), true, "play selected", off_on },
406 {1, S_O(fade_on_stop), true, "volume fade", off_on },
407 {4, S_O(ff_rewind_min_step), FF_REWIND_1000,
408 "scan min step", "1,2,3,4,5,6,8,10,15,20,25,30,45,60" },
409 {4, S_O(ff_rewind_accel), 3, "scan accel", NULL },
410 #if CONFIG_CODEC == SWCODEC
411 {3, S_O(buffer_margin), 0, "antiskip",
412 "5s,15s,30s,1min,2min,3min,5min,10min" },
413 #else
414 {3, S_O(buffer_margin), 0, "antiskip", NULL },
415 #endif
416 /* disk */
417 #ifndef HAVE_MMC
418 #ifdef HAVE_ATA_POWER_OFF
419 {1, S_O(disk_poweroff), false, "disk poweroff", off_on },
420 #endif
421 {8, S_O(disk_spindown), 5, "disk spindown", NULL },
422 #endif /* HAVE_MMC */
424 /* browser */
425 {3, S_O(dirfilter), SHOW_SUPPORTED,
426 "show files", "all,supported,music,playlists"
427 #ifdef HAVE_TAGCACHE
428 ",id3 database"
429 #endif
431 {1, S_O(sort_case), false, "sort case", off_on },
432 {1, S_O(browse_current), false, "follow playlist", off_on },
433 /* playlist */
434 {1, S_O(playlist_viewer_icons), true, "playlist viewer icons", off_on },
435 {1, S_O(playlist_viewer_indices), true,
436 "playlist viewer indices", off_on },
437 {1, S_O(playlist_viewer_track_display), 0,
438 "playlist viewer track display", "track name,full path" },
439 {2, S_O(recursive_dir_insert), RECURSE_OFF,
440 "recursive directory insert", off_on_ask },
441 /* bookmarks */
442 {3, S_O(autocreatebookmark), BOOKMARK_NO, "autocreate bookmarks",
443 "off,on,ask,recent only - on,recent only - ask" },
444 {2, S_O(autoloadbookmark), BOOKMARK_NO,
445 "autoload bookmarks", off_on_ask },
446 {2, S_O(usemrb), BOOKMARK_NO,
447 "use most-recent-bookmarks", "off,on,unique only" },
448 #ifdef HAVE_LCD_BITMAP
449 /* peak meter */
450 {5, S_O(peak_meter_clip_hold), 16, "peak meter clip hold", /* 0...25 */
451 "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" },
452 {5, S_O(peak_meter_hold), 3, "peak meter hold",
453 "off,200ms,300ms,500ms,1,2,3,4,5,6,7,8,9,10,15,20,30,1min" },
454 {7, S_O(peak_meter_release), 8, "peak meter release", NULL }, /* 0...126 */
455 {1, S_O(peak_meter_dbfs), true, "peak meter dbfs", off_on },
456 {7, S_O(peak_meter_min), 60, "peak meter min", NULL }, /* 0...100 */
457 {7, S_O(peak_meter_max), 0, "peak meter max", NULL }, /* 0...100 */
458 #endif
459 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
460 {7, S_O(mdb_strength), 0, "mdb strength", NULL},
461 {7, S_O(mdb_harmonics), 0, "mdb harmonics", NULL},
462 {9, S_O(mdb_center), 0, "mdb center", NULL},
463 {9, S_O(mdb_shape), 0, "mdb shape", NULL},
464 {1, S_O(mdb_enable), 0, "mdb enable", off_on},
465 #endif
466 #if CONFIG_CODEC == MAS3507D
467 {1, S_O(line_in), false, "line in", off_on },
468 #endif
469 /* voice */
470 {2, S_O(talk_dir), 0, "talk dir", off_number_spell_hover },
471 {2, S_O(talk_file), 0, "talk file", off_number_spell_hover },
472 {1, S_O(talk_menu), true, "talk menu", off_on },
474 {2, S_O(sort_file), 0, "sort files", "alpha,oldest,newest,type" },
475 {2, S_O(sort_dir), 0, "sort dirs", "alpha,oldest,newest" },
476 {1, S_O(id3_v1_first), 0, "id3 tag priority", "v2-v1,v1-v2"},
478 #ifdef HAVE_RECORDING
479 /* recording */
480 {1, S_O(recscreen_on), false, "recscreen on", off_on },
481 {1, S_O(rec_startup), false, "rec screen on startup", off_on },
482 {4, S_O(rec_timesplit), 0, "rec timesplit", /* 0...15 */
483 "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" },
484 {4, S_O(rec_sizesplit), 0, "rec sizesplit", /* 0...15 */
485 "off,5MB,10MB,15MB,32MB,64MB,75MB,100MB,128MB,256MB,512MB,650MB,700MB,1GB,1.5GB,1.75GB" },
486 {1, S_O(rec_channels), 0, "rec channels", "stereo,mono" },
487 {1, S_O(rec_split_type), 0, "rec split type", "Split, Stop" },
488 {1, S_O(rec_split_method), 0, "rec split method", "Time,Filesize" },
491 #if defined(HAVE_SPDIF_IN) || defined(HAVE_FMRADIO_IN)
493 #else
495 #endif
496 S_O(rec_source), 0 /* 0=mic */, "rec source",
497 "mic,line"
498 #ifdef HAVE_SPDIF_IN
499 ",spdif"
500 #endif
501 #ifdef HAVE_FMRADIO_IN
502 ",fmradio"
503 #endif
505 {5, S_O(rec_prerecord_time), 0, "prerecording time", NULL }, /* 0...30 */
506 {1, S_O(rec_directory), 0, /* rec_base_directory */
507 "rec directory", REC_BASE_DIR ",current" },
508 #ifdef CONFIG_BACKLIGHT
509 {2, S_O(cliplight), 0, "cliplight", "off,main,both,remote" },
510 #endif
511 #if CONFIG_CODEC == MAS3587F
512 {4, S_O(rec_mic_gain), 8, "rec mic gain", NULL },
513 {4, S_O(rec_left_gain), 2 /* 0dB */, "rec left gain", NULL }, /* 0...15 */
514 {4, S_O(rec_right_gain), 2 /* 0dB */, "rec right gain", NULL }, /* 0...15 */
515 {3, S_O(rec_frequency), 0, /* 0=44.1kHz */
516 "rec frequency", "44,48,32,22,24,16" },
517 {3, S_O(rec_quality), 5 /* 192 kBit/s max */, "rec quality", NULL },
518 {1, S_O(rec_editable), false, "editable recordings", off_on },
519 #endif /* CONFIG_CODEC == MAS3587F */
521 #if CONFIG_CODEC == SWCODEC
522 #ifdef HAVE_UDA1380
523 {8|SIGNED, S_O(rec_mic_gain), 16 /* 8 dB */, "rec mic gain", NULL }, /* -128...+108 */
524 #endif
525 #ifdef HAVE_TLV320
526 /* TLV320 only has no mic boost or 20db mic boost */
527 {1, S_O(rec_mic_gain), 0 /* 0 dB */, "rec mic gain", NULL }, /* 0db or 20db */
528 #endif
529 {8|SIGNED, S_O(rec_left_gain), 0, "rec left gain", NULL }, /* -128...+96 */
530 {8|SIGNED, S_O(rec_right_gain), 0, "rec right gain", NULL }, /* -128...+96 */
531 {REC_FREQ_CFG_NUM_BITS, S_O(rec_frequency), REC_FREQ_DEFAULT,
532 "rec frequency", REC_FREQ_CFG_VAL_LIST },
533 {REC_FORMAT_CFG_NUM_BITS ,S_O(rec_format), REC_FORMAT_DEFAULT,
534 "rec format", REC_FORMAT_CFG_VAL_LIST },
535 /** Encoder settings start - keep these together **/
536 /* mp3_enc */
537 {5,S_O(mp3_enc_config.bitrate), MP3_ENC_BITRATE_CFG_DEFAULT,
538 "mp3_enc bitrate", MP3_ENC_BITRATE_CFG_VALUE_LIST },
539 /* wav_enc */
540 /* (no settings yet) */
541 /* wavpack_enc */
542 /* (no settings yet) */
543 /** Encoder settings end **/
544 #endif /* CONFIG_CODEC == SWCODEC */
546 /* values for the trigger */
547 {8 | SIGNED, S_O(rec_start_thres), -35, "trigger start threshold", NULL},
548 {8 | SIGNED, S_O(rec_stop_thres), -45, "trigger stop threshold", NULL},
549 {4, S_O(rec_start_duration), 0, "trigger start duration", trig_durations_conf},
550 {4, S_O(rec_stop_postrec), 2, "trigger stop postrec", trig_durations_conf},
551 {4, S_O(rec_stop_gap), 1, "trigger min gap", trig_durations_conf},
552 {4, S_O(rec_trigger_mode ), 0, "trigger mode", "off,once,repeat"},
553 #endif /* HAVE_RECORDING */
555 #ifdef HAVE_SPDIF_POWER
556 {1, S_O(spdif_enable), false, "spdif enable", off_on},
557 #endif
559 {2, S_O(next_folder), false, "folder navigation", "off,on,random" },
560 {1, S_O(runtimedb), false, "gather runtime data", off_on },
562 #if CONFIG_CODEC == SWCODEC
563 {1, S_O(replaygain), false, "replaygain", off_on },
564 {2, S_O(replaygain_type), REPLAYGAIN_ALBUM, "replaygain type",
565 "track,album,track shuffle" },
566 {1, S_O(replaygain_noclip), false, "replaygain noclip", off_on },
567 {8 | SIGNED, S_O(replaygain_preamp), 0, "replaygain preamp", NULL },
568 {2, S_O(beep), 0, "beep", "off,weak,moderate,strong" },
569 {2, S_O(crossfade), 0, "crossfade", "off,shuffle,track skip,always"},
570 {3, S_O(crossfade_fade_in_delay), 0, "crossfade fade in delay", NULL},
571 {3, S_O(crossfade_fade_out_delay), 0, "crossfade fade out delay", NULL},
572 {4, S_O(crossfade_fade_in_duration), 0, "crossfade fade in duration", NULL},
573 {4, S_O(crossfade_fade_out_duration), 0, "crossfade fade out duration", NULL},
574 {1, S_O(crossfade_fade_out_mixmode), 0, "crossfade fade out mode", "crossfade,mix"},
575 {1, S_O(crossfeed), false, "crossfeed", off_on },
576 {6, S_O(crossfeed_direct_gain), 15, "crossfeed direct gain", NULL },
577 {7, S_O(crossfeed_cross_gain), 60, "crossfeed cross gain", NULL },
578 {8, S_O(crossfeed_hf_attenuation), 160, "crossfeed hf attenuation", NULL },
579 {11, S_O(crossfeed_hf_cutoff), 700, "crossfeed hf cutoff", NULL },
581 /* equalizer */
582 {1, S_O(eq_enabled), false, "eq enabled", off_on },
583 {8, S_O(eq_precut), 0, "eq precut", NULL },
584 /* 0..32768 Hz */
585 {15, S_O(eq_band0_cutoff), 60, "eq band 0 cutoff", NULL },
586 {15, S_O(eq_band1_cutoff), 200, "eq band 1 cutoff", NULL },
587 {15, S_O(eq_band2_cutoff), 800, "eq band 2 cutoff", NULL },
588 {15, S_O(eq_band3_cutoff), 4000, "eq band 3 cutoff", NULL },
589 {15, S_O(eq_band4_cutoff), 12000, "eq band 4 cutoff", NULL },
590 /* 0..64 (or 0.0 to 6.4) */
591 {6, S_O(eq_band0_q), 7, "eq band 0 q", NULL },
592 {6, S_O(eq_band1_q), 10, "eq band 1 q", NULL },
593 {6, S_O(eq_band2_q), 10, "eq band 2 q", NULL },
594 {6, S_O(eq_band3_q), 10, "eq band 3 q", NULL },
595 {6, S_O(eq_band4_q), 7, "eq band 4 q", NULL },
596 /* -240..240 (or -24db to +24db) */
597 {9|SIGNED, S_O(eq_band0_gain), 0, "eq band 0 gain", NULL },
598 {9|SIGNED, S_O(eq_band1_gain), 0, "eq band 1 gain", NULL },
599 {9|SIGNED, S_O(eq_band2_gain), 0, "eq band 2 gain", NULL },
600 {9|SIGNED, S_O(eq_band3_gain), 0, "eq band 3 gain", NULL },
601 {9|SIGNED, S_O(eq_band4_gain), 0, "eq band 4 gain", NULL },
603 /* dithering */
604 {1, S_O(dithering_enabled), false, "dithering enabled", off_on },
605 #endif
607 #ifdef HAVE_DIRCACHE
608 {1, S_O(dircache), false, "dircache", off_on },
609 {22, S_O(dircache_size), 0, NULL, NULL },
610 #endif
612 #ifdef HAVE_TAGCACHE
613 #ifdef HAVE_TC_RAMCACHE
614 {1, S_O(tagcache_ram), 0, "tagcache_ram", off_on },
615 #endif
616 {1, S_O(tagcache_autoupdate), 0, "tagcache_autoupdate", off_on },
617 #endif
619 {4, S_O(default_codepage), 0, "default codepage",
620 "iso8859-1,iso8859-7,iso8859-8,cp1251,iso8859-11,cp1256,iso8859-9,iso8859-2,sjis,gb2312,ksx1001,big5,utf-8,cp1256" },
622 {1, S_O(warnon_erase_dynplaylist), false,
623 "warn when erasing dynamic playlist", off_on },
625 #ifdef CONFIG_BACKLIGHT
626 #ifdef HAS_BUTTON_HOLD
627 {2, S_O(backlight_on_button_hold), 0, "backlight on button hold",
628 "normal,off,on" },
629 #endif
631 #ifdef HAVE_LCD_SLEEP
632 {4, S_O(lcd_sleep_after_backlight_off), 3,
633 "lcd sleep after backlight off",
634 "always,never,5,10,15,20,30,45,60,90" },
635 #endif
636 #endif /* CONFIG_BACKLIGHT */
638 #ifdef HAVE_WM8758
639 {1, S_O(eq_hw_enabled), false, "eq hardware enabled", off_on },
641 {2, S_O(eq_hw_band0_cutoff), 1, "eq hardware band 0 cutoff", "80Hz,105Hz,135Hz,175Hz" },
642 {5|SIGNED, S_O(eq_hw_band0_gain), 0, "eq hardware band 0 gain", NULL },
644 {2, S_O(eq_hw_band1_center), 1, "eq hardware band 1 center", "230Hz,300Hz,385Hz,500Hz" },
645 {1, S_O(eq_hw_band1_bandwidth), 0, "eq hardware band 1 bandwidth", "narrow,wide" },
646 {5|SIGNED, S_O(eq_hw_band1_gain), 0, "eq hardware band 1 gain", NULL },
648 {2, S_O(eq_hw_band2_center), 1, "eq hardware band 2 center", "650Hz,850Hz,1.1kHz,1.4kHz" },
649 {1, S_O(eq_hw_band2_bandwidth), 0, "eq hardware band 2 bandwidth", "narrow,wide" },
650 {5|SIGNED, S_O(eq_hw_band2_gain), 0, "eq hardware band 2 gain", NULL },
652 {2, S_O(eq_hw_band3_center), 1, "eq hardware band 3 center", "1.8kHz,2.4kHz,3.2kHz,4.1kHz" },
653 {1, S_O(eq_hw_band3_bandwidth), 0, "eq hardware band 3 bandwidth", "narrow,wide" },
654 {5|SIGNED, S_O(eq_hw_band3_gain), 0, "eq hardware band 3 gain", NULL },
656 {2, S_O(eq_hw_band4_cutoff), 1, "eq hardware band 4 cutoff", "5.3kHz,6.9kHz,9kHz,11.7kHz" },
657 {5|SIGNED, S_O(eq_hw_band4_gain), 0, "eq hardware band 4 gain", NULL },
658 #endif
659 {1, S_O(hold_lr_for_scroll_in_list), true, "hold_lr_for_scroll_in_list", off_on },
661 {2, S_O(show_path_in_browser), 0, "show path in browser", "off,current directory,full path" },
662 #ifdef HAVE_AGC
663 {4, S_O(rec_agc_preset_mic), 1, "agc mic preset", NULL}, /* 0...5 */
664 {4, S_O(rec_agc_preset_line), 1, "agc line preset", NULL}, /* 0...5 */
665 {8|SIGNED, S_O(rec_agc_maxgain_mic), 104, "agc maximum mic gain", NULL},
666 {8|SIGNED, S_O(rec_agc_maxgain_line), 96, "agc maximum line gain", NULL},
667 {3, S_O(rec_agc_cliptime), 1, "agc cliptime", "0.2s,0.4s,0.6s,0.8,1s"},
668 #endif
670 #ifdef HAVE_REMOTE_LCD
671 #ifdef HAS_REMOTE_BUTTON_HOLD
672 {2, S_O(remote_backlight_on_button_hold), 0, "remote backlight on button hold",
673 "normal,off,on" },
674 #endif
675 #endif
677 #ifdef HAVE_HEADPHONE_DETECTION
678 {2, S_O(unplug_mode), 0, "pause on headphone unplug", NULL},
679 {4, S_O(unplug_rw), 0, "rewind duration on pause", NULL},
680 {1, S_O(unplug_autoresume), 0, "disable autoresume if phones not present", off_on },
681 #endif
682 #ifdef CONFIG_TUNER
683 {2, S_O(fm_region), 0, "fm_region", "eu,us,jp,kr" },
684 #endif
686 {1, S_O(audioscrobbler), false, "Last.fm Logging", off_on},
688 /* If values are just added to the end, no need to bump the version. */
689 /* new stuff to be added at the end */
690 #ifdef HAVE_RECORDING
691 {2, S_O(rec_trigger_type), 0, "trigger type", "stop,pause,nf stp"},
692 #endif
694 /* Sum of all bit sizes must not grow beyond 0xB8*8 = 1472 */
697 /* helper function to extract n (<=32) bits from an arbitrary position
698 * counting from LSB to MSB */
699 static uint32_t get_bits(
700 const uint32_t *p, /* the start of the bitfield array */
701 unsigned int from, /* bit no. to start reading from */
702 unsigned int size) /* how many bits to read */
704 unsigned int long_index = from / 32;
705 unsigned int bit_index = from % 32;
706 uint32_t result;
708 result = p[long_index] >> bit_index;
710 if (bit_index + size > 32) /* crossing longword boundary */
711 result |= p[long_index+1] << (32 - bit_index);
713 result &= 0xFFFFFFFF >> (32 - size);
715 return result;
718 /* helper function to set n (<=32) bits to an arbitrary position,
719 * counting from LSB to MSB */
720 static void set_bits(
721 uint32_t *p, /* the start of the bitfield array */
722 unsigned int from, /* bit no. to start writing into */
723 unsigned int size, /* how many bits to change */
724 uint32_t value) /* content (LSBs will be taken) */
726 unsigned int long_index = from / 32;
727 unsigned int bit_index = from % 32;
728 uint32_t mask;
730 mask = 0xFFFFFFFF >> (32 - size);
731 value &= mask;
732 mask <<= bit_index;
734 if (bit_index + size > 32)
735 p[long_index+1] =
736 (p[long_index+1] & (0xFFFFFFFF << (bit_index + size - 32)))
737 | (value >> (32 - bit_index));
739 p[long_index] = (p[long_index] & ~mask) | (value << bit_index);
742 #ifdef HAVE_LCD_COLOR
744 * Helper function to convert a string of 6 hex digits to a native colour
747 #define hex2dec(c) (((c) >= '0' && ((c) <= '9')) ? (toupper(c)) - '0' : \
748 (toupper(c)) - 'A' + 10)
750 int hex_to_rgb(const char* hex)
751 { int ok = 1;
752 int i;
753 int red, green, blue;
755 if (strlen(hex) == 6) {
756 for (i=0; i < 6; i++ ) {
757 if (!isxdigit(hex[i])) {
758 ok=0;
759 break;
763 if (ok) {
764 red = (hex2dec(hex[0]) << 4) | hex2dec(hex[1]);
765 green = (hex2dec(hex[2]) << 4) | hex2dec(hex[3]);
766 blue = (hex2dec(hex[4]) << 4) | hex2dec(hex[5]);
767 return LCD_RGBPACK(red,green,blue);
771 return 0;
773 #endif
776 * Calculates the checksum for the config block and returns it
779 static unsigned short calculate_config_checksum(const unsigned char* buf)
781 unsigned int i;
782 unsigned char cksum[2];
783 cksum[0] = cksum[1] = 0;
785 for (i=0; i < RTC_BLOCK_SIZE - 2; i+=2 ) {
786 cksum[0] ^= buf[i];
787 cksum[1] ^= buf[i+1];
790 return (cksum[0] << 8) | cksum[1];
794 * initialize the config block buffer
796 static void init_config_buffer( void )
798 DEBUGF( "init_config_buffer()\n" );
800 /* reset to 0 - all unused */
801 memset(config_block, 0, CONFIG_BLOCK_SIZE);
802 /* insert header */
803 config_block[0] = 'R';
804 config_block[1] = 'o';
805 config_block[2] = 'c';
806 config_block[3] = CONFIG_BLOCK_VERSION;
809 bool flush_config_block_callback(void)
811 ata_write_sectors(IF_MV2(0,) config_sector, 1, config_block);
812 return true;
815 * save the config block buffer to disk or RTC RAM
817 static int save_config_buffer( void )
819 unsigned short chksum;
820 #ifdef HAVE_RTC_RAM
821 unsigned int i;
822 #endif
824 /* update the checksum in the end of the block before saving */
825 chksum = calculate_config_checksum(config_block);
826 config_block[ RTC_BLOCK_SIZE - 2 ] = chksum >> 8;
827 config_block[ RTC_BLOCK_SIZE - 1 ] = chksum & 0xff;
829 #ifdef HAVE_RTC_RAM
830 /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so
831 that it would write a number of bytes at a time since the RTC chip
832 supports that, but this will have to do for now 8-) */
833 for (i=0; i < RTC_BLOCK_SIZE; i++ ) {
834 int r = rtc_write(0x14+i, config_block[i]);
835 if (r) {
836 DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n",
837 14+i, r );
838 return r;
842 #endif
844 if (config_sector != 0)
845 register_ata_idle_func(flush_config_block_callback);
846 else
847 return -1;
849 return 0;
853 * load the config block buffer from disk or RTC RAM
855 static int load_config_buffer(int which)
857 unsigned short chksum;
858 bool correct = false;
861 DEBUGF( "load_config_buffer()\n" );
863 if (which & SETTINGS_HD)
865 if (config_sector != 0) {
866 ata_read_sectors(IF_MV2(0,) config_sector, 1, config_block);
867 /* calculate the checksum, check it and the header */
868 chksum = calculate_config_checksum(config_block);
870 if (config_block[0] == 'R' &&
871 config_block[1] == 'o' &&
872 config_block[2] == 'c' &&
873 config_block[3] == CONFIG_BLOCK_VERSION &&
874 (chksum >> 8) == config_block[RTC_BLOCK_SIZE - 2] &&
875 (chksum & 0xff) == config_block[RTC_BLOCK_SIZE - 1])
877 DEBUGF( "load_config_buffer: header & checksum test ok\n" );
878 correct = true;
883 #ifdef HAVE_RTC_RAM
884 if(!correct)
886 /* If the disk sector was incorrect, reinit the buffer */
887 memset(config_block, 0, CONFIG_BLOCK_SIZE);
890 if (which & SETTINGS_RTC)
892 unsigned int i;
893 unsigned char rtc_block[RTC_BLOCK_SIZE];
895 /* read rtc block */
896 for (i=0; i < RTC_BLOCK_SIZE; i++ )
897 rtc_block[i] = rtc_read(0x14+i);
899 chksum = calculate_config_checksum(rtc_block);
901 /* if rtc block is ok, use that */
902 if (rtc_block[0] == 'R' &&
903 rtc_block[1] == 'o' &&
904 rtc_block[2] == 'c' &&
905 rtc_block[3] == CONFIG_BLOCK_VERSION &&
906 (chksum >> 8) == rtc_block[RTC_BLOCK_SIZE - 2] &&
907 (chksum & 0xff) == rtc_block[RTC_BLOCK_SIZE - 1])
909 memcpy(config_block, rtc_block, RTC_BLOCK_SIZE);
910 correct = true;
913 #endif
915 if ( !correct ) {
916 /* if checksum is not valid, clear the config buffer */
917 DEBUGF( "load_config_buffer: header & checksum test failed\n" );
918 init_config_buffer();
919 return -1;
922 return 0;
926 /* helper to save content of global_settings into a bitfield,
927 as described per table */
928 static void save_bit_table(const struct bit_entry* p_table, int count, int bitstart)
930 uint32_t *p_bitfield = (uint32_t *)config_block; /* 32 bit addr. */
931 uint32_t value; /* 32 bit content */
932 int i;
933 const struct bit_entry* p_run = p_table; /* start after the size info */
934 int curr_bit = bitstart + p_table->bit_size;
935 count--; /* first is excluded from loop */
937 for (i=0; i<count; i++)
939 p_run++;
940 /* could do a memcpy, but that would be endian-dependent */
941 switch(p_run->byte_size)
943 case 1:
944 value = ((uint8_t *)&global_settings)[p_run->settings_offset];
945 break;
946 case 2:
947 value = ((uint16_t *)&global_settings)[p_run->settings_offset/2];
948 break;
949 case 4:
950 value = ((uint32_t *)&global_settings)[p_run->settings_offset/4];
951 break;
952 default:
953 DEBUGF( "save_bit_table: illegal size!\n" );
954 continue;
956 set_bits(p_bitfield, curr_bit, p_run->bit_size & 0x3F, value);
957 curr_bit += p_run->bit_size & 0x3F;
959 set_bits(p_bitfield, bitstart, p_table->bit_size, /* write size */
960 curr_bit); /* = position after last element */
964 * figure out the config sector from the partition table and the
965 * mounted file system
967 void settings_calc_config_sector(void)
969 #ifdef SIMULATOR
970 config_sector = 61;
971 #else
972 int i;
973 long partition_start;
974 long sector = 0;
976 if (fat_startsector(IF_MV(0)) != 0) /* There is a partition table */
978 sector = 61;
979 for (i = 0; i < 4; i++)
981 partition_start = disk_partinfo(i)->start;
982 if (partition_start != 0 && (partition_start - 2) < sector)
983 sector = partition_start - 2;
985 if (sector < 0)
986 sector = 0;
989 config_sector = sector;
990 #endif
994 * persist all runtime user settings to disk or RTC RAM
996 int settings_save( void )
998 int i;
1001 int elapsed_secs;
1003 elapsed_secs = (current_tick - lasttime) / HZ;
1004 global_settings.runtime += elapsed_secs;
1005 lasttime += (elapsed_secs * HZ);
1007 if ( global_settings.runtime > global_settings.topruntime )
1008 global_settings.topruntime = global_settings.runtime;
1011 /* serialize scalar values into RTC and HD sector, specified via table */
1012 save_bit_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), 4*8);
1013 save_bit_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]), RTC_BLOCK_SIZE*8);
1015 i = 0xb8;
1016 strncpy((char *)&config_block[i], (char *)global_settings.wps_file,
1017 MAX_FILENAME);
1018 i+= MAX_FILENAME;
1019 strncpy((char *)&config_block[i], (char *)global_settings.lang_file,
1020 MAX_FILENAME);
1021 i+= MAX_FILENAME;
1022 strncpy((char *)&config_block[i], (char *)global_settings.font_file,
1023 MAX_FILENAME);
1024 i+= MAX_FILENAME;
1025 #ifdef HAVE_REMOTE_LCD
1026 strncpy((char *)&config_block[i], (char *)global_settings.rwps_file,
1027 MAX_FILENAME);
1028 i+= MAX_FILENAME;
1029 #endif
1031 #ifdef CONFIG_TUNER
1032 strncpy((char *)&config_block[i], (char *)global_settings.fmr_file,
1033 MAX_FILENAME);
1034 i+= MAX_FILENAME;
1035 #endif
1037 #if LCD_DEPTH > 1
1038 strncpy((char *)&config_block[i], (char *)global_settings.backdrop_file,
1039 MAX_FILENAME);
1040 i+= MAX_FILENAME;
1041 #endif
1042 #ifdef HAVE_LCD_BITMAP
1043 strncpy((char *)&config_block[i], (char *)global_settings.kbd_file,
1044 MAX_FILENAME);
1045 i+= MAX_FILENAME;
1046 #endif
1048 if(save_config_buffer())
1050 lcd_clear_display();
1051 #ifdef HAVE_REMOTE_LCD
1052 lcd_remote_clear_display();
1053 #endif
1054 #ifdef HAVE_LCD_CHARCELLS
1055 lcd_puts(0, 0, str(LANG_SETTINGS_SAVE_PLAYER));
1056 lcd_puts(0, 1, str(LANG_SETTINGS_BATTERY_PLAYER));
1057 #else
1058 lcd_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
1059 lcd_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
1060 lcd_update();
1061 #ifdef HAVE_REMOTE_LCD
1062 lcd_remote_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
1063 lcd_remote_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
1064 lcd_remote_update();
1065 #endif
1066 #endif
1067 sleep(HZ*2);
1068 return -1;
1070 return 0;
1073 #ifdef HAVE_LCD_BITMAP
1075 * Applies the range infos stored in global_settings to
1076 * the peak meter.
1078 void settings_apply_pm_range(void)
1080 int pm_min, pm_max;
1082 /* depending on the scale mode (dBfs or percent) the values
1083 of global_settings.peak_meter_dbfs have different meanings */
1084 if (global_settings.peak_meter_dbfs)
1086 /* convert to dBfs * 100 */
1087 pm_min = -(((int)global_settings.peak_meter_min) * 100);
1088 pm_max = -(((int)global_settings.peak_meter_max) * 100);
1090 else
1092 /* percent is stored directly -> no conversion */
1093 pm_min = global_settings.peak_meter_min;
1094 pm_max = global_settings.peak_meter_max;
1097 /* apply the range */
1098 peak_meter_init_range(global_settings.peak_meter_dbfs, pm_min, pm_max);
1100 #endif /* HAVE_LCD_BITMAP */
1102 void sound_settings_apply(void)
1104 sound_set(SOUND_BASS, global_settings.bass);
1105 sound_set(SOUND_TREBLE, global_settings.treble);
1106 sound_set(SOUND_BALANCE, global_settings.balance);
1107 sound_set(SOUND_VOLUME, global_settings.volume);
1108 #if CONFIG_CODEC == SWCODEC
1109 channels_set(global_settings.channel_config);
1110 stereo_width_set(global_settings.stereo_width);
1111 #else
1112 sound_set(SOUND_CHANNELS, global_settings.channel_config);
1113 sound_set(SOUND_STEREO_WIDTH, global_settings.stereo_width);
1114 #endif
1115 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
1116 sound_set(SOUND_LOUDNESS, global_settings.loudness);
1117 sound_set(SOUND_AVC, global_settings.avc);
1118 sound_set(SOUND_MDB_STRENGTH, global_settings.mdb_strength);
1119 sound_set(SOUND_MDB_HARMONICS, global_settings.mdb_harmonics);
1120 sound_set(SOUND_MDB_CENTER, global_settings.mdb_center);
1121 sound_set(SOUND_MDB_SHAPE, global_settings.mdb_shape);
1122 sound_set(SOUND_MDB_ENABLE, global_settings.mdb_enable);
1123 sound_set(SOUND_SUPERBASS, global_settings.superbass);
1124 #endif
1127 void settings_apply(void)
1129 char buf[64];
1130 #if CONFIG_CODEC == SWCODEC
1131 int i;
1132 #endif
1134 sound_settings_apply();
1136 audio_set_buffer_margin(global_settings.buffer_margin);
1138 #ifdef HAVE_LCD_CONTRAST
1139 lcd_set_contrast(global_settings.contrast);
1140 #endif
1141 lcd_scroll_speed(global_settings.scroll_speed);
1142 #ifdef HAVE_REMOTE_LCD
1143 lcd_remote_set_contrast(global_settings.remote_contrast);
1144 lcd_remote_set_invert_display(global_settings.remote_invert);
1145 lcd_remote_set_flip(global_settings.remote_flip_display);
1146 lcd_remote_scroll_speed(global_settings.remote_scroll_speed);
1147 lcd_remote_scroll_step(global_settings.remote_scroll_step);
1148 lcd_remote_scroll_delay(global_settings.remote_scroll_delay * (HZ/10));
1149 lcd_remote_bidir_scroll(global_settings.remote_bidir_limit);
1150 #ifdef HAVE_REMOTE_LCD_TICKING
1151 lcd_remote_emireduce(global_settings.remote_reduce_ticking);
1152 #endif
1153 remote_backlight_set_timeout(global_settings.remote_backlight_timeout);
1154 #ifdef CONFIG_CHARGING
1155 remote_backlight_set_timeout_plugged(global_settings.remote_backlight_timeout_plugged);
1156 #endif
1157 #ifdef HAS_REMOTE_BUTTON_HOLD
1158 remote_backlight_set_on_button_hold(global_settings.remote_backlight_on_button_hold);
1159 #endif
1160 #endif /* HAVE_REMOTE_LCD */
1161 #ifdef CONFIG_BACKLIGHT
1162 backlight_set_timeout(global_settings.backlight_timeout);
1163 #ifdef CONFIG_CHARGING
1164 backlight_set_timeout_plugged(global_settings.backlight_timeout_plugged);
1165 #endif
1166 #if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)
1167 backlight_set_fade_in(global_settings.backlight_fade_in);
1168 backlight_set_fade_out(global_settings.backlight_fade_out);
1169 #endif
1170 #endif
1171 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
1172 backlight_set_brightness(global_settings.brightness);
1173 #endif
1174 ata_spindown(global_settings.disk_spindown);
1175 #if (CONFIG_CODEC == MAS3507D) && !defined(SIMULATOR)
1176 dac_line_in(global_settings.line_in);
1177 #endif
1178 mpeg_id3_options(global_settings.id3_v1_first);
1179 #ifdef HAVE_ATA_POWER_OFF
1180 ata_poweroff(global_settings.disk_poweroff);
1181 #endif
1183 set_poweroff_timeout(global_settings.poweroff);
1185 set_battery_capacity(global_settings.battery_capacity);
1186 #if BATTERY_TYPES_COUNT > 1
1187 set_battery_type(global_settings.battery_type);
1188 #endif
1190 #ifdef HAVE_LCD_BITMAP
1191 lcd_set_invert_display(global_settings.invert);
1192 lcd_set_flip(global_settings.flip_display);
1193 button_set_flip(global_settings.flip_display);
1194 lcd_update(); /* refresh after flipping the screen */
1195 settings_apply_pm_range();
1196 peak_meter_init_times(
1197 global_settings.peak_meter_release, global_settings.peak_meter_hold,
1198 global_settings.peak_meter_clip_hold);
1199 #endif
1201 #if LCD_DEPTH > 1
1202 unload_wps_backdrop();
1203 #endif
1204 if ( global_settings.wps_file[0] &&
1205 global_settings.wps_file[0] != 0xff ) {
1206 snprintf(buf, sizeof buf, WPS_DIR "/%s.wps",
1207 global_settings.wps_file);
1208 wps_data_load(gui_wps[0].data, buf, true);
1210 else
1212 wps_data_init(gui_wps[0].data);
1215 #if LCD_DEPTH > 1
1216 if ( global_settings.backdrop_file[0] &&
1217 global_settings.backdrop_file[0] != 0xff ) {
1218 snprintf(buf, sizeof buf, BACKDROP_DIR "/%s.bmp",
1219 global_settings.backdrop_file);
1220 load_main_backdrop(buf);
1221 } else {
1222 unload_main_backdrop();
1224 show_main_backdrop();
1225 #endif
1227 #ifdef HAVE_LCD_COLOR
1228 screens[SCREEN_MAIN].set_foreground(global_settings.fg_color);
1229 screens[SCREEN_MAIN].set_background(global_settings.bg_color);
1230 #endif
1232 #if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
1233 if ( global_settings.rwps_file[0] &&
1234 global_settings.rwps_file[0] != 0xff ) {
1235 snprintf(buf, sizeof buf, WPS_DIR "/%s.rwps",
1236 global_settings.rwps_file);
1237 wps_data_load(gui_wps[1].data, buf, true);
1239 else
1240 wps_data_init(gui_wps[1].data);
1241 #endif
1243 #ifdef HAVE_LCD_BITMAP
1244 if ( global_settings.font_file[0] &&
1245 global_settings.font_file[0] != 0xff ) {
1246 snprintf(buf, sizeof buf, FONT_DIR "/%s.fnt",
1247 global_settings.font_file);
1248 font_load(buf);
1250 else
1251 font_reset();
1253 if ( global_settings.kbd_file[0] &&
1254 global_settings.kbd_file[0] != 0xff ) {
1255 snprintf(buf, sizeof buf, ROCKBOX_DIR "/%s.kbd",
1256 global_settings.kbd_file);
1257 load_kbd(buf);
1259 else
1260 load_kbd(NULL);
1262 lcd_scroll_step(global_settings.scroll_step);
1263 gui_list_screen_scroll_step(global_settings.screen_scroll_step);
1264 gui_list_screen_scroll_out_of_view(global_settings.offset_out_of_view);
1265 #else
1266 lcd_jump_scroll(global_settings.jump_scroll);
1267 lcd_jump_scroll_delay(global_settings.jump_scroll_delay * (HZ/10));
1268 #endif
1269 lcd_bidir_scroll(global_settings.bidir_limit);
1270 lcd_scroll_delay(global_settings.scroll_delay * (HZ/10));
1272 if ( global_settings.lang_file[0] &&
1273 global_settings.lang_file[0] != 0xff ) {
1274 snprintf(buf, sizeof buf, LANG_DIR "/%s.lng",
1275 global_settings.lang_file);
1276 lang_load(buf);
1277 talk_init(); /* use voice of same language */
1280 set_codepage(global_settings.default_codepage);
1282 #if CONFIG_CODEC == SWCODEC
1283 audio_set_crossfade(global_settings.crossfade);
1284 dsp_set_replaygain(true);
1285 dsp_set_crossfeed(global_settings.crossfeed);
1286 dsp_set_crossfeed_direct_gain(global_settings.crossfeed_direct_gain);
1287 dsp_set_crossfeed_cross_params(global_settings.crossfeed_cross_gain,
1288 global_settings.crossfeed_cross_gain
1289 + global_settings.crossfeed_hf_attenuation,
1290 global_settings.crossfeed_hf_cutoff);
1292 dsp_set_eq(global_settings.eq_enabled);
1293 dsp_set_eq_precut(global_settings.eq_precut);
1294 /* Update all EQ bands */
1295 for(i = 0; i < 5; i++) {
1296 dsp_set_eq_coefs(i);
1299 dsp_dither_enable(global_settings.dithering_enabled);
1300 #endif
1302 #ifdef HAVE_WM8758
1303 eq_hw_enable(global_settings.eq_hw_enabled);
1304 #endif
1306 #ifdef HAVE_SPDIF_POWER
1307 spdif_power_enable(global_settings.spdif_enable);
1308 #endif
1310 #ifdef CONFIG_BACKLIGHT
1311 set_backlight_filter_keypress(global_settings.bl_filter_first_keypress);
1312 #ifdef HAVE_REMOTE_LCD
1313 set_remote_backlight_filter_keypress(global_settings.remote_bl_filter_first_keypress);
1314 #endif
1315 #ifdef HAS_BUTTON_HOLD
1316 backlight_set_on_button_hold(global_settings.backlight_on_button_hold);
1317 #endif
1318 #ifdef HAVE_LCD_SLEEP
1319 lcd_set_sleep_after_backlight_off(global_settings.lcd_sleep_after_backlight_off);
1320 #endif
1321 #endif /* CONFIG_BACKLIGHT */
1323 /* This should stay last */
1324 #if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
1325 enc_global_settings_apply();
1326 #endif
1330 /* helper to load global_settings from a bitfield, as described per table */
1331 static void load_bit_table(const struct bit_entry* p_table, int count, int bitstart)
1333 uint32_t *p_bitfield = (uint32_t *)config_block; /* 32 bit addr. */
1334 uint32_t value; /* 32 bit content */
1335 int i;
1336 int maxbit; /* how many bits are valid in the saved part */
1337 const struct bit_entry* p_run = p_table; /* start after the size info */
1338 count--; /* first is excluded from loop */
1339 maxbit = get_bits(p_bitfield, bitstart, p_table->bit_size);
1340 bitstart += p_table->bit_size;
1342 for (i=0; i<count; i++)
1344 int size;
1345 p_run++;
1347 size = p_run->bit_size & 0x3F; /* mask off abused bits */
1348 if (bitstart + size > maxbit)
1349 break; /* exit if this is not valid any more in bitfield */
1351 value = get_bits(p_bitfield, bitstart, size);
1352 bitstart += size;
1353 if (p_run->bit_size & SIGNED)
1354 { // sign extend the read value
1355 unsigned long mask = 0xFFFFFFFF << (size - 1);
1356 if (value & mask) /* true if MSB of value is set */
1357 value |= mask;
1360 /* could do a memcpy, but that would be endian-dependent */
1361 switch(p_run->byte_size)
1363 case 1:
1364 ((uint8_t *)&global_settings)[p_run->settings_offset] =
1365 (unsigned char)value;
1366 break;
1367 case 2:
1368 ((uint16_t *)&global_settings)[p_run->settings_offset/2] =
1369 (unsigned short)value;
1370 break;
1371 case 4:
1372 ((uint32_t *)&global_settings)[p_run->settings_offset/4] =
1373 (unsigned int)value;
1374 break;
1375 default:
1376 DEBUGF( "load_bit_table: illegal size!\n" );
1377 continue;
1384 * load settings from disk or RTC RAM
1386 void settings_load(int which)
1388 int i;
1389 DEBUGF( "reload_all_settings()\n" );
1391 /* load the buffer from the RTC (resets it to all-unused if the block
1392 is invalid) and decode the settings which are set in the block */
1393 if (!load_config_buffer(which))
1395 /* load scalar values from RTC and HD sector, specified via table */
1396 if (which & SETTINGS_RTC)
1398 load_bit_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), 4*8);
1400 if (which & SETTINGS_HD)
1402 load_bit_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]),
1403 RTC_BLOCK_SIZE*8);
1406 #ifdef HAVE_RECORDING
1407 global_settings.recscreen_on = false;
1408 #endif
1410 #ifdef HAVE_LCD_CONTRAST
1411 if ( global_settings.contrast < MIN_CONTRAST_SETTING ||
1412 global_settings.contrast > MAX_CONTRAST_SETTING )
1413 global_settings.contrast = lcd_default_contrast();
1414 #endif
1416 #ifdef HAVE_LCD_REMOTE
1417 if (global_settings.remote_contrast < MIN_REMOTE_CONTRAST_SETTING ||
1418 global_settings.remote_contrast > MAX_REMOTE_CONTRAST_SETTING )
1419 global_settings.remote_contrast = lcd_remote_default_contrast();
1420 #endif
1421 i = 0xb8;
1422 strncpy((char *)global_settings.wps_file, (char *)&config_block[i],
1423 MAX_FILENAME);
1424 i+= MAX_FILENAME;
1425 strncpy((char *)global_settings.lang_file, (char *)&config_block[i],
1426 MAX_FILENAME);
1427 i+= MAX_FILENAME;
1428 strncpy((char *)global_settings.font_file, (char *)&config_block[i],
1429 MAX_FILENAME);
1430 i+= MAX_FILENAME;
1431 #ifdef HAVE_REMOTE_LCD
1432 strncpy((char *)global_settings.rwps_file, (char *)&config_block[i],
1433 MAX_FILENAME);
1434 i+= MAX_FILENAME;
1435 #endif
1437 #ifdef CONFIG_TUNER
1438 strncpy((char *)global_settings.fmr_file, (char *)&config_block[i],
1439 MAX_FILENAME);
1440 i+= MAX_FILENAME;
1441 #endif
1443 #if LCD_DEPTH > 1
1444 strncpy((char *)global_settings.backdrop_file, (char *)&config_block[i],
1445 MAX_FILENAME);
1446 i+= MAX_FILENAME;
1447 #endif
1448 #ifdef HAVE_LCD_BITMAP
1449 strncpy((char *)global_settings.kbd_file, (char *)&config_block[i],
1450 MAX_FILENAME);
1451 i+= MAX_FILENAME;
1452 #endif
1456 void set_file(char* filename, char* setting, int maxlen)
1458 char* fptr = strrchr(filename,'/');
1459 int len;
1460 int extlen = 0;
1461 char* ptr;
1463 if (!fptr)
1464 return;
1466 *fptr = 0;
1467 fptr++;
1469 len = strlen(fptr);
1470 ptr = fptr + len;
1471 while ((*ptr != '.') && (ptr != fptr)) {
1472 extlen++;
1473 ptr--;
1475 if(ptr == fptr) extlen = 0;
1477 if (strncasecmp(ROCKBOX_DIR, filename ,strlen(ROCKBOX_DIR)) ||
1478 (len-extlen > maxlen))
1479 return;
1481 strncpy(setting, fptr, len-extlen);
1482 setting[len-extlen]=0;
1484 settings_save();
1487 /* helper to sort a .cfg file entry into a global_settings member,
1488 as described per table. Returns the position if found, else 0. */
1489 static int load_cfg_table(
1490 const struct bit_entry* p_table, /* the table which describes the entries */
1491 int count, /* number of entries in the table, including the first */
1492 const char* name, /* the item to be searched */
1493 const char* value, /* the value which got loaded for that item */
1494 int hint) /* position to start looking */
1496 int i = hint;
1500 if (p_table[i].cfg_name != NULL && !strcasecmp(name, p_table[i].cfg_name))
1501 { /* found */
1502 int val = 0;
1503 if (p_table[i].cfg_val == NULL)
1504 { /* numerical value, just convert the string */
1505 val = atoi(value);
1507 #if HAVE_LCD_COLOR
1508 else if (!strncasecmp(p_table[i].cfg_val,"rgb",4))
1510 val = hex_to_rgb(value);
1512 #endif
1513 else
1514 { /* set of string values, find the index */
1515 const char* item;
1516 const char* run;
1517 int len = strlen(value);
1519 item = run = p_table[i].cfg_val;
1521 while(1)
1523 /* count the length of the field */
1524 while (*run != ',' && *run != '\0')
1525 run++;
1527 if (!strncasecmp(value, item, MAX(run-item, len)))
1528 break; /* match, exit the search */
1530 if (*run == '\0') /* reached the end of the choices */
1531 return i; /* return the position, but don't update */
1533 val++; /* count the item up */
1534 run++; /* behind the ',' */
1535 item = run;
1539 /* could do a memcpy, but that would be endian-dependent */
1540 switch(p_table[i].byte_size)
1542 case 1:
1543 ((unsigned char*)&global_settings)[p_table[i].settings_offset] =
1544 (unsigned char)val;
1545 break;
1546 case 2:
1547 ((unsigned short*)&global_settings)[p_table[i].settings_offset/2] =
1548 (unsigned short)val;
1549 break;
1550 case 4:
1551 ((unsigned int*)&global_settings)[p_table[i].settings_offset/4] =
1552 (unsigned int)val;
1553 break;
1554 default:
1555 DEBUGF( "illegal size!" );
1556 continue;
1559 return i; /* return the position */
1562 i++;
1563 if (i==count)
1564 i=1; /* wraparound */
1565 } while (i != hint); /* back where we started, all searched */
1567 return 0; /* indicate not found */
1571 bool settings_load_config(const char* file)
1573 int fd;
1574 char line[128];
1576 fd = open(file, O_RDONLY);
1577 if (fd < 0)
1578 return false;
1580 while (read_line(fd, line, sizeof line) > 0)
1582 char* name;
1583 char* value;
1584 const struct bit_entry* table[2] = { rtc_bits, hd_bits };
1585 const int ta_size[2] = {
1586 sizeof(rtc_bits)/sizeof(rtc_bits[0]),
1587 sizeof(hd_bits)/sizeof(hd_bits[0])
1589 int last_table = 0; /* which table was used last round */
1590 int last_pos = 1; /* at which position did we succeed */
1591 int pos; /* currently returned position */
1593 if (!settings_parseline(line, &name, &value))
1594 continue;
1596 /* check for the string values */
1597 if (!strcasecmp(name, "wps")) {
1598 #if LCD_DEPTH > 1
1599 unload_wps_backdrop();
1600 #endif
1601 int fd2;
1602 if ((fd2 = open(value, O_RDONLY)) >= 0) {
1603 close(fd2);
1604 set_file(value, (char *)global_settings.wps_file, MAX_FILENAME);
1607 #if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
1608 else if (!strcasecmp(name, "rwps")) {
1609 int fd2;
1610 if ((fd2 = open(value, O_RDONLY)) >= 0) {
1611 close(fd2);
1612 set_file(value, (char *)global_settings.rwps_file, MAX_FILENAME);
1615 #endif
1616 else if (!strcasecmp(name, "lang")) {
1617 if (!lang_load(value))
1619 set_file(value, (char *)global_settings.lang_file, MAX_FILENAME);
1620 talk_init(); /* use voice of same language */
1623 #ifdef CONFIG_TUNER
1624 else if (!strcasecmp(name, "fmr")) {
1625 set_file(value, global_settings.fmr_file, MAX_FILENAME);
1627 #endif
1628 #ifdef HAVE_LCD_BITMAP
1629 else if (!strcasecmp(name, "font")) {
1630 if (font_load(value))
1631 set_file(value, (char *)global_settings.font_file, MAX_FILENAME);
1633 #endif
1634 #if LCD_DEPTH > 1
1635 else if (!strcasecmp(name, "backdrop")) {
1636 if (load_main_backdrop(value)) {
1637 set_file(value, (char *)global_settings.backdrop_file, MAX_FILENAME);
1638 show_main_backdrop();
1641 #endif
1642 #ifdef HAVE_LCD_BITMAP
1643 else if (!strcasecmp(name, "keyboard")) {
1644 if (!load_kbd(value))
1645 set_file(value, (char *)global_settings.kbd_file, MAX_FILENAME);
1647 #endif
1650 /* check for scalar values, using the two tables */
1651 pos = load_cfg_table(table[last_table], ta_size[last_table],
1652 name, value, last_pos);
1653 if (pos) /* success */
1655 last_pos = pos; /* remember as a position hint for next round */
1656 continue;
1659 last_table = 1-last_table; /* try other table */
1660 last_pos = 1; /* search from start */
1661 pos = load_cfg_table(table[last_table], ta_size[last_table],
1662 name, value, last_pos);
1663 if (pos) /* success */
1665 last_pos = pos; /* remember as a position hint for next round */
1666 continue;
1670 close(fd);
1671 settings_apply();
1672 settings_save();
1673 return true;
1677 /* helper to save content of global_settings into a file,
1678 as described per table */
1679 static void save_cfg_table(const struct bit_entry* p_table, int count, int fd)
1681 long value; /* 32 bit content */
1682 int i;
1683 const struct bit_entry* p_run = p_table; /* start after the size info */
1684 count--; /* first is excluded from loop */
1686 for (i=0; i<count; i++)
1688 p_run++;
1690 if (p_run->cfg_name == NULL)
1691 continue; /* this value is not to be saved */
1693 /* could do a memcpy, but that would be endian-dependent */
1694 switch(p_run->byte_size)
1696 case 1:
1697 if (p_run->bit_size & SIGNED) /* signed? */
1698 value = ((char*)&global_settings)[p_run->settings_offset];
1699 else
1700 value = ((unsigned char*)&global_settings)[p_run->settings_offset];
1701 break;
1702 case 2:
1703 if (p_run->bit_size & SIGNED) /* signed? */
1704 value = ((short*)&global_settings)[p_run->settings_offset/2];
1705 else
1706 value = ((unsigned short*)&global_settings)[p_run->settings_offset/2];
1707 break;
1708 case 4:
1709 value = ((unsigned int*)&global_settings)[p_run->settings_offset/4];
1710 break;
1711 default:
1712 DEBUGF( "illegal size!" );
1713 continue;
1716 if (p_run->cfg_val == NULL) /* write as number */
1718 fdprintf(fd, "%s: %ld\r\n", p_run->cfg_name, value);
1720 #ifdef HAVE_LCD_COLOR
1721 else if (!strcasecmp(p_run->cfg_val, "rgb"))
1723 fdprintf(fd, "%s: %02x%02x%02x\r\n", p_run->cfg_name,
1724 (int)RGB_UNPACK_RED(value),
1725 (int)RGB_UNPACK_GREEN(value),
1726 (int)RGB_UNPACK_BLUE(value));
1728 #endif
1729 else /* write as item */
1731 const char* p = p_run->cfg_val;
1733 fdprintf(fd, "%s: ", p_run->cfg_name);
1735 while(value >= 0)
1737 char c = *p++; /* currently processed char */
1738 if (c == ',') /* separator */
1739 value--;
1740 else if (c == '\0') /* end of string */
1741 break; /* not found */
1742 else if (value == 0) /* the right place */
1743 write(fd, &c, 1); /* char by char, this is lame, OK */
1746 fdprintf(fd, "\r\n");
1747 if (p_run->cfg_val != off_on) /* explaination for non-bool */
1748 fdprintf(fd, "# (possible values: %s)\r\n", p_run->cfg_val);
1753 bool settings_save_config(void)
1755 int fd;
1756 char filename[MAX_PATH];
1758 create_numbered_filename(filename, ROCKBOX_DIR, "config", ".cfg", 2
1759 IF_CNFN_NUM_(, NULL));
1761 /* allow user to modify filename */
1762 while (true) {
1763 if (!kbd_input(filename, sizeof filename)) {
1764 fd = creat(filename, O_WRONLY);
1765 if (fd < 0)
1766 gui_syncsplash(HZ, true, str(LANG_FAILED));
1767 else
1768 break;
1770 else {
1771 gui_syncsplash(HZ, true, str(LANG_MENU_SETTING_CANCEL));
1772 return false;
1776 fdprintf(fd, "# .cfg file created by rockbox %s - "
1777 "http://www.rockbox.org\r\n#\r\n#\r\n# wps / rwps / language"
1778 " / font / fmpreset / backdrop \r\n#\r\n", appsversion);
1780 if (global_settings.wps_file[0] != 0)
1781 fdprintf(fd, "wps: %s/%s.wps\r\n", WPS_DIR,
1782 global_settings.wps_file);
1784 #ifdef HAVE_REMOTE_LCD
1785 if (global_settings.rwps_file[0] != 0)
1786 fdprintf(fd, "rwps: %s/%s.rwps\r\n", WPS_DIR,
1787 global_settings.rwps_file);
1788 #endif
1790 if (global_settings.lang_file[0] != 0)
1791 fdprintf(fd, "lang: %s/%s.lng\r\n", LANG_DIR,
1792 global_settings.lang_file);
1794 #ifdef HAVE_LCD_BITMAP
1795 if (global_settings.font_file[0] != 0)
1796 fdprintf(fd, "font: %s/%s.fnt\r\n", FONT_DIR,
1797 global_settings.font_file);
1798 #endif
1800 #if LCD_DEPTH > 1
1801 if (global_settings.backdrop_file[0] != 0)
1802 fdprintf(fd, "backdrop: %s/%s.bmp\r\n", BACKDROP_DIR,
1803 global_settings.backdrop_file);
1804 #endif
1806 #ifdef CONFIG_TUNER
1807 if (global_settings.fmr_file[0] != 0)
1808 fdprintf(fd, "fmr: %s/%s.fmr\r\n", FMPRESET_PATH,
1809 global_settings.fmr_file);
1810 #endif
1812 #ifdef HAVE_LCD_BITMAP
1813 if (global_settings.kbd_file[0] != 0)
1814 fdprintf(fd, "keyboard: %s/%s.kbd\r\n", ROCKBOX_DIR,
1815 global_settings.kbd_file);
1816 #endif
1818 /* here's the action: write values to file, specified via table */
1819 save_cfg_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), fd);
1820 save_cfg_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]), fd);
1822 close(fd);
1824 gui_syncsplash(HZ, true, str(LANG_SETTINGS_SAVED));
1825 return true;
1829 /* helper to load defaults from table into global_settings members */
1830 static void default_table(const struct bit_entry* p_table, int count)
1832 int i;
1834 for (i=1; i<count; i++) /* exclude the first, the size placeholder */
1836 /* could do a memcpy, but that would be endian-dependent */
1837 switch(p_table[i].byte_size)
1839 case 1:
1840 ((unsigned char*)&global_settings)[p_table[i].settings_offset] =
1841 (unsigned char)p_table[i].default_val;
1842 break;
1843 case 2:
1844 ((unsigned short*)&global_settings)[p_table[i].settings_offset/2] =
1845 (unsigned short)p_table[i].default_val;
1846 break;
1847 case 4:
1848 ((unsigned int*)&global_settings)[p_table[i].settings_offset/4] =
1849 (unsigned int)p_table[i].default_val;
1850 break;
1851 default:
1852 DEBUGF( "illegal size!" );
1853 continue;
1860 * reset all settings to their default value
1862 void settings_reset(void) {
1864 DEBUGF( "settings_reset()\n" );
1866 /* read defaults from table(s) into global_settings */
1867 default_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]));
1868 default_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]));
1870 /* do some special cases not covered by table */
1871 global_settings.volume = sound_default(SOUND_VOLUME);
1872 global_settings.balance = sound_default(SOUND_BALANCE);
1873 global_settings.bass = sound_default(SOUND_BASS);
1874 global_settings.treble = sound_default(SOUND_TREBLE);
1875 global_settings.channel_config = sound_default(SOUND_CHANNELS);
1876 global_settings.stereo_width = sound_default(SOUND_STEREO_WIDTH);
1877 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
1878 global_settings.loudness = sound_default(SOUND_LOUDNESS);
1879 global_settings.avc = sound_default(SOUND_AVC);
1880 global_settings.mdb_strength = sound_default(SOUND_MDB_STRENGTH);
1881 global_settings.mdb_harmonics = sound_default(SOUND_MDB_HARMONICS);
1882 global_settings.mdb_center = sound_default(SOUND_MDB_CENTER);
1883 global_settings.mdb_shape = sound_default(SOUND_MDB_SHAPE);
1884 global_settings.mdb_enable = sound_default(SOUND_MDB_ENABLE);
1885 global_settings.superbass = sound_default(SOUND_SUPERBASS);
1886 #endif
1887 #ifdef HAVE_LCD_CONTRAST
1888 global_settings.contrast = lcd_default_contrast();
1889 #endif
1890 #ifdef HAVE_LCD_REMOTE
1891 global_settings.remote_contrast = lcd_remote_default_contrast();
1892 #endif
1894 #ifdef CONFIG_TUNER
1895 global_settings.fmr_file[0] = '\0';
1896 #endif
1897 global_settings.wps_file[0] = '\0';
1898 #ifdef HAVE_REMOTE_LCD
1899 global_settings.rwps_file[0] = '\0';
1900 #endif
1901 global_settings.font_file[0] = '\0';
1902 global_settings.lang_file[0] = '\0';
1903 #if LCD_DEPTH > 1
1904 global_settings.backdrop_file[0] = '\0';
1905 #endif
1906 #ifdef HAVE_LCD_COLOR
1907 global_settings.fg_color = LCD_DEFAULT_FG;
1908 global_settings.bg_color = LCD_DEFAULT_BG;
1909 #endif
1910 #ifdef HAVE_LCD_BITMAP
1911 global_settings.kbd_file[0] = '\0';
1912 #endif
1913 global_settings.hold_lr_for_scroll_in_list = true;
1915 #if defined (HAVE_RECORDING) && CONFIG_CODEC == SWCODEC
1916 enc_global_settings_reset();
1917 #endif
1920 bool set_bool(const char* string, bool* variable )
1922 return set_bool_options(string, variable,
1923 (char *)STR(LANG_SET_BOOL_YES),
1924 (char *)STR(LANG_SET_BOOL_NO),
1925 NULL);
1928 /* wrapper to convert from int param to bool param in set_option */
1929 static void (*boolfunction)(bool);
1930 void bool_funcwrapper(int value)
1932 if (value)
1933 boolfunction(true);
1934 else
1935 boolfunction(false);
1938 bool set_bool_options(const char* string, bool* variable,
1939 const char* yes_str, int yes_voice,
1940 const char* no_str, int no_voice,
1941 void (*function)(bool))
1943 struct opt_items names[] = {
1944 {(unsigned char *)no_str, no_voice},
1945 {(unsigned char *)yes_str, yes_voice}
1947 bool result;
1949 boolfunction = function;
1950 result = set_option(string, variable, BOOL, names, 2,
1951 function ? bool_funcwrapper : NULL);
1952 return result;
1955 void talk_unit(int unit, int value)
1957 if (global_settings.talk_menu)
1959 if (unit < UNIT_LAST)
1960 { /* use the available unit definition */
1961 talk_value(value, unit, false);
1963 else
1964 { /* say the number, followed by an arbitrary voice ID */
1965 talk_number(value, false);
1966 talk_id(unit, true);
1971 struct value_setting_data {
1972 enum optiontype type;
1973 /* used for "value" settings.. */
1974 int max;
1975 int step;
1976 int voice_unit;
1977 const char * unit;
1978 void (*formatter)(char* dest, int dest_length,
1979 int variable, const char* unit);
1980 /* used for BOOL and "choice" settings */
1981 struct opt_items* options;
1984 char * value_setting_get_name_cb(int selected_item,void * data, char *buffer)
1986 struct value_setting_data* cb_data =
1987 (struct value_setting_data*)data;
1988 if (cb_data->type == INT && !cb_data->options)
1990 int item = cb_data->max -(selected_item*cb_data->step);
1991 if (cb_data->formatter)
1992 cb_data->formatter(buffer, MAX_PATH,item,cb_data->unit);
1993 else
1994 snprintf(buffer, MAX_PATH,"%d %s",item,cb_data->unit);
1996 else strcpy(buffer,P2STR(cb_data->options[selected_item].string));
1997 return buffer;
1999 #define type_fromvoidptr(type, value) \
2000 (type == INT)? \
2001 (int)(*(int*)(value)) \
2003 (bool)(*(bool*)(value))
2004 bool do_set_setting(const unsigned char* string, void *variable,
2005 int nb_items,int selected,
2006 struct value_setting_data *cb_data,
2007 void (*function)(int))
2009 int action;
2010 bool done = false;
2011 struct gui_synclist lists;
2012 int oldvalue;
2013 bool allow_wrap = true;
2015 if (cb_data->type == INT)
2017 oldvalue = *(int*)variable;
2018 if (variable == &global_settings.volume)
2019 allow_wrap = false;
2021 else oldvalue = *(bool*)variable;
2023 gui_synclist_init(&lists,value_setting_get_name_cb,(void*)cb_data,false,1);
2024 gui_synclist_set_title(&lists, (char*)string, NOICON);
2025 gui_synclist_set_icon_callback(&lists,NULL);
2026 gui_synclist_set_nb_items(&lists,nb_items);
2027 gui_synclist_limit_scroll(&lists,true);
2028 gui_synclist_select_item(&lists, selected);
2030 if (global_settings.talk_menu)
2032 if (cb_data->type == INT && !cb_data->options)
2033 talk_unit(cb_data->voice_unit, *(int*)variable);
2034 else talk_id(cb_data->options[selected].voice_id, false);
2037 gui_synclist_draw(&lists);
2038 while (!done)
2041 action = get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
2042 if (action == ACTION_NONE)
2043 continue;
2044 if (gui_synclist_do_button(&lists,action,
2045 allow_wrap?LIST_WRAP_UNLESS_HELD:LIST_WRAP_OFF))
2047 if (global_settings.talk_menu)
2049 int value;
2050 if (cb_data->type == INT && !cb_data->options)
2052 value = cb_data->max -
2053 gui_synclist_get_sel_pos(&lists)*cb_data->step;
2054 talk_unit(cb_data->voice_unit, value);
2056 else
2058 value = gui_synclist_get_sel_pos(&lists);
2059 talk_id(cb_data->options[value].voice_id, false);
2062 if (cb_data->type == INT && !cb_data->options)
2063 *(int*)variable = cb_data->max -
2064 gui_synclist_get_sel_pos(&lists)*cb_data->step;
2065 else if (cb_data->type == BOOL)
2066 *(bool*)variable = gui_synclist_get_sel_pos(&lists) ? true : false;
2067 else *(int*)variable = gui_synclist_get_sel_pos(&lists);
2069 else if (action == ACTION_STD_CANCEL)
2071 gui_syncsplash(HZ/2,true,str(LANG_MENU_SETTING_CANCEL));
2072 if (cb_data->type == INT)
2073 *(int*)variable = oldvalue;
2074 else *(bool*)variable = (bool)oldvalue;
2075 done = true;
2077 else if (action == ACTION_STD_OK)
2079 done = true;
2081 else if(default_event_handler(action) == SYS_USB_CONNECTED)
2082 return true;
2083 gui_syncstatusbar_draw(&statusbars, false);
2084 if ( function )
2085 function(type_fromvoidptr(cb_data->type,variable));
2087 return false;
2089 bool set_int(const unsigned char* string,
2090 const char* unit,
2091 int voice_unit,
2092 int* variable,
2093 void (*function)(int),
2094 int step,
2095 int min,
2096 int max,
2097 void (*formatter)(char*, int, int, const char*) )
2099 #if CONFIG_KEYPAD != PLAYER_PAD
2100 struct value_setting_data data = {
2101 INT,max, step, voice_unit,unit,formatter,NULL };
2102 return do_set_setting(string,variable,(max-min)/step + 1,
2103 (max-*variable)/step, &data,function);
2104 #else
2105 int count = (max-min)/step + 1;
2106 struct value_setting_data data = {
2107 INT,min, -step, voice_unit,unit,formatter,NULL };
2108 return do_set_setting(string,variable,count,
2109 count - ((max-*variable)/step), &data,function);
2110 #endif
2113 /* NOTE: the 'type' parameter specifies the actual type of the variable
2114 that 'variable' points to. not the value within. Only variables with
2115 type 'bool' should use parameter BOOL.
2117 The type separation is necessary since int and bool are fundamentally
2118 different and bit-incompatible types and can not share the same access
2119 code. */
2120 bool set_option(const char* string, void* variable, enum optiontype type,
2121 const struct opt_items* options, int numoptions, void (*function)(int))
2123 struct value_setting_data data = {
2124 type,0, 0, 0,NULL,NULL,(struct opt_items*)options };
2125 int selected;
2126 if (type == BOOL)
2127 selected = *(bool*)variable ? 1 : 0;
2128 else selected = *(int*)variable;
2129 return do_set_setting(string,variable,numoptions,
2130 selected, &data,function);
2133 #ifdef HAVE_RECORDING
2134 /* This array holds the record timer interval lengths, in seconds */
2135 static const unsigned long rec_timer_seconds[] =
2137 0, /* 0 means OFF */
2138 5*60, /* 00:05 */
2139 10*60, /* 00:10 */
2140 15*60, /* 00:15 */
2141 30*60, /* 00:30 */
2142 60*60, /* 01:00 */
2143 74*60, /* 74:00 */
2144 80*60, /* 80:00 */
2145 2*60*60, /* 02:00 */
2146 4*60*60, /* 04:00 */
2147 6*60*60, /* 06:00 */
2148 8*60*60, /* 08:00 */
2149 10L*60*60, /* 10:00 */
2150 12L*60*60, /* 12:00 */
2151 18L*60*60, /* 18:00 */
2152 24L*60*60 /* 24:00 */
2155 unsigned int rec_timesplit_seconds(void)
2157 return rec_timer_seconds[global_settings.rec_timesplit];
2160 /* This array holds the record size interval lengths, in bytes */
2161 static const unsigned long rec_size_bytes[] =
2163 0, /* 0 means OFF */
2164 5*1024*1024, /* 5MB */
2165 10*1024*1024, /* 10MB */
2166 15*1024*1024, /* 15MB */
2167 32*1024*1024, /* 32MB */
2168 64*1024*1024, /* 64MB */
2169 75*1024*1024, /* 75MB */
2170 100*1024*1024, /* 100MB */
2171 128*1024*1024, /* 128MB */
2172 256*1024*1024, /* 256MB */
2173 512*1024*1024, /* 512MB */
2174 650*1024*1024, /* 650MB */
2175 700*1024*1024, /* 700MB */
2176 1024*1024*1024, /* 1GB */
2177 1536*1024*1024, /* 1.5GB */
2178 1792*1024*1024, /* 1.75GB */
2181 unsigned long rec_sizesplit_bytes(void)
2183 return rec_size_bytes[global_settings.rec_sizesplit];
2186 * Time strings used for the trigger durations.
2187 * Keep synchronous to trigger_times in settings_apply_trigger
2189 const char * const trig_durations[TRIG_DURATION_COUNT] =
2191 "0s", "1s", "2s", "5s",
2192 "10s", "15s", "20s", "25s", "30s",
2193 "1min", "2min", "5min", "10min"
2196 void settings_apply_trigger(void)
2198 /* Keep synchronous to trig_durations and trig_durations_conf*/
2199 static const long trigger_times[TRIG_DURATION_COUNT] = {
2200 0, HZ, 2*HZ, 5*HZ,
2201 10*HZ, 15*HZ, 20*HZ, 25*HZ, 30*HZ,
2202 60*HZ, 2*60*HZ, 5*60*HZ, 10*60*HZ
2205 peak_meter_define_trigger(
2206 global_settings.rec_start_thres,
2207 trigger_times[global_settings.rec_start_duration],
2208 MIN(trigger_times[global_settings.rec_start_duration] / 2, 2*HZ),
2209 global_settings.rec_stop_thres,
2210 trigger_times[global_settings.rec_stop_postrec],
2211 trigger_times[global_settings.rec_stop_gap]
2214 #endif