1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
33 #include "backlight.h"
36 #include "mp3_playback.h"
43 #include "backlight.h"
44 #include "powermgmt.h"
53 #include "timefuncs.h"
54 #ifdef HAVE_LCD_BITMAP
57 #include "peakmeter.h"
63 #include "powermgmt.h"
70 #include "rbunicode.h"
73 #include "statusbar.h"
84 #if CONFIG_CODEC == MAS3507D
85 void dac_line_in(bool enable
);
87 struct user_settings global_settings
;
89 const char rec_base_directory
[] = REC_BASE_DIR
;
91 #if CONFIG_CODEC == SWCODEC
93 #include "pcm_playback.h"
97 #define CONFIG_BLOCK_VERSION 43
98 #define CONFIG_BLOCK_SIZE 512
99 #define RTC_BLOCK_SIZE 44
101 #ifdef HAVE_LCD_BITMAP
107 #ifdef HAVE_REMOTE_LCD
108 #include "lcd-remote.h"
112 static long config_sector
= 0; /* mark uninitialized */
113 static unsigned char config_block
[CONFIG_BLOCK_SIZE
];
116 /* descriptor for a configuration value */
117 /* (watch the struct packing and member sizes to keep this small) */
120 /* how many bits within the bitfield (1-32), MSB set if value is signed */
121 unsigned char bit_size
; /* min 6+1 bit */
122 /* how many bytes in the global_settings struct (1,2,4) */
123 unsigned char byte_size
; /* min 3 bits */
124 /* store position in global_settings struct */
125 short settings_offset
; /* min 9 bit, better 10 */
127 int default_val
; /* min 15 bit */
128 /* variable name in a .cfg file, NULL if not to be saved */
129 const char* cfg_name
;
130 /* set of values, "rgb" for a color, or NULL for a numerical value */
134 /********************************************
136 Config block as saved on the battery-packed RTC user RAM memory block
137 of 44 bytes, starting at offset 0x14 of the RTC memory space.
140 0x00 0x14 "Roc" header signature: 0x52 0x6f 0x63
141 0x03 0x17 <version byte: 0x0>
142 0x04 0x18 start of bit-table
144 0x28,0x29 unused, not reachable by set_bits() without disturbing the next 2
145 0x2A,0x2B <checksum 2 bytes: xor of 0x00-0x29>
147 Config memory is reset to 0xff and initialized with 'factory defaults' if
148 a valid header & checksum is not found. Config version number is only
149 increased when information is _relocated_ or space is _reused_ so that old
150 versions can read and modify configuration changed by new versions.
151 Memory locations not used by a given version should not be
152 modified unless the header & checksum test fails.
154 Rest of config block, only saved to disk:
155 0x2C start of 2nd bit-table
157 0xA4 (char[20]) FMR Preset file
158 0xB8 (char[20]) WPS file
159 0xCC (char[20]) Lang file
160 0xE0 (char[20]) Font file
161 ... (char[20]) RWPS file (on targets supporting a Remote WPS)
162 ... (char[20]) Main backdrop file (on color LCD targets)
164 ... to 0x200 <unused>
166 *************************************/
168 /* The persistence of the global_settings members is now controlled by
169 the two tables below, rtc_bits and hd_bits.
170 New values can just be added to the end, it will be backwards
171 compatible. If you however change order, bitsize, etc. of existing
172 entries, you need to bump CONFIG_BLOCK_VERSION to break compatibility.
176 /* convenience macro for both size and offset of global_settings member */
177 #define S_O(val) sizeof(global_settings.val), offsetof(struct user_settings, val)
178 #define SIGNED 0x80 /* for bitsize value with signed attribute */
180 /* some sets of values which are used more than once, to save memory */
181 static const char off_on
[] = "off,on";
182 static const char off_on_ask
[] = "off,on,ask";
183 static const char off_number_spell_hover
[] = "off,number,spell,hover";
184 #ifdef HAVE_LCD_BITMAP
185 static const char graphic_numeric
[] = "graphic,numeric";
188 #ifdef HAVE_RECORDING
189 /* keep synchronous to trig_durations and
190 trigger_times in settings_apply_trigger */
191 static const char trig_durations_conf
[] =
192 "0s,1s,2s,5s,10s,15s,20s,25s,30s,1min,2min,5min,10min";
195 #if defined(CONFIG_BACKLIGHT)
196 static const char backlight_times_conf
[] =
197 "off,on,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60,90";
200 /* the part of the settings which ends up in the RTC RAM, where available
201 (those we either need early, save frequently, or without spinup) */
202 static const struct bit_entry rtc_bits
[] =
204 /* placeholder, containing the size information */
205 {9, 0, 0, 0, NULL
, NULL
}, /* 9 bit to tell how far this is populated */
207 /* # of bits, offset+size, default, .cfg name, .cfg values */
209 #if CONFIG_CODEC == MAS3507D
210 {8 | SIGNED
, S_O(volume
), -18, "volume", NULL
}, /* -78...+18 */
212 {8 | SIGNED
, S_O(volume
), -25, "volume", NULL
}, /* -100...+12 / -84...0 */
214 {8 | SIGNED
, S_O(balance
), 0, "balance", NULL
}, /* -100...100 */
215 #if CONFIG_CODEC != SWCODEC /* any MAS */
216 {5 | SIGNED
, S_O(bass
), 0, "bass", NULL
}, /* -15..+15 / -12..+12 */
217 {5 | SIGNED
, S_O(treble
), 0, "treble", NULL
}, /* -15..+15 / -12..+12 */
218 #elif defined HAVE_UDA1380
219 {5, S_O(bass
), 0, "bass", NULL
}, /* 0..+24 */
220 {3, S_O(treble
), 0, "treble", NULL
}, /* 0..+6 */
221 #elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
222 || defined(HAVE_WM8731) || defined(HAVE_WM8721)
223 {5 | SIGNED
, S_O(bass
), 0, "bass", NULL
}, /* -6..+9 */
224 {5 | SIGNED
, S_O(treble
), 0, "treble", NULL
}, /* -6..+9 */
226 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
227 {5, S_O(loudness
), 0, "loudness", NULL
}, /* 0...17 */
228 {3, S_O(avc
), 0, "auto volume", "off,20ms,2,4,8" },
229 {1, S_O(superbass
), false, "superbass", off_on
},
231 {3, S_O(channel_config
), 0, "channels",
232 "stereo,mono,custom,mono left,mono right,karaoke" },
233 {8, S_O(stereo_width
), 100, "stereo width", NULL
},
235 {1, S_O(resume
), false, "resume", off_on
},
236 {1, S_O(playlist_shuffle
), false, "shuffle", off_on
},
237 {16 | SIGNED
, S_O(resume_index
), -1, NULL
, NULL
},
238 {16 | SIGNED
, S_O(resume_first_index
), 0, NULL
, NULL
},
239 {32 | SIGNED
, S_O(resume_offset
), -1, NULL
, NULL
},
240 {32 | SIGNED
, S_O(resume_seed
), -1, NULL
, NULL
},
241 {3, S_O(repeat_mode
), REPEAT_ALL
, "repeat", "off,all,one,shuffle,ab" },
243 {6, S_O(contrast
), 40, "contrast", NULL
},
244 #ifdef CONFIG_BACKLIGHT
245 {5, S_O(backlight_timeout
), 5, "backlight timeout", backlight_times_conf
},
247 {5, S_O(backlight_timeout_plugged
), 11, "backlight timeout plugged",
248 backlight_times_conf
},
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
},
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
},
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
},
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 {15, S_O(max_files_in_playlist
), 10000,
272 "max files in playlist", NULL
}, /* 1000...20000 */
273 {14, S_O(max_files_in_dir
), 400,
274 "max files in dir", NULL
}, /* 50...10000 */
276 {12, S_O(battery_capacity
), BATTERY_CAPACITY_DEFAULT
, "battery capacity",
277 NULL
}, /* 1500...3200 for NiMH, 2200...3200 for LiIon,
278 500...1500 for Alkaline */
280 {1, S_O(car_adapter_mode
), false, "car adapter mode", off_on
},
284 {1, S_O(fm_force_mono
), false, "force fm mono", off_on
},
285 {8, S_O(last_frequency
), 0, NULL
, NULL
}, /* Default: MIN_FREQ */
288 #if BATTERY_TYPES_COUNT > 1
289 {1, S_O(battery_type
), 0, "battery type", "alkaline,nimh" },
292 #ifdef HAVE_REMOTE_LCD
294 {6, S_O(remote_contrast
), 42, "remote contrast", NULL
},
295 {1, S_O(remote_invert
), false, "remote invert", off_on
},
296 {1, S_O(remote_flip_display
), false, "remote flip display", off_on
},
297 {5, S_O(remote_backlight_timeout
), 5, "remote backlight timeout",
298 backlight_times_conf
},
300 {5, S_O(remote_backlight_timeout_plugged
), 11,
301 "remote backlight timeout plugged", backlight_times_conf
},
303 #ifdef HAVE_REMOTE_LCD_TICKING
304 {1, S_O(remote_reduce_ticking
), false, "remote reduce ticking", off_on
},
308 #ifdef CONFIG_BACKLIGHT
309 {1, S_O(bl_filter_first_keypress
),
310 #ifdef HAVE_LCD_COLOR
315 "backlight filters first keypress", off_on
},
316 #ifdef HAVE_REMOTE_LCD
317 {1, S_O(remote_bl_filter_first_keypress
), false,
318 "backlight filters first remote keypress", off_on
},
323 /* new stuff to be added here */
324 /* If values are just added to the end, no need to bump the version. */
326 /* Current sum of bits: 277 (worst case, but w/o remote lcd) */
327 /* Sum of all bit sizes must not grow beyond 288! */
331 /* the part of the settings which ends up in HD sector only */
332 static const struct bit_entry hd_bits
[] =
334 /* This table starts after the 44 RTC bytes = 352 bits. */
335 /* Here we need 11 bits to tell how far this is populated. */
337 /* placeholder, containing the size information */
338 {11, 0, 0, 0, NULL
, NULL
}, /* 11 bit to tell how far this is populated */
340 /* # of bits, offset+size, default, .cfg name, .cfg values */
342 #ifdef CONFIG_BACKLIGHT
343 {1, S_O(caption_backlight
), false, "caption backlight", off_on
},
345 #ifdef HAVE_REMOTE_LCD
346 {1, S_O(remote_caption_backlight
), false,
347 "remote caption backlight", off_on
},
349 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
350 {4, S_O(brightness
), 9, "brightness", NULL
},
352 #ifdef HAVE_BACKLIGHT_PWM_FADING
353 /* backlight fading */
354 {2, S_O(backlight_fade_in
), 1, "backlight fade in", "off,500ms,1s,2s"},
355 {3, S_O(backlight_fade_out
), 3, "backlight fade out",
356 "off,500ms,1s,2s,3s,4s,5s,10s"},
359 {4, S_O(scroll_speed
), 9, "scroll speed", NULL
}, /* 0...15 */
360 {8, S_O(scroll_delay
), 100, "scroll delay", NULL
}, /* 0...250 */
361 {8, S_O(bidir_limit
), 50, "bidir limit", NULL
}, /* 0...200 */
362 #ifdef HAVE_LCD_BITMAP
363 {1, S_O(offset_out_of_view
), false, "Screen Scrolls Out Of View", off_on
},
365 {9, S_O(scroll_step
), 6, "scroll step", NULL
},
366 {9, S_O(screen_scroll_step
), 16, "screen scroll step", NULL
},
367 #elif LCD_WIDTH > 127
368 {8, S_O(scroll_step
), 6, "scroll step", NULL
},
369 {8, S_O(screen_scroll_step
), 16, "screen scroll step", NULL
},
371 {7, S_O(scroll_step
), 6, "scroll step", NULL
},
372 {7, S_O(screen_scroll_step
), 16, "screen scroll step", NULL
},
374 #endif /* HAVE_LCD_BITMAP */
375 #ifdef HAVE_LCD_CHARCELLS
376 {3, S_O(jump_scroll
), 0, "jump scroll", NULL
}, /* 0...5 */
377 {8, S_O(jump_scroll_delay
), 50, "jump scroll delay", NULL
}, /* 0...250 */
379 {1, S_O(scroll_paginated
), false, "scroll paginated", off_on
},
381 #ifdef HAVE_LCD_COLOR
382 {LCD_DEPTH
,S_O(fg_color
),LCD_DEFAULT_FG
,"foreground color","rgb"},
383 {LCD_DEPTH
,S_O(bg_color
),LCD_DEFAULT_BG
,"background color","rgb"},
387 {1, S_O(play_selected
), true, "play selected", off_on
},
388 {1, S_O(fade_on_stop
), true, "volume fade", off_on
},
389 {4, S_O(ff_rewind_min_step
), FF_REWIND_1000
,
390 "scan min step", "1,2,3,4,5,6,8,10,15,20,25,30,45,60" },
391 {4, S_O(ff_rewind_accel
), 3, "scan accel", NULL
},
392 #if CONFIG_CODEC == SWCODEC
393 {3, S_O(buffer_margin
), 0, "antiskip",
394 "5s,15s,30s,1min,2min,3min,5min,10min" },
396 {3, S_O(buffer_margin
), 0, "antiskip", NULL
},
400 #ifdef HAVE_ATA_POWER_OFF
401 {1, S_O(disk_poweroff
), false, "disk poweroff", off_on
},
403 {8, S_O(disk_spindown
), 5, "disk spindown", NULL
},
404 #endif /* HAVE_MMC */
407 {3, S_O(dirfilter
), SHOW_SUPPORTED
,
408 "show files", "all,supported,music,playlists,id3 database" },
409 {1, S_O(sort_case
), false, "sort case", off_on
},
410 {1, S_O(browse_current
), false, "follow playlist", off_on
},
412 {1, S_O(playlist_viewer_icons
), true, "playlist viewer icons", off_on
},
413 {1, S_O(playlist_viewer_indices
), true,
414 "playlist viewer indices", off_on
},
415 {1, S_O(playlist_viewer_track_display
), 0,
416 "playlist viewer track display", "track name,full path" },
417 {2, S_O(recursive_dir_insert
), RECURSE_OFF
,
418 "recursive directory insert", off_on_ask
},
420 {3, S_O(autocreatebookmark
), BOOKMARK_NO
, "autocreate bookmarks",
421 "off,on,ask,recent only - on,recent only - ask" },
422 {2, S_O(autoloadbookmark
), BOOKMARK_NO
,
423 "autoload bookmarks", off_on_ask
},
424 {2, S_O(usemrb
), BOOKMARK_NO
,
425 "use most-recent-bookmarks", "off,on,unique only" },
426 #ifdef HAVE_LCD_BITMAP
428 {5, S_O(peak_meter_clip_hold
), 16, "peak meter clip hold", /* 0...25 */
429 "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" },
430 {5, S_O(peak_meter_hold
), 3, "peak meter hold",
431 "off,200ms,300ms,500ms,1,2,3,4,5,6,7,8,9,10,15,20,30,1min" },
432 {7, S_O(peak_meter_release
), 8, "peak meter release", NULL
}, /* 0...126 */
433 {1, S_O(peak_meter_dbfs
), true, "peak meter dbfs", off_on
},
434 {7, S_O(peak_meter_min
), 60, "peak meter min", NULL
}, /* 0...100 */
435 {7, S_O(peak_meter_max
), 0, "peak meter max", NULL
}, /* 0...100 */
437 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
438 {7, S_O(mdb_strength
), 0, "mdb strength", NULL
},
439 {7, S_O(mdb_harmonics
), 0, "mdb harmonics", NULL
},
440 {9, S_O(mdb_center
), 0, "mdb center", NULL
},
441 {9, S_O(mdb_shape
), 0, "mdb shape", NULL
},
442 {1, S_O(mdb_enable
), 0, "mdb enable", off_on
},
444 #if CONFIG_CODEC == MAS3507D
445 {1, S_O(line_in
), false, "line in", off_on
},
448 {2, S_O(talk_dir
), 0, "talk dir", off_number_spell_hover
},
449 {2, S_O(talk_file
), 0, "talk file", off_number_spell_hover
},
450 {1, S_O(talk_menu
), true, "talk menu", off_on
},
452 {2, S_O(sort_file
), 0, "sort files", "alpha,oldest,newest,type" },
453 {2, S_O(sort_dir
), 0, "sort dirs", "alpha,oldest,newest" },
454 {1, S_O(id3_v1_first
), 0, "id3 tag priority", "v2-v1,v1-v2"},
456 #ifdef HAVE_RECORDING
458 {1, S_O(rec_startup
), false, "rec screen on startup", off_on
},
459 {4, S_O(rec_timesplit
), 0, "rec timesplit", /* 0...15 */
460 "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" },
461 {1, S_O(rec_channels
), 0, "rec channels", "stereo,mono" },
463 {2, S_O(rec_source
), 0 /* 0=mic */, "rec source", "mic,line,spdif" },
465 {1, S_O(rec_source
), 0 /* 0=mic */, "rec source", "mic,line" },
467 {5, S_O(rec_prerecord_time
), 0, "prerecording time", NULL
}, /* 0...30 */
468 {1, S_O(rec_directory
), 0, /* rec_base_directory */
469 "rec directory", REC_BASE_DIR
",current" },
470 #ifdef CONFIG_BACKLIGHT
471 {2, S_O(cliplight
), 0, "cliplight", "off,main,both,remote" },
473 #if CONFIG_CODEC == MAS3587F
474 {4, S_O(rec_mic_gain
), 8, "rec mic gain", NULL
},
475 {4, S_O(rec_left_gain
), 2 /* 0dB */, "rec left gain", NULL
}, /* 0...15 */
476 {4, S_O(rec_right_gain
), 2 /* 0dB */, "rec right gain", NULL
}, /* 0...15 */
477 {3, S_O(rec_frequency
), 0, /* 0=44.1kHz */
478 "rec frequency", "44,48,32,22,24,16" },
479 {1, S_O(rec_editable
), false, "editable recordings", off_on
},
480 {3, S_O(rec_quality
), 5, "rec quality", NULL
},
481 #elif defined(HAVE_UDA1380)
482 {8|SIGNED
, S_O(rec_mic_gain
), 16 /* 8 dB */, "rec mic gain", NULL
}, /* -128...+108 */
483 {8|SIGNED
, S_O(rec_left_gain
), 0, "rec left gain", NULL
}, /* -128...+96 */
484 {8|SIGNED
, S_O(rec_right_gain
), 0, "rec right gain", NULL
}, /* -128...+96 */
485 {3, S_O(rec_frequency
), 0, /* 0=44.1kHz */
486 "rec frequency", "44,48,32,22,24,16" },
489 /* values for the trigger */
490 {8 | SIGNED
, S_O(rec_start_thres
), -35, "trigger start threshold", NULL
},
491 {8 | SIGNED
, S_O(rec_stop_thres
), -45, "trigger stop threshold", NULL
},
492 {4, S_O(rec_start_duration
), 0, "trigger start duration", trig_durations_conf
},
493 {4, S_O(rec_stop_postrec
), 2, "trigger stop postrec", trig_durations_conf
},
494 {4, S_O(rec_stop_gap
), 1, "trigger min gap", trig_durations_conf
},
495 {4, S_O(rec_trigger_mode
), 0, "trigger mode", "off,once,repeat"},
496 #endif /* HAVE_RECORDING */
498 #ifdef HAVE_SPDIF_POWER
499 {1, S_O(spdif_enable
), false, "spdif enable", off_on
},
502 {1, S_O(next_folder
), false, "folder navigation", off_on
},
503 {1, S_O(runtimedb
), false, "gather runtime data", off_on
},
505 #if CONFIG_CODEC == SWCODEC
506 {1, S_O(replaygain
), false, "replaygain", off_on
},
507 {2, S_O(replaygain_type
), REPLAYGAIN_ALBUM
, "replaygain type",
508 "track,album,track shuffle" },
509 {1, S_O(replaygain_noclip
), false, "replaygain noclip", off_on
},
510 {8 | SIGNED
, S_O(replaygain_preamp
), 0, "replaygain preamp", NULL
},
511 {2, S_O(beep
), 0, "beep", "off,weak,moderate,strong" },
512 {2, S_O(crossfade
), 0, "crossfade", "off,shuffle,track skip,always"},
513 {3, S_O(crossfade_fade_in_delay
), 0, "crossfade fade in delay", NULL
},
514 {3, S_O(crossfade_fade_out_delay
), 0, "crossfade fade out delay", NULL
},
515 {4, S_O(crossfade_fade_in_duration
), 0, "crossfade fade in duration", NULL
},
516 {4, S_O(crossfade_fade_out_duration
), 0, "crossfade fade out duration", NULL
},
517 {1, S_O(crossfade_fade_out_mixmode
), 0, "crossfade fade out mode", "crossfade,mix"},
518 {1, S_O(crossfeed
), false, "crossfeed", off_on
},
519 {6, S_O(crossfeed_direct_gain
), 15, "crossfeed direct gain", NULL
},
520 {7, S_O(crossfeed_cross_gain
), 60, "crossfeed cross gain", NULL
},
521 {8, S_O(crossfeed_hf_attenuation
), 160, "crossfeed hf attenuation", NULL
},
522 {11, S_O(crossfeed_hf_cutoff
), 700, "crossfeed hf cutoff", NULL
},
525 {1, S_O(eq_enabled
), false, "eq enabled", off_on
},
526 {8, S_O(eq_precut
), 0, "eq precut", NULL
},
528 {15, S_O(eq_band0_cutoff
), 60, "eq band 0 cutoff", NULL
},
529 {15, S_O(eq_band1_cutoff
), 200, "eq band 1 cutoff", NULL
},
530 {15, S_O(eq_band2_cutoff
), 800, "eq band 2 cutoff", NULL
},
531 {15, S_O(eq_band3_cutoff
), 4000, "eq band 3 cutoff", NULL
},
532 {15, S_O(eq_band4_cutoff
), 12000, "eq band 4 cutoff", NULL
},
533 /* 0..64 (or 0.0 to 6.4) */
534 {6, S_O(eq_band0_q
), 7, "eq band 0 q", NULL
},
535 {6, S_O(eq_band1_q
), 10, "eq band 1 q", NULL
},
536 {6, S_O(eq_band2_q
), 10, "eq band 2 q", NULL
},
537 {6, S_O(eq_band3_q
), 10, "eq band 3 q", NULL
},
538 {6, S_O(eq_band4_q
), 7, "eq band 4 q", NULL
},
539 /* -240..240 (or -24db to +24db) */
540 {9|SIGNED
, S_O(eq_band0_gain
), 0, "eq band 0 gain", NULL
},
541 {9|SIGNED
, S_O(eq_band1_gain
), 0, "eq band 1 gain", NULL
},
542 {9|SIGNED
, S_O(eq_band2_gain
), 0, "eq band 2 gain", NULL
},
543 {9|SIGNED
, S_O(eq_band3_gain
), 0, "eq band 3 gain", NULL
},
544 {9|SIGNED
, S_O(eq_band4_gain
), 0, "eq band 4 gain", NULL
},
548 {1, S_O(dircache
), false, "dircache", off_on
},
549 {22, S_O(dircache_size
), 0, NULL
, NULL
},
550 {1, S_O(tagcache_ram
), 0, "tagcache_ram", off_on
},
553 {4, S_O(default_codepage
), 0, "default codepage",
554 "iso8859-1,iso8859-7,iso8859-8,cp1251,iso8859-11,cp1256,iso8859-9,iso8859-2,sjis,gb2312,ksx1001,big5,utf-8,cp1256" },
556 {1, S_O(warnon_erase_dynplaylist
), false,
557 "warn when erasing dynamic playlist", off_on
},
559 /* If values are just added to the end, no need to bump the version. */
560 /* new stuff to be added at the end */
562 /* Sum of all bit sizes must not grow beyond 0xB8*8 = 1472 */
565 /* helper function to extract n (<=32) bits from an arbitrary position
566 * counting from LSB to MSB */
567 static uint32_t get_bits(
568 const uint32_t *p
, /* the start of the bitfield array */
569 unsigned int from
, /* bit no. to start reading from */
570 unsigned int size
) /* how many bits to read */
572 unsigned int long_index
= from
/ 32;
573 unsigned int bit_index
= from
% 32;
576 result
= p
[long_index
] >> bit_index
;
578 if (bit_index
+ size
> 32) /* crossing longword boundary */
579 result
|= p
[long_index
+1] << (32 - bit_index
);
581 result
&= 0xFFFFFFFF >> (32 - size
);
586 /* helper function to set n (<=32) bits to an arbitrary position,
587 * counting from LSB to MSB */
588 static void set_bits(
589 uint32_t *p
, /* the start of the bitfield array */
590 unsigned int from
, /* bit no. to start writing into */
591 unsigned int size
, /* how many bits to change */
592 uint32_t value
) /* content (LSBs will be taken) */
594 unsigned int long_index
= from
/ 32;
595 unsigned int bit_index
= from
% 32;
598 mask
= 0xFFFFFFFF >> (32 - size
);
602 if (bit_index
+ size
> 32)
604 (p
[long_index
+1] & (0xFFFFFFFF << (bit_index
+ size
- 32)))
605 | (value
>> (32 - bit_index
));
607 p
[long_index
] = (p
[long_index
] & ~mask
) | (value
<< bit_index
);
610 #ifdef HAVE_LCD_COLOR
612 * Helper function to convert a string of 6 hex digits to a native colour
615 #define hex2dec(c) (((c) >= '0' && ((c) <= '9')) ? (toupper(c)) - '0' : \
616 (toupper(c)) - 'A' + 10)
618 int hex_to_rgb(const char* hex
)
621 int red
, green
, blue
;
623 if (strlen(hex
) == 6) {
624 for (i
=0; i
< 6; i
++ ) {
625 if (!isxdigit(hex
[i
])) {
632 red
= (hex2dec(hex
[0]) << 4) | hex2dec(hex
[1]);
633 green
= (hex2dec(hex
[2]) << 4) | hex2dec(hex
[3]);
634 blue
= (hex2dec(hex
[4]) << 4) | hex2dec(hex
[5]);
635 return LCD_RGBPACK(red
,green
,blue
);
644 * Calculates the checksum for the config block and returns it
647 static unsigned short calculate_config_checksum(const unsigned char* buf
)
650 unsigned char cksum
[2];
651 cksum
[0] = cksum
[1] = 0;
653 for (i
=0; i
< RTC_BLOCK_SIZE
- 2; i
+=2 ) {
655 cksum
[1] ^= buf
[i
+1];
658 return (cksum
[0] << 8) | cksum
[1];
662 * initialize the config block buffer
664 static void init_config_buffer( void )
666 DEBUGF( "init_config_buffer()\n" );
668 /* reset to 0 - all unused */
669 memset(config_block
, 0, CONFIG_BLOCK_SIZE
);
671 config_block
[0] = 'R';
672 config_block
[1] = 'o';
673 config_block
[2] = 'c';
674 config_block
[3] = CONFIG_BLOCK_VERSION
;
678 * save the config block buffer to disk or RTC RAM
680 static int save_config_buffer( void )
682 unsigned short chksum
;
687 /* update the checksum in the end of the block before saving */
688 chksum
= calculate_config_checksum(config_block
);
689 config_block
[ RTC_BLOCK_SIZE
- 2 ] = chksum
>> 8;
690 config_block
[ RTC_BLOCK_SIZE
- 1 ] = chksum
& 0xff;
693 /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so
694 that it would write a number of bytes at a time since the RTC chip
695 supports that, but this will have to do for now 8-) */
696 for (i
=0; i
< RTC_BLOCK_SIZE
; i
++ ) {
697 int r
= rtc_write(0x14+i
, config_block
[i
]);
699 DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n",
707 if (config_sector
!= 0)
708 ata_delayed_write( config_sector
, config_block
);
716 * load the config block buffer from disk or RTC RAM
718 static int load_config_buffer(int which
)
720 unsigned short chksum
;
721 bool correct
= false;
724 DEBUGF( "load_config_buffer()\n" );
726 if (which
& SETTINGS_HD
)
728 if (config_sector
!= 0) {
729 ata_read_sectors(IF_MV2(0,) config_sector
, 1, config_block
);
730 /* calculate the checksum, check it and the header */
731 chksum
= calculate_config_checksum(config_block
);
733 if (config_block
[0] == 'R' &&
734 config_block
[1] == 'o' &&
735 config_block
[2] == 'c' &&
736 config_block
[3] == CONFIG_BLOCK_VERSION
&&
737 (chksum
>> 8) == config_block
[RTC_BLOCK_SIZE
- 2] &&
738 (chksum
& 0xff) == config_block
[RTC_BLOCK_SIZE
- 1])
740 DEBUGF( "load_config_buffer: header & checksum test ok\n" );
749 /* If the disk sector was incorrect, reinit the buffer */
750 memset(config_block
, 0, CONFIG_BLOCK_SIZE
);
753 if (which
& SETTINGS_RTC
)
756 unsigned char rtc_block
[RTC_BLOCK_SIZE
];
759 for (i
=0; i
< RTC_BLOCK_SIZE
; i
++ )
760 rtc_block
[i
] = rtc_read(0x14+i
);
762 chksum
= calculate_config_checksum(rtc_block
);
764 /* if rtc block is ok, use that */
765 if (rtc_block
[0] == 'R' &&
766 rtc_block
[1] == 'o' &&
767 rtc_block
[2] == 'c' &&
768 rtc_block
[3] == CONFIG_BLOCK_VERSION
&&
769 (chksum
>> 8) == rtc_block
[RTC_BLOCK_SIZE
- 2] &&
770 (chksum
& 0xff) == rtc_block
[RTC_BLOCK_SIZE
- 1])
772 memcpy(config_block
, rtc_block
, RTC_BLOCK_SIZE
);
779 /* if checksum is not valid, clear the config buffer */
780 DEBUGF( "load_config_buffer: header & checksum test failed\n" );
781 init_config_buffer();
789 /* helper to save content of global_settings into a bitfield,
790 as described per table */
791 static void save_bit_table(const struct bit_entry
* p_table
, int count
, int bitstart
)
793 uint32_t *p_bitfield
= (uint32_t *)config_block
; /* 32 bit addr. */
794 uint32_t value
; /* 32 bit content */
796 const struct bit_entry
* p_run
= p_table
; /* start after the size info */
797 int curr_bit
= bitstart
+ p_table
->bit_size
;
798 count
--; /* first is excluded from loop */
800 for (i
=0; i
<count
; i
++)
803 /* could do a memcpy, but that would be endian-dependent */
804 switch(p_run
->byte_size
)
807 value
= ((uint8_t *)&global_settings
)[p_run
->settings_offset
];
810 value
= ((uint16_t *)&global_settings
)[p_run
->settings_offset
/2];
813 value
= ((uint32_t *)&global_settings
)[p_run
->settings_offset
/4];
816 DEBUGF( "save_bit_table: illegal size!\n" );
819 set_bits(p_bitfield
, curr_bit
, p_run
->bit_size
& 0x3F, value
);
820 curr_bit
+= p_run
->bit_size
& 0x3F;
822 set_bits(p_bitfield
, bitstart
, p_table
->bit_size
, /* write size */
823 curr_bit
); /* = position after last element */
827 * figure out the config sector from the partition table and the
828 * mounted file system
830 void settings_calc_config_sector(void)
836 long partition_start
;
839 if (fat_startsector(IF_MV(0)) != 0) /* There is a partition table */
842 for (i
= 0; i
< 4; i
++)
844 partition_start
= disk_partinfo(i
)->start
;
845 if (partition_start
!= 0 && (partition_start
- 2) < sector
)
846 sector
= partition_start
- 2;
852 config_sector
= sector
;
857 * persist all runtime user settings to disk or RTC RAM
859 int settings_save( void )
866 elapsed_secs
= (current_tick
- lasttime
) / HZ
;
867 global_settings
.runtime
+= elapsed_secs
;
868 lasttime
+= (elapsed_secs
* HZ
);
870 if ( global_settings
.runtime
> global_settings
.topruntime
)
871 global_settings
.topruntime
= global_settings
.runtime
;
874 /* serialize scalar values into RTC and HD sector, specified via table */
875 save_bit_table(rtc_bits
, sizeof(rtc_bits
)/sizeof(rtc_bits
[0]), 4*8);
876 save_bit_table(hd_bits
, sizeof(hd_bits
)/sizeof(hd_bits
[0]), RTC_BLOCK_SIZE
*8);
879 strncpy((char *)&config_block
[i
], (char *)global_settings
.wps_file
,
882 strncpy((char *)&config_block
[i
], (char *)global_settings
.lang_file
,
885 strncpy((char *)&config_block
[i
], (char *)global_settings
.font_file
,
888 #ifdef HAVE_REMOTE_LCD
889 strncpy((char *)&config_block
[i
], (char *)global_settings
.rwps_file
,
895 strncpy((char *)&config_block
[i
], (char *)global_settings
.fmr_file
,
900 #ifdef HAVE_LCD_COLOR
901 strncpy((char *)&config_block
[i
], (char *)global_settings
.backdrop_file
,
905 #ifdef HAVE_LCD_BITMAP
906 strncpy((char *)&config_block
[i
], (char *)global_settings
.kbd_file
,
911 if(save_config_buffer())
914 #ifdef HAVE_REMOTE_LCD
915 lcd_remote_clear_display();
917 #ifdef HAVE_LCD_CHARCELLS
918 lcd_puts(0, 0, str(LANG_SETTINGS_SAVE_PLAYER
));
919 lcd_puts(0, 1, str(LANG_SETTINGS_BATTERY_PLAYER
));
921 lcd_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER
));
922 lcd_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER
));
924 #ifdef HAVE_REMOTE_LCD
925 lcd_remote_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER
));
926 lcd_remote_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER
));
936 #ifdef HAVE_LCD_BITMAP
938 * Applies the range infos stored in global_settings to
941 void settings_apply_pm_range(void)
945 /* depending on the scale mode (dBfs or percent) the values
946 of global_settings.peak_meter_dbfs have different meanings */
947 if (global_settings
.peak_meter_dbfs
)
949 /* convert to dBfs * 100 */
950 pm_min
= -(((int)global_settings
.peak_meter_min
) * 100);
951 pm_max
= -(((int)global_settings
.peak_meter_max
) * 100);
955 /* percent is stored directly -> no conversion */
956 pm_min
= global_settings
.peak_meter_min
;
957 pm_max
= global_settings
.peak_meter_max
;
960 /* apply the range */
961 peak_meter_init_range(global_settings
.peak_meter_dbfs
, pm_min
, pm_max
);
963 #endif /* HAVE_LCD_BITMAP */
965 void sound_settings_apply(void)
967 sound_set(SOUND_BASS
, global_settings
.bass
);
968 sound_set(SOUND_TREBLE
, global_settings
.treble
);
969 sound_set(SOUND_BALANCE
, global_settings
.balance
);
970 sound_set(SOUND_VOLUME
, global_settings
.volume
);
971 #if CONFIG_CODEC == SWCODEC
972 channels_set(global_settings
.channel_config
);
973 stereo_width_set(global_settings
.stereo_width
);
975 sound_set(SOUND_CHANNELS
, global_settings
.channel_config
);
976 sound_set(SOUND_STEREO_WIDTH
, global_settings
.stereo_width
);
978 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
979 sound_set(SOUND_LOUDNESS
, global_settings
.loudness
);
980 sound_set(SOUND_AVC
, global_settings
.avc
);
981 sound_set(SOUND_MDB_STRENGTH
, global_settings
.mdb_strength
);
982 sound_set(SOUND_MDB_HARMONICS
, global_settings
.mdb_harmonics
);
983 sound_set(SOUND_MDB_CENTER
, global_settings
.mdb_center
);
984 sound_set(SOUND_MDB_SHAPE
, global_settings
.mdb_shape
);
985 sound_set(SOUND_MDB_ENABLE
, global_settings
.mdb_enable
);
986 sound_set(SOUND_SUPERBASS
, global_settings
.superbass
);
990 void settings_apply(void)
993 #if CONFIG_CODEC == SWCODEC
997 sound_settings_apply();
999 audio_set_buffer_margin(global_settings
.buffer_margin
);
1001 lcd_set_contrast(global_settings
.contrast
);
1002 lcd_scroll_speed(global_settings
.scroll_speed
);
1003 #ifdef HAVE_REMOTE_LCD
1004 lcd_remote_set_contrast(global_settings
.remote_contrast
);
1005 lcd_remote_set_invert_display(global_settings
.remote_invert
);
1006 lcd_remote_set_flip(global_settings
.remote_flip_display
);
1007 lcd_remote_scroll_speed(global_settings
.scroll_speed
);
1008 lcd_remote_scroll_step(global_settings
.scroll_step
);
1009 lcd_remote_scroll_delay(global_settings
.scroll_delay
* (HZ
/10));
1010 #ifdef HAVE_REMOTE_LCD_TICKING
1011 lcd_remote_emireduce(global_settings
.remote_reduce_ticking
);
1013 remote_backlight_set_timeout(global_settings
.remote_backlight_timeout
);
1014 #ifdef HAVE_CHARGING
1015 remote_backlight_set_timeout_plugged(global_settings
.remote_backlight_timeout_plugged
);
1018 #ifdef CONFIG_BACKLIGHT
1019 backlight_set_timeout(global_settings
.backlight_timeout
);
1020 #ifdef HAVE_CHARGING
1021 backlight_set_timeout_plugged(global_settings
.backlight_timeout_plugged
);
1023 #if defined(HAVE_BACKLIGHT_PWM_FADING) && !defined(SIMULATOR)
1024 backlight_set_fade_in(global_settings
.backlight_fade_in
);
1025 backlight_set_fade_out(global_settings
.backlight_fade_out
);
1028 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
1029 backlight_set_brightness(global_settings
.brightness
);
1031 ata_spindown(global_settings
.disk_spindown
);
1032 #if (CONFIG_CODEC == MAS3507D) && !defined(SIMULATOR)
1033 dac_line_in(global_settings
.line_in
);
1035 mpeg_id3_options(global_settings
.id3_v1_first
);
1036 #ifdef HAVE_ATA_POWER_OFF
1037 ata_poweroff(global_settings
.disk_poweroff
);
1040 set_poweroff_timeout(global_settings
.poweroff
);
1042 set_battery_capacity(global_settings
.battery_capacity
);
1043 #if BATTERY_TYPES_COUNT > 1
1044 set_battery_type(global_settings
.battery_type
);
1047 #ifdef HAVE_LCD_BITMAP
1048 lcd_set_invert_display(global_settings
.invert
);
1049 lcd_set_flip(global_settings
.flip_display
);
1050 button_set_flip(global_settings
.flip_display
);
1051 lcd_update(); /* refresh after flipping the screen */
1052 settings_apply_pm_range();
1053 peak_meter_init_times(
1054 global_settings
.peak_meter_release
, global_settings
.peak_meter_hold
,
1055 global_settings
.peak_meter_clip_hold
);
1058 if ( global_settings
.wps_file
[0] &&
1059 global_settings
.wps_file
[0] != 0xff ) {
1060 snprintf(buf
, sizeof buf
, WPS_DIR
"/%s.wps",
1061 global_settings
.wps_file
);
1062 wps_data_load(gui_wps
[0].data
, buf
, true);
1065 wps_data_init(gui_wps
[0].data
);
1067 #ifdef HAVE_LCD_COLOR
1068 if ( global_settings
.backdrop_file
[0] &&
1069 global_settings
.backdrop_file
[0] != 0xff ) {
1070 snprintf(buf
, sizeof buf
, BACKDROP_DIR
"/%s.bmp",
1071 global_settings
.backdrop_file
);
1073 load_main_backdrop(buf
);
1075 lcd_set_backdrop(NULL
);
1077 screens
[SCREEN_MAIN
].set_foreground(global_settings
.fg_color
);
1078 screens
[SCREEN_MAIN
].set_background(global_settings
.bg_color
);
1081 #if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
1082 if ( global_settings
.rwps_file
[0] &&
1083 global_settings
.rwps_file
[0] != 0xff ) {
1084 snprintf(buf
, sizeof buf
, WPS_DIR
"/%s.rwps",
1085 global_settings
.rwps_file
);
1086 wps_data_load(gui_wps
[1].data
, buf
, true);
1089 wps_data_init(gui_wps
[1].data
);
1092 #ifdef HAVE_LCD_BITMAP
1093 if ( global_settings
.font_file
[0] &&
1094 global_settings
.font_file
[0] != 0xff ) {
1095 snprintf(buf
, sizeof buf
, ROCKBOX_DIR FONT_DIR
"/%s.fnt",
1096 global_settings
.font_file
);
1102 if ( global_settings
.kbd_file
[0] &&
1103 global_settings
.kbd_file
[0] != 0xff ) {
1104 snprintf(buf
, sizeof buf
, ROCKBOX_DIR
"/%s.kbd",
1105 global_settings
.kbd_file
);
1111 lcd_scroll_step(global_settings
.scroll_step
);
1112 gui_list_screen_scroll_step(global_settings
.screen_scroll_step
);
1113 gui_list_screen_scroll_out_of_view(global_settings
.offset_out_of_view
);
1115 lcd_jump_scroll(global_settings
.jump_scroll
);
1116 lcd_jump_scroll_delay(global_settings
.jump_scroll_delay
* (HZ
/10));
1118 lcd_bidir_scroll(global_settings
.bidir_limit
);
1119 lcd_scroll_delay(global_settings
.scroll_delay
* (HZ
/10));
1121 if ( global_settings
.lang_file
[0] &&
1122 global_settings
.lang_file
[0] != 0xff ) {
1123 snprintf(buf
, sizeof buf
, ROCKBOX_DIR LANG_DIR
"/%s.lng",
1124 global_settings
.lang_file
);
1126 talk_init(); /* use voice of same language */
1129 set_codepage(global_settings
.default_codepage
);
1131 #if CONFIG_CODEC == SWCODEC
1132 audio_set_crossfade(global_settings
.crossfade
);
1133 dsp_set_replaygain(true);
1134 dsp_set_crossfeed(global_settings
.crossfeed
);
1135 dsp_set_crossfeed_direct_gain(global_settings
.crossfeed_direct_gain
);
1136 dsp_set_crossfeed_cross_params(global_settings
.crossfeed_cross_gain
,
1137 global_settings
.crossfeed_cross_gain
1138 + global_settings
.crossfeed_hf_attenuation
,
1139 global_settings
.crossfeed_hf_cutoff
);
1141 dsp_set_eq(global_settings
.eq_enabled
);
1142 dsp_set_eq_precut(global_settings
.eq_precut
);
1143 /* Update all EQ bands */
1144 for(i
= 0; i
< 5; i
++) {
1145 dsp_set_eq_coefs(i
);
1149 #ifdef HAVE_SPDIF_POWER
1150 spdif_power_enable(global_settings
.spdif_enable
);
1153 #ifdef CONFIG_BACKLIGHT
1154 set_backlight_filter_keypress(global_settings
.bl_filter_first_keypress
);
1155 #ifdef HAVE_REMOTE_LCD
1156 set_remote_backlight_filter_keypress(global_settings
.remote_bl_filter_first_keypress
);
1162 /* helper to load global_settings from a bitfield, as described per table */
1163 static void load_bit_table(const struct bit_entry
* p_table
, int count
, int bitstart
)
1165 uint32_t *p_bitfield
= (uint32_t *)config_block
; /* 32 bit addr. */
1166 uint32_t value
; /* 32 bit content */
1168 int maxbit
; /* how many bits are valid in the saved part */
1169 const struct bit_entry
* p_run
= p_table
; /* start after the size info */
1170 count
--; /* first is excluded from loop */
1171 maxbit
= get_bits(p_bitfield
, bitstart
, p_table
->bit_size
);
1172 bitstart
+= p_table
->bit_size
;
1174 for (i
=0; i
<count
; i
++)
1179 size
= p_run
->bit_size
& 0x3F; /* mask off abused bits */
1180 if (bitstart
+ size
> maxbit
)
1181 break; /* exit if this is not valid any more in bitfield */
1183 value
= get_bits(p_bitfield
, bitstart
, size
);
1185 if (p_run
->bit_size
& SIGNED
)
1186 { // sign extend the read value
1187 unsigned long mask
= 0xFFFFFFFF << (size
- 1);
1188 if (value
& mask
) /* true if MSB of value is set */
1192 /* could do a memcpy, but that would be endian-dependent */
1193 switch(p_run
->byte_size
)
1196 ((uint8_t *)&global_settings
)[p_run
->settings_offset
] =
1197 (unsigned char)value
;
1200 ((uint16_t *)&global_settings
)[p_run
->settings_offset
/2] =
1201 (unsigned short)value
;
1204 ((uint32_t *)&global_settings
)[p_run
->settings_offset
/4] =
1205 (unsigned int)value
;
1208 DEBUGF( "load_bit_table: illegal size!\n" );
1216 * load settings from disk or RTC RAM
1218 void settings_load(int which
)
1221 DEBUGF( "reload_all_settings()\n" );
1223 /* load the buffer from the RTC (resets it to all-unused if the block
1224 is invalid) and decode the settings which are set in the block */
1225 if (!load_config_buffer(which
))
1227 /* load scalar values from RTC and HD sector, specified via table */
1228 if (which
& SETTINGS_RTC
)
1230 load_bit_table(rtc_bits
, sizeof(rtc_bits
)/sizeof(rtc_bits
[0]), 4*8);
1232 if (which
& SETTINGS_HD
)
1234 load_bit_table(hd_bits
, sizeof(hd_bits
)/sizeof(hd_bits
[0]),
1238 if ( global_settings
.contrast
< MIN_CONTRAST_SETTING
)
1239 global_settings
.contrast
= lcd_default_contrast();
1242 strncpy((char *)global_settings
.wps_file
, (char *)&config_block
[i
],
1245 strncpy((char *)global_settings
.lang_file
, (char *)&config_block
[i
],
1248 strncpy((char *)global_settings
.font_file
, (char *)&config_block
[i
],
1251 #ifdef HAVE_REMOTE_LCD
1252 strncpy((char *)global_settings
.rwps_file
, (char *)&config_block
[i
],
1258 strncpy((char *)global_settings
.fmr_file
, (char *)&config_block
[i
],
1263 #ifdef HAVE_LCD_COLOR
1264 strncpy((char *)global_settings
.backdrop_file
, (char *)&config_block
[i
],
1268 #ifdef HAVE_LCD_BITMAP
1269 strncpy((char *)global_settings
.kbd_file
, (char *)&config_block
[i
],
1276 void set_file(char* filename
, char* setting
, int maxlen
)
1278 char* fptr
= strrchr(filename
,'/');
1291 while ((*ptr
!= '.') && (ptr
!= fptr
)) {
1295 if(ptr
== fptr
) extlen
= 0;
1297 if (strncasecmp(ROCKBOX_DIR
, filename
,strlen(ROCKBOX_DIR
)) ||
1298 (len
-extlen
> maxlen
))
1301 strncpy(setting
, fptr
, len
-extlen
);
1302 setting
[len
-extlen
]=0;
1307 /* helper to sort a .cfg file entry into a global_settings member,
1308 as described per table. Returns the position if found, else 0. */
1309 static int load_cfg_table(
1310 const struct bit_entry
* p_table
, /* the table which describes the entries */
1311 int count
, /* number of entries in the table, including the first */
1312 const char* name
, /* the item to be searched */
1313 const char* value
, /* the value which got loaded for that item */
1314 int hint
) /* position to start looking */
1320 if (p_table
[i
].cfg_name
!= NULL
&& !strcasecmp(name
, p_table
[i
].cfg_name
))
1323 if (p_table
[i
].cfg_val
== NULL
)
1324 { /* numerical value, just convert the string */
1328 else if (!strncasecmp(p_table
[i
].cfg_val
,"rgb",4))
1330 val
= hex_to_rgb(value
);
1334 { /* set of string values, find the index */
1337 int len
= strlen(value
);
1339 item
= run
= p_table
[i
].cfg_val
;
1343 /* count the length of the field */
1344 while (*run
!= ',' && *run
!= '\0')
1347 if (!strncasecmp(value
, item
, MAX(run
-item
, len
)))
1348 break; /* match, exit the search */
1350 if (*run
== '\0') /* reached the end of the choices */
1351 return i
; /* return the position, but don't update */
1353 val
++; /* count the item up */
1354 run
++; /* behind the ',' */
1359 /* could do a memcpy, but that would be endian-dependent */
1360 switch(p_table
[i
].byte_size
)
1363 ((unsigned char*)&global_settings
)[p_table
[i
].settings_offset
] =
1367 ((unsigned short*)&global_settings
)[p_table
[i
].settings_offset
/2] =
1368 (unsigned short)val
;
1371 ((unsigned int*)&global_settings
)[p_table
[i
].settings_offset
/4] =
1375 DEBUGF( "illegal size!" );
1379 return i
; /* return the position */
1384 i
=1; /* wraparound */
1385 } while (i
!= hint
); /* back where we started, all searched */
1387 return 0; /* indicate not found */
1391 bool settings_load_config(const char* file
)
1396 fd
= open(file
, O_RDONLY
);
1400 while (read_line(fd
, line
, sizeof line
) > 0)
1404 const struct bit_entry
* table
[2] = { rtc_bits
, hd_bits
};
1405 const int ta_size
[2] = {
1406 sizeof(rtc_bits
)/sizeof(rtc_bits
[0]),
1407 sizeof(hd_bits
)/sizeof(hd_bits
[0])
1409 int last_table
= 0; /* which table was used last round */
1410 int last_pos
= 1; /* at which position did we succeed */
1411 int pos
; /* currently returned position */
1413 if (!settings_parseline(line
, &name
, &value
))
1416 /* check for the string values */
1417 if (!strcasecmp(name
, "wps")) {
1418 if (wps_data_load(gui_wps
[0].data
, value
, true))
1419 set_file(value
, (char *)global_settings
.wps_file
, MAX_FILENAME
);
1421 #if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
1422 else if (!strcasecmp(name
, "rwps")) {
1423 if (wps_data_load(gui_wps
[1].data
, value
, true))
1424 set_file(value
, (char *)global_settings
.rwps_file
, MAX_FILENAME
);
1427 else if (!strcasecmp(name
, "lang")) {
1428 if (!lang_load(value
))
1430 set_file(value
, (char *)global_settings
.lang_file
, MAX_FILENAME
);
1431 talk_init(); /* use voice of same language */
1435 else if (!strcasecmp(name
, "fmr")) {
1436 set_file(value
, global_settings
.fmr_file
, MAX_FILENAME
);
1439 #ifdef HAVE_LCD_BITMAP
1440 else if (!strcasecmp(name
, "font")) {
1441 if (font_load(value
))
1442 set_file(value
, (char *)global_settings
.font_file
, MAX_FILENAME
);
1445 #ifdef HAVE_LCD_COLOR
1446 else if (!strcasecmp(name
, "backdrop")) {
1447 if (load_main_backdrop(value
))
1448 set_file(value
, (char *)global_settings
.backdrop_file
, MAX_FILENAME
);
1451 #ifdef HAVE_LCD_BITMAP
1452 else if (!strcasecmp(name
, "keyboard")) {
1453 if (!load_kbd(value
))
1454 set_file(value
, (char *)global_settings
.kbd_file
, MAX_FILENAME
);
1459 /* check for scalar values, using the two tables */
1460 pos
= load_cfg_table(table
[last_table
], ta_size
[last_table
],
1461 name
, value
, last_pos
);
1462 if (pos
) /* success */
1464 last_pos
= pos
; /* remember as a position hint for next round */
1468 last_table
= 1-last_table
; /* try other table */
1469 last_pos
= 1; /* search from start */
1470 pos
= load_cfg_table(table
[last_table
], ta_size
[last_table
],
1471 name
, value
, last_pos
);
1472 if (pos
) /* success */
1474 last_pos
= pos
; /* remember as a position hint for next round */
1486 /* helper to save content of global_settings into a file,
1487 as described per table */
1488 static void save_cfg_table(const struct bit_entry
* p_table
, int count
, int fd
)
1490 long value
; /* 32 bit content */
1492 const struct bit_entry
* p_run
= p_table
; /* start after the size info */
1493 count
--; /* first is excluded from loop */
1495 for (i
=0; i
<count
; i
++)
1499 if (p_run
->cfg_name
== NULL
)
1500 continue; /* this value is not to be saved */
1502 /* could do a memcpy, but that would be endian-dependent */
1503 switch(p_run
->byte_size
)
1506 if (p_run
->bit_size
& SIGNED
) /* signed? */
1507 value
= ((char*)&global_settings
)[p_run
->settings_offset
];
1509 value
= ((unsigned char*)&global_settings
)[p_run
->settings_offset
];
1512 if (p_run
->bit_size
& SIGNED
) /* signed? */
1513 value
= ((short*)&global_settings
)[p_run
->settings_offset
/2];
1515 value
= ((unsigned short*)&global_settings
)[p_run
->settings_offset
/2];
1518 value
= ((unsigned int*)&global_settings
)[p_run
->settings_offset
/4];
1521 DEBUGF( "illegal size!" );
1525 if (p_run
->cfg_val
== NULL
) /* write as number */
1527 fdprintf(fd
, "%s: %ld\r\n", p_run
->cfg_name
, value
);
1529 #ifdef HAVE_LCD_COLOR
1530 else if (!strcasecmp(p_run
->cfg_val
, "rgb"))
1532 fdprintf(fd
, "%s: %02x%02x%02x\r\n", p_run
->cfg_name
,
1533 (int)RGB_UNPACK_RED(value
),
1534 (int)RGB_UNPACK_GREEN(value
),
1535 (int)RGB_UNPACK_BLUE(value
));
1538 else /* write as item */
1540 const char* p
= p_run
->cfg_val
;
1542 fdprintf(fd
, "%s: ", p_run
->cfg_name
);
1546 char c
= *p
++; /* currently processed char */
1547 if (c
== ',') /* separator */
1549 else if (c
== '\0') /* end of string */
1550 break; /* not found */
1551 else if (value
== 0) /* the right place */
1552 write(fd
, &c
, 1); /* char by char, this is lame, OK */
1555 fdprintf(fd
, "\r\n");
1556 if (p_run
->cfg_val
!= off_on
) /* explaination for non-bool */
1557 fdprintf(fd
, "# (possible values: %s)\r\n", p_run
->cfg_val
);
1563 bool settings_save_config(void)
1566 char filename
[MAX_PATH
];
1568 create_numbered_filename(filename
, ROCKBOX_DIR
, "config", ".cfg", 2);
1570 /* allow user to modify filename */
1572 if (!kbd_input(filename
, sizeof filename
)) {
1573 fd
= creat(filename
,0);
1575 gui_syncsplash(HZ
, true, str(LANG_FAILED
));
1580 gui_syncsplash(HZ
, true, str(LANG_MENU_SETTING_CANCEL
));
1585 fdprintf(fd
, "# .cfg file created by rockbox %s - "
1586 "http://www.rockbox.org\r\n#\r\n#\r\n# wps / rwps / language"
1587 " / font / fmpreset / backdrop \r\n#\r\n", appsversion
);
1589 if (global_settings
.wps_file
[0] != 0)
1590 fdprintf(fd
, "wps: %s/%s.wps\r\n", WPS_DIR
,
1591 global_settings
.wps_file
);
1593 #ifdef HAVE_REMOTE_LCD
1594 if (global_settings
.rwps_file
[0] != 0)
1595 fdprintf(fd
, "rwps: %s/%s.rwps\r\n", WPS_DIR
,
1596 global_settings
.rwps_file
);
1599 if (global_settings
.lang_file
[0] != 0)
1600 fdprintf(fd
, "lang: %s/%s.lng\r\n", ROCKBOX_DIR LANG_DIR
,
1601 global_settings
.lang_file
);
1603 #ifdef HAVE_LCD_BITMAP
1604 if (global_settings
.font_file
[0] != 0)
1605 fdprintf(fd
, "font: %s/%s.fnt\r\n", ROCKBOX_DIR FONT_DIR
,
1606 global_settings
.font_file
);
1609 #ifdef HAVE_LCD_COLOR
1610 if (global_settings
.backdrop_file
[0] != 0)
1611 fdprintf(fd
, "backdrop: %s/%s.bmp\r\n", BACKDROP_DIR
,
1612 global_settings
.backdrop_file
);
1616 if (global_settings
.fmr_file
[0] != 0)
1617 fdprintf(fd
, "fmr: %s/%s.fmr\r\n", FMPRESET_PATH
,
1618 global_settings
.fmr_file
);
1621 #ifdef HAVE_LCD_BITMAP
1622 if (global_settings
.kbd_file
[0] != 0)
1623 fdprintf(fd
, "keyboard: %s/%s.kbd\r\n", ROCKBOX_DIR
,
1624 global_settings
.kbd_file
);
1627 /* here's the action: write values to file, specified via table */
1628 save_cfg_table(rtc_bits
, sizeof(rtc_bits
)/sizeof(rtc_bits
[0]), fd
);
1629 save_cfg_table(hd_bits
, sizeof(hd_bits
)/sizeof(hd_bits
[0]), fd
);
1633 gui_syncsplash(HZ
, true, str(LANG_SETTINGS_SAVED
));
1638 /* helper to load defaults from table into global_settings members */
1639 static void default_table(const struct bit_entry
* p_table
, int count
)
1643 for (i
=1; i
<count
; i
++) /* exclude the first, the size placeholder */
1645 /* could do a memcpy, but that would be endian-dependent */
1646 switch(p_table
[i
].byte_size
)
1649 ((unsigned char*)&global_settings
)[p_table
[i
].settings_offset
] =
1650 (unsigned char)p_table
[i
].default_val
;
1653 ((unsigned short*)&global_settings
)[p_table
[i
].settings_offset
/2] =
1654 (unsigned short)p_table
[i
].default_val
;
1657 ((unsigned int*)&global_settings
)[p_table
[i
].settings_offset
/4] =
1658 (unsigned int)p_table
[i
].default_val
;
1661 DEBUGF( "illegal size!" );
1669 * reset all settings to their default value
1671 void settings_reset(void) {
1673 DEBUGF( "settings_reset()\n" );
1675 /* read defaults from table(s) into global_settings */
1676 default_table(rtc_bits
, sizeof(rtc_bits
)/sizeof(rtc_bits
[0]));
1677 default_table(hd_bits
, sizeof(hd_bits
)/sizeof(hd_bits
[0]));
1679 /* do some special cases not covered by table */
1680 global_settings
.volume
= sound_default(SOUND_VOLUME
);
1681 global_settings
.balance
= sound_default(SOUND_BALANCE
);
1682 global_settings
.bass
= sound_default(SOUND_BASS
);
1683 global_settings
.treble
= sound_default(SOUND_TREBLE
);
1684 global_settings
.channel_config
= sound_default(SOUND_CHANNELS
);
1685 global_settings
.stereo_width
= sound_default(SOUND_STEREO_WIDTH
);
1686 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
1687 global_settings
.loudness
= sound_default(SOUND_LOUDNESS
);
1688 global_settings
.avc
= sound_default(SOUND_AVC
);
1689 global_settings
.mdb_strength
= sound_default(SOUND_MDB_STRENGTH
);
1690 global_settings
.mdb_harmonics
= sound_default(SOUND_MDB_HARMONICS
);
1691 global_settings
.mdb_center
= sound_default(SOUND_MDB_CENTER
);
1692 global_settings
.mdb_shape
= sound_default(SOUND_MDB_SHAPE
);
1693 global_settings
.mdb_enable
= sound_default(SOUND_MDB_ENABLE
);
1694 global_settings
.superbass
= sound_default(SOUND_SUPERBASS
);
1696 global_settings
.contrast
= lcd_default_contrast();
1699 global_settings
.fmr_file
[0] = '\0';
1701 global_settings
.wps_file
[0] = '\0';
1702 #ifdef HAVE_REMOTE_LCD
1703 global_settings
.rwps_file
[0] = '\0';
1705 global_settings
.font_file
[0] = '\0';
1706 global_settings
.lang_file
[0] = '\0';
1707 #ifdef HAVE_LCD_COLOR
1708 global_settings
.backdrop_file
[0] = '\0';
1710 global_settings
.fg_color
= LCD_DEFAULT_FG
;
1711 global_settings
.bg_color
= LCD_DEFAULT_BG
;
1713 #ifdef HAVE_LCD_BITMAP
1714 global_settings
.kbd_file
[0] = '\0';
1719 bool set_bool(const char* string
, bool* variable
)
1721 return set_bool_options(string
, variable
,
1722 (char *)STR(LANG_SET_BOOL_YES
),
1723 (char *)STR(LANG_SET_BOOL_NO
),
1727 /* wrapper to convert from int param to bool param in set_option */
1728 static void (*boolfunction
)(bool);
1729 void bool_funcwrapper(int value
)
1734 boolfunction(false);
1737 bool set_bool_options(const char* string
, bool* variable
,
1738 const char* yes_str
, int yes_voice
,
1739 const char* no_str
, int no_voice
,
1740 void (*function
)(bool))
1742 struct opt_items names
[] = {
1743 {(unsigned char *)no_str
, no_voice
},
1744 {(unsigned char *)yes_str
, yes_voice
}
1748 boolfunction
= function
;
1749 result
= set_option(string
, variable
, BOOL
, names
, 2,
1750 function
? bool_funcwrapper
: NULL
);
1754 void talk_unit(int unit
, int value
)
1756 if (global_settings
.talk_menu
)
1758 if (unit
< UNIT_LAST
)
1759 { /* use the available unit definition */
1760 talk_value(value
, unit
, false);
1763 { /* say the number, followed by an arbitrary voice ID */
1764 talk_number(value
, false);
1765 talk_id(unit
, true);
1770 bool set_int(const unsigned char* string
,
1774 void (*function
)(int),
1778 void (*formatter
)(char*, int, int, const char*) )
1781 int oldvalue
=*variable
;
1782 struct gui_select select
;
1783 gui_select_init_numeric(&select
, (char *)string
, *variable
, min
, max
, step
, unit
,
1785 gui_syncselect_draw(&select
);
1786 talk_unit(voice_unit
, *variable
);
1787 while (!select
.validated
)
1789 button
= button_get_w_tmo(HZ
/2);
1790 if(gui_syncselect_do_button(&select
, button
))
1792 *variable
=select
.options
.option
;
1793 gui_syncselect_draw(&select
);
1794 talk_unit(voice_unit
, *variable
);
1796 function(*variable
);
1798 gui_syncstatusbar_draw(&statusbars
, false);
1803 function(*variable
);
1806 if(default_event_handler(button
) == SYS_USB_CONNECTED
)
1812 /* NOTE: the 'type' parameter specifies the actual type of the variable
1813 that 'variable' points to. not the value within. Only variables with
1814 type 'bool' should use parameter BOOL.
1816 The type separation is necessary since int and bool are fundamentally
1817 different and bit-incompatible types and can not share the same access
1820 #define set_type_fromint(type, dest, value) \
1822 *(int *)dest=value; \
1824 *(bool *)dest=value?true:false
1826 #define type_fromvoidptr(type, value) \
1828 (int)(*(int*)(value)) \
1830 (bool)(*(bool*)(value))
1832 #define get_int_fromtype(type, var) \
1833 (type == INT)?*(int *)var:(*(bool *)var?1:0)
1835 bool set_option(const char* string
, void* variable
, enum optiontype type
,
1836 const struct opt_items
* options
, int numoptions
, void (*function
)(int))
1840 /* oldvalue=*variable; */
1841 oldvalue
=get_int_fromtype(type
, variable
);
1842 struct gui_select select
;
1843 gui_select_init_items(&select
, string
, oldvalue
, options
, numoptions
);
1844 gui_syncselect_draw(&select
);
1845 if (global_settings
.talk_menu
)
1846 talk_id(options
[select
.options
.option
].voice_id
, true);
1848 while ( !select
.validated
)
1850 gui_syncstatusbar_draw(&statusbars
, true);
1851 button
= button_get_w_tmo(HZ
/2);
1852 select
.options
.limit_loop
= false;
1853 if(gui_syncselect_do_button(&select
, button
))
1855 /* *variable = gui_select_get_selected(&select) */
1856 set_type_fromint(type
, variable
, select
.options
.option
);
1857 gui_syncselect_draw(&select
);
1858 if (global_settings
.talk_menu
)
1859 talk_id(options
[select
.options
.option
].voice_id
, false);
1861 function(type_fromvoidptr(type
, variable
));
1863 gui_syncstatusbar_draw(&statusbars
, false);
1866 /* *variable=oldvalue; */
1867 set_type_fromint(type
, variable
, oldvalue
);
1869 function(type_fromvoidptr(type
, variable
));
1872 if(default_event_handler(button
) == SYS_USB_CONNECTED
)
1878 #ifdef HAVE_RECORDING
1879 /* This array holds the record timer interval lengths, in seconds */
1880 static const unsigned long rec_timer_seconds
[] =
1882 0, /* 0 means OFF */
1890 2*60*60, /* 02:00 */
1891 4*60*60, /* 04:00 */
1892 6*60*60, /* 06:00 */
1893 8*60*60, /* 08:00 */
1894 10L*60*60, /* 10:00 */
1895 12L*60*60, /* 12:00 */
1896 18L*60*60, /* 18:00 */
1897 24L*60*60 /* 24:00 */
1900 unsigned int rec_timesplit_seconds(void)
1902 return rec_timer_seconds
[global_settings
.rec_timesplit
];
1906 * Time strings used for the trigger durations.
1907 * Keep synchronous to trigger_times in settings_apply_trigger
1909 const char * const trig_durations
[TRIG_DURATION_COUNT
] =
1911 "0s", "1s", "2s", "5s",
1912 "10s", "15s", "20s", "25s", "30s",
1913 "1min", "2min", "5min", "10min"
1916 void settings_apply_trigger(void)
1918 /* Keep synchronous to trig_durations and trig_durations_conf*/
1919 static const long trigger_times
[TRIG_DURATION_COUNT
] = {
1921 10*HZ
, 15*HZ
, 20*HZ
, 25*HZ
, 30*HZ
,
1922 60*HZ
, 2*60*HZ
, 5*60*HZ
, 10*60*HZ
1925 peak_meter_define_trigger(
1926 global_settings
.rec_start_thres
,
1927 trigger_times
[global_settings
.rec_start_duration
],
1928 MIN(trigger_times
[global_settings
.rec_start_duration
] / 2, 2*HZ
),
1929 global_settings
.rec_stop_thres
,
1930 trigger_times
[global_settings
.rec_stop_postrec
],
1931 trigger_times
[global_settings
.rec_stop_gap
]