Iriver: Moved the handling of the UDA1380 split gain (analog preamp + decimator gain...
[Rockbox.git] / apps / settings.c
blob0031130f9a08fb2ba51af7094fc832a7ddebf95b
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 "settings.h"
28 #include "disk.h"
29 #include "panic.h"
30 #include "debug.h"
31 #include "button.h"
32 #include "usb.h"
33 #include "backlight.h"
34 #include "lcd.h"
35 #include "audio.h"
36 #include "mp3_playback.h"
37 #include "mpeg.h"
38 #include "talk.h"
39 #include "string.h"
40 #include "ata.h"
41 #include "fat.h"
42 #include "power.h"
43 #include "backlight.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 "select.h"
73 #include "statusbar.h"
74 #include "splash.h"
75 #include "list.h"
76 #ifdef HAVE_LCD_COLOR
77 #include "backdrop.h"
78 #endif
80 #ifdef CONFIG_TUNER
81 #include "radio.h"
82 #endif
84 #if CONFIG_CODEC == MAS3507D
85 void dac_line_in(bool enable);
86 #endif
87 struct user_settings global_settings;
88 #ifdef HAVE_RECORDING
89 const char rec_base_directory[] = REC_BASE_DIR;
90 #endif
91 #if CONFIG_CODEC == SWCODEC
92 #include "pcmbuf.h"
93 #include "pcm_playback.h"
94 #include "dsp.h"
95 #endif
97 #define CONFIG_BLOCK_VERSION 43
98 #define CONFIG_BLOCK_SIZE 512
99 #define RTC_BLOCK_SIZE 44
101 #ifdef HAVE_LCD_BITMAP
102 #define MAX_LINES 10
103 #else
104 #define MAX_LINES 2
105 #endif
107 #ifdef HAVE_REMOTE_LCD
108 #include "lcd-remote.h"
109 #endif
111 long lasttime = 0;
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) */
118 struct bit_entry
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 */
126 /* default value */
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 */
131 const char* cfg_val;
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.
139 offset abs
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";
186 #endif
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";
193 #endif
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";
198 #endif
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 */
208 /* sound */
209 #if CONFIG_CODEC == MAS3507D
210 {8 | SIGNED, S_O(volume), -18, "volume", NULL }, /* -78...+18 */
211 #else
212 {8 | SIGNED, S_O(volume), -25, "volume", NULL }, /* -100...+12 / -84...0 */
213 #endif
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 */
225 #endif
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 },
230 #endif
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},
234 /* playback */
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" },
242 /* LCD */
243 {6, S_O(contrast), 40, "contrast", NULL },
244 #ifdef CONFIG_BACKLIGHT
245 {5, S_O(backlight_timeout), 5, "backlight timeout", backlight_times_conf },
246 #ifdef HAVE_CHARGING
247 {5, S_O(backlight_timeout_plugged), 11, "backlight timeout plugged",
248 backlight_times_conf },
249 #endif
250 #endif /* CONFIG_BACKLIGHT */
251 #ifdef HAVE_LCD_BITMAP
252 {1, S_O(invert), false, "invert", off_on },
253 {1, S_O(flip_display), false, "flip display", off_on },
254 /* display */
255 {1, S_O(invert_cursor), true, "invert cursor", off_on },
256 {1, S_O(statusbar), true, "statusbar", off_on },
257 {1, S_O(scrollbar), true, "scrollbar", off_on },
258 #if CONFIG_KEYPAD == RECORDER_PAD
259 {1, S_O(buttonbar), true, "buttonbar", off_on },
260 #endif
261 {1, S_O(volume_type), 0, "volume display", graphic_numeric },
262 {1, S_O(battery_display), 0, "battery display", graphic_numeric },
263 {1, S_O(timeformat), 0, "time format", "24hour,12hour" },
264 #endif /* HAVE_LCD_BITMAP */
265 {1, S_O(show_icons), true, "show icons", off_on },
266 /* system */
267 {4, S_O(poweroff), 10,
268 "idle poweroff", "off,1,2,3,4,5,6,7,8,9,10,15,30,45,60" },
269 {18, S_O(runtime), 0, NULL, NULL },
270 {18, S_O(topruntime), 0, NULL, NULL },
271 {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 */
275 /* battery */
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 */
279 #ifdef HAVE_CHARGING
280 {1, S_O(car_adapter_mode), false, "car adapter mode", off_on },
281 #endif
282 /* tuner */
283 #ifdef CONFIG_TUNER
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 */
286 #endif
288 #if BATTERY_TYPES_COUNT > 1
289 {1, S_O(battery_type), 0, "battery type", "alkaline,nimh" },
290 #endif
292 #ifdef HAVE_REMOTE_LCD
293 /* 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 },
299 #ifdef HAVE_CHARGING
300 {5, S_O(remote_backlight_timeout_plugged), 11,
301 "remote backlight timeout plugged", backlight_times_conf },
302 #endif
303 #ifdef HAVE_REMOTE_LCD_TICKING
304 {1, S_O(remote_reduce_ticking), false, "remote reduce ticking", off_on },
305 #endif
306 #endif
308 #ifdef CONFIG_BACKLIGHT
309 {1, S_O(bl_filter_first_keypress),
310 #ifdef HAVE_LCD_COLOR
311 true,
312 #else
313 false,
314 #endif
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 },
319 #endif
321 #endif
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 */
341 /* more display */
342 #ifdef CONFIG_BACKLIGHT
343 {1, S_O(caption_backlight), false, "caption backlight", off_on },
344 #endif
345 #ifdef HAVE_REMOTE_LCD
346 {1, S_O(remote_caption_backlight), false,
347 "remote caption backlight", off_on },
348 #endif
349 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
350 {4, S_O(brightness), 9, "brightness", NULL },
351 #endif
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"},
357 #endif
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 },
364 #if LCD_WIDTH > 255
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 },
370 #else
371 {7, S_O(scroll_step), 6, "scroll step", NULL },
372 {7, S_O(screen_scroll_step), 16, "screen scroll step", NULL },
373 #endif
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 */
378 #endif
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"},
384 #endif
386 /* more playback */
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" },
395 #else
396 {3, S_O(buffer_margin), 0, "antiskip", NULL },
397 #endif
398 /* disk */
399 #ifndef HAVE_MMC
400 #ifdef HAVE_ATA_POWER_OFF
401 {1, S_O(disk_poweroff), false, "disk poweroff", off_on },
402 #endif
403 {8, S_O(disk_spindown), 5, "disk spindown", NULL },
404 #endif /* HAVE_MMC */
406 /* browser */
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 },
411 /* playlist */
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 },
419 /* bookmarks */
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
427 /* peak meter */
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 */
436 #endif
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},
443 #endif
444 #if CONFIG_CODEC == MAS3507D
445 {1, S_O(line_in), false, "line in", off_on },
446 #endif
447 /* voice */
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
457 /* 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" },
462 #ifdef HAVE_SPDIF_IN
463 {2, S_O(rec_source), 0 /* 0=mic */, "rec source", "mic,line,spdif" },
464 #else
465 {1, S_O(rec_source), 0 /* 0=mic */, "rec source", "mic,line" },
466 #endif
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" },
472 #endif
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" },
487 #endif
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},
500 #endif
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 },
524 /* equalizer */
525 {1, S_O(eq_enabled), false, "eq enabled", off_on },
526 {8, S_O(eq_precut), 0, "eq precut", NULL },
527 /* 0..32768 Hz */
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 },
545 #endif
547 #ifdef HAVE_DIRCACHE
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 },
551 #endif
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;
574 uint32_t result;
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);
583 return result;
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;
596 uint32_t mask;
598 mask = 0xFFFFFFFF >> (32 - size);
599 value &= mask;
600 mask <<= bit_index;
602 if (bit_index + size > 32)
603 p[long_index+1] =
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)
619 { int ok = 1;
620 int i;
621 int red, green, blue;
623 if (strlen(hex) == 6) {
624 for (i=0; i < 6; i++ ) {
625 if (!isxdigit(hex[i])) {
626 ok=0;
627 break;
631 if (ok) {
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);
639 return 0;
641 #endif
644 * Calculates the checksum for the config block and returns it
647 static unsigned short calculate_config_checksum(const unsigned char* buf)
649 unsigned int i;
650 unsigned char cksum[2];
651 cksum[0] = cksum[1] = 0;
653 for (i=0; i < RTC_BLOCK_SIZE - 2; i+=2 ) {
654 cksum[0] ^= buf[i];
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);
670 /* insert header */
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;
683 #ifdef HAVE_RTC_RAM
684 unsigned int i;
685 #endif
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;
692 #ifdef HAVE_RTC_RAM
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]);
698 if (r) {
699 DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n",
700 14+i, r );
701 return r;
705 #endif
707 if (config_sector != 0)
708 ata_delayed_write( config_sector, config_block);
709 else
710 return -1;
712 return 0;
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" );
741 correct = true;
746 #ifdef HAVE_RTC_RAM
747 if(!correct)
749 /* If the disk sector was incorrect, reinit the buffer */
750 memset(config_block, 0, CONFIG_BLOCK_SIZE);
753 if (which & SETTINGS_RTC)
755 unsigned int i;
756 unsigned char rtc_block[RTC_BLOCK_SIZE];
758 /* read rtc block */
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);
773 correct = true;
776 #endif
778 if ( !correct ) {
779 /* if checksum is not valid, clear the config buffer */
780 DEBUGF( "load_config_buffer: header & checksum test failed\n" );
781 init_config_buffer();
782 return -1;
785 return 0;
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 */
795 int i;
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++)
802 p_run++;
803 /* could do a memcpy, but that would be endian-dependent */
804 switch(p_run->byte_size)
806 case 1:
807 value = ((uint8_t *)&global_settings)[p_run->settings_offset];
808 break;
809 case 2:
810 value = ((uint16_t *)&global_settings)[p_run->settings_offset/2];
811 break;
812 case 4:
813 value = ((uint32_t *)&global_settings)[p_run->settings_offset/4];
814 break;
815 default:
816 DEBUGF( "save_bit_table: illegal size!\n" );
817 continue;
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)
832 #ifdef SIMULATOR
833 config_sector = 61;
834 #else
835 int i;
836 long partition_start;
837 long sector = 0;
839 if (fat_startsector(IF_MV(0)) != 0) /* There is a partition table */
841 sector = 61;
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;
848 if (sector < 0)
849 sector = 0;
852 config_sector = sector;
853 #endif
857 * persist all runtime user settings to disk or RTC RAM
859 int settings_save( void )
861 int i;
864 int elapsed_secs;
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);
878 i = 0xb8;
879 strncpy((char *)&config_block[i], (char *)global_settings.wps_file,
880 MAX_FILENAME);
881 i+= MAX_FILENAME;
882 strncpy((char *)&config_block[i], (char *)global_settings.lang_file,
883 MAX_FILENAME);
884 i+= MAX_FILENAME;
885 strncpy((char *)&config_block[i], (char *)global_settings.font_file,
886 MAX_FILENAME);
887 i+= MAX_FILENAME;
888 #ifdef HAVE_REMOTE_LCD
889 strncpy((char *)&config_block[i], (char *)global_settings.rwps_file,
890 MAX_FILENAME);
891 i+= MAX_FILENAME;
892 #endif
894 #ifdef CONFIG_TUNER
895 strncpy((char *)&config_block[i], (char *)global_settings.fmr_file,
896 MAX_FILENAME);
897 i+= MAX_FILENAME;
898 #endif
900 #ifdef HAVE_LCD_COLOR
901 strncpy((char *)&config_block[i], (char *)global_settings.backdrop_file,
902 MAX_FILENAME);
903 i+= MAX_FILENAME;
904 #endif
905 #ifdef HAVE_LCD_BITMAP
906 strncpy((char *)&config_block[i], (char *)global_settings.kbd_file,
907 MAX_FILENAME);
908 i+= MAX_FILENAME;
909 #endif
911 if(save_config_buffer())
913 lcd_clear_display();
914 #ifdef HAVE_REMOTE_LCD
915 lcd_remote_clear_display();
916 #endif
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));
920 #else
921 lcd_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER));
922 lcd_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER));
923 lcd_update();
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));
927 lcd_remote_update();
928 #endif
929 #endif
930 sleep(HZ*2);
931 return -1;
933 return 0;
936 #ifdef HAVE_LCD_BITMAP
938 * Applies the range infos stored in global_settings to
939 * the peak meter.
941 void settings_apply_pm_range(void)
943 int pm_min, pm_max;
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);
953 else
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);
974 #else
975 sound_set(SOUND_CHANNELS, global_settings.channel_config);
976 sound_set(SOUND_STEREO_WIDTH, global_settings.stereo_width);
977 #endif
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);
987 #endif
990 void settings_apply(void)
992 char buf[64];
993 #if CONFIG_CODEC == SWCODEC
994 int i;
995 #endif
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);
1012 #endif
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);
1016 #endif
1017 #endif
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);
1022 #endif
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);
1026 #endif
1027 #endif
1028 #ifdef HAVE_BACKLIGHT_BRIGHTNESS
1029 backlight_set_brightness(global_settings.brightness);
1030 #endif
1031 ata_spindown(global_settings.disk_spindown);
1032 #if (CONFIG_CODEC == MAS3507D) && !defined(SIMULATOR)
1033 dac_line_in(global_settings.line_in);
1034 #endif
1035 mpeg_id3_options(global_settings.id3_v1_first);
1036 #ifdef HAVE_ATA_POWER_OFF
1037 ata_poweroff(global_settings.disk_poweroff);
1038 #endif
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);
1045 #endif
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);
1056 #endif
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);
1064 else
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);
1074 } else {
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);
1079 #endif
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);
1088 else
1089 wps_data_init(gui_wps[1].data);
1090 #endif
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);
1097 font_load(buf);
1099 else
1100 font_reset();
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);
1106 load_kbd(buf);
1108 else
1109 load_kbd(NULL);
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);
1114 #else
1115 lcd_jump_scroll(global_settings.jump_scroll);
1116 lcd_jump_scroll_delay(global_settings.jump_scroll_delay * (HZ/10));
1117 #endif
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);
1125 lang_load(buf);
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);
1147 #endif
1149 #ifdef HAVE_SPDIF_POWER
1150 spdif_power_enable(global_settings.spdif_enable);
1151 #endif
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);
1157 #endif
1158 #endif
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 */
1167 int i;
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++)
1176 int size;
1177 p_run++;
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);
1184 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 */
1189 value |= mask;
1192 /* could do a memcpy, but that would be endian-dependent */
1193 switch(p_run->byte_size)
1195 case 1:
1196 ((uint8_t *)&global_settings)[p_run->settings_offset] =
1197 (unsigned char)value;
1198 break;
1199 case 2:
1200 ((uint16_t *)&global_settings)[p_run->settings_offset/2] =
1201 (unsigned short)value;
1202 break;
1203 case 4:
1204 ((uint32_t *)&global_settings)[p_run->settings_offset/4] =
1205 (unsigned int)value;
1206 break;
1207 default:
1208 DEBUGF( "load_bit_table: illegal size!\n" );
1209 continue;
1216 * load settings from disk or RTC RAM
1218 void settings_load(int which)
1220 int i;
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]),
1235 RTC_BLOCK_SIZE*8);
1238 if ( global_settings.contrast < MIN_CONTRAST_SETTING )
1239 global_settings.contrast = lcd_default_contrast();
1241 i = 0xb8;
1242 strncpy((char *)global_settings.wps_file, (char *)&config_block[i],
1243 MAX_FILENAME);
1244 i+= MAX_FILENAME;
1245 strncpy((char *)global_settings.lang_file, (char *)&config_block[i],
1246 MAX_FILENAME);
1247 i+= MAX_FILENAME;
1248 strncpy((char *)global_settings.font_file, (char *)&config_block[i],
1249 MAX_FILENAME);
1250 i+= MAX_FILENAME;
1251 #ifdef HAVE_REMOTE_LCD
1252 strncpy((char *)global_settings.rwps_file, (char *)&config_block[i],
1253 MAX_FILENAME);
1254 i+= MAX_FILENAME;
1255 #endif
1257 #ifdef CONFIG_TUNER
1258 strncpy((char *)global_settings.fmr_file, (char *)&config_block[i],
1259 MAX_FILENAME);
1260 i+= MAX_FILENAME;
1261 #endif
1263 #ifdef HAVE_LCD_COLOR
1264 strncpy((char *)global_settings.backdrop_file, (char *)&config_block[i],
1265 MAX_FILENAME);
1266 i+= MAX_FILENAME;
1267 #endif
1268 #ifdef HAVE_LCD_BITMAP
1269 strncpy((char *)global_settings.kbd_file, (char *)&config_block[i],
1270 MAX_FILENAME);
1271 i+= MAX_FILENAME;
1272 #endif
1276 void set_file(char* filename, char* setting, int maxlen)
1278 char* fptr = strrchr(filename,'/');
1279 int len;
1280 int extlen = 0;
1281 char* ptr;
1283 if (!fptr)
1284 return;
1286 *fptr = 0;
1287 fptr++;
1289 len = strlen(fptr);
1290 ptr = fptr + len;
1291 while ((*ptr != '.') && (ptr != fptr)) {
1292 extlen++;
1293 ptr--;
1295 if(ptr == fptr) extlen = 0;
1297 if (strncasecmp(ROCKBOX_DIR, filename ,strlen(ROCKBOX_DIR)) ||
1298 (len-extlen > maxlen))
1299 return;
1301 strncpy(setting, fptr, len-extlen);
1302 setting[len-extlen]=0;
1304 settings_save();
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 */
1316 int i = hint;
1320 if (p_table[i].cfg_name != NULL && !strcasecmp(name, p_table[i].cfg_name))
1321 { /* found */
1322 int val = 0;
1323 if (p_table[i].cfg_val == NULL)
1324 { /* numerical value, just convert the string */
1325 val = atoi(value);
1327 #if HAVE_LCD_COLOR
1328 else if (!strncasecmp(p_table[i].cfg_val,"rgb",4))
1330 val = hex_to_rgb(value);
1332 #endif
1333 else
1334 { /* set of string values, find the index */
1335 const char* item;
1336 const char* run;
1337 int len = strlen(value);
1339 item = run = p_table[i].cfg_val;
1341 while(1)
1343 /* count the length of the field */
1344 while (*run != ',' && *run != '\0')
1345 run++;
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 ',' */
1355 item = run;
1359 /* could do a memcpy, but that would be endian-dependent */
1360 switch(p_table[i].byte_size)
1362 case 1:
1363 ((unsigned char*)&global_settings)[p_table[i].settings_offset] =
1364 (unsigned char)val;
1365 break;
1366 case 2:
1367 ((unsigned short*)&global_settings)[p_table[i].settings_offset/2] =
1368 (unsigned short)val;
1369 break;
1370 case 4:
1371 ((unsigned int*)&global_settings)[p_table[i].settings_offset/4] =
1372 (unsigned int)val;
1373 break;
1374 default:
1375 DEBUGF( "illegal size!" );
1376 continue;
1379 return i; /* return the position */
1382 i++;
1383 if (i==count)
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)
1393 int fd;
1394 char line[128];
1396 fd = open(file, O_RDONLY);
1397 if (fd < 0)
1398 return false;
1400 while (read_line(fd, line, sizeof line) > 0)
1402 char* name;
1403 char* value;
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))
1414 continue;
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);
1426 #endif
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 */
1434 #ifdef CONFIG_TUNER
1435 else if (!strcasecmp(name, "fmr")) {
1436 set_file(value, global_settings.fmr_file, MAX_FILENAME);
1438 #endif
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);
1444 #endif
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);
1450 #endif
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);
1456 #endif
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 */
1465 continue;
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 */
1475 continue;
1479 close(fd);
1480 settings_apply();
1481 settings_save();
1482 return true;
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 */
1491 int i;
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++)
1497 p_run++;
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)
1505 case 1:
1506 if (p_run->bit_size & SIGNED) /* signed? */
1507 value = ((char*)&global_settings)[p_run->settings_offset];
1508 else
1509 value = ((unsigned char*)&global_settings)[p_run->settings_offset];
1510 break;
1511 case 2:
1512 if (p_run->bit_size & SIGNED) /* signed? */
1513 value = ((short*)&global_settings)[p_run->settings_offset/2];
1514 else
1515 value = ((unsigned short*)&global_settings)[p_run->settings_offset/2];
1516 break;
1517 case 4:
1518 value = ((unsigned int*)&global_settings)[p_run->settings_offset/4];
1519 break;
1520 default:
1521 DEBUGF( "illegal size!" );
1522 continue;
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));
1537 #endif
1538 else /* write as item */
1540 const char* p = p_run->cfg_val;
1542 fdprintf(fd, "%s: ", p_run->cfg_name);
1544 while(value >= 0)
1546 char c = *p++; /* currently processed char */
1547 if (c == ',') /* separator */
1548 value--;
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)
1565 int fd;
1566 char filename[MAX_PATH];
1568 create_numbered_filename(filename, ROCKBOX_DIR, "config", ".cfg", 2);
1570 /* allow user to modify filename */
1571 while (true) {
1572 if (!kbd_input(filename, sizeof filename)) {
1573 fd = creat(filename,0);
1574 if (fd < 0)
1575 gui_syncsplash(HZ, true, str(LANG_FAILED));
1576 else
1577 break;
1579 else {
1580 gui_syncsplash(HZ, true, str(LANG_MENU_SETTING_CANCEL));
1581 return false;
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);
1597 #endif
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);
1607 #endif
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);
1613 #endif
1615 #ifdef CONFIG_TUNER
1616 if (global_settings.fmr_file[0] != 0)
1617 fdprintf(fd, "fmr: %s/%s.fmr\r\n", FMPRESET_PATH,
1618 global_settings.fmr_file);
1619 #endif
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);
1625 #endif
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);
1631 close(fd);
1633 gui_syncsplash(HZ, true, str(LANG_SETTINGS_SAVED));
1634 return true;
1638 /* helper to load defaults from table into global_settings members */
1639 static void default_table(const struct bit_entry* p_table, int count)
1641 int i;
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)
1648 case 1:
1649 ((unsigned char*)&global_settings)[p_table[i].settings_offset] =
1650 (unsigned char)p_table[i].default_val;
1651 break;
1652 case 2:
1653 ((unsigned short*)&global_settings)[p_table[i].settings_offset/2] =
1654 (unsigned short)p_table[i].default_val;
1655 break;
1656 case 4:
1657 ((unsigned int*)&global_settings)[p_table[i].settings_offset/4] =
1658 (unsigned int)p_table[i].default_val;
1659 break;
1660 default:
1661 DEBUGF( "illegal size!" );
1662 continue;
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);
1695 #endif
1696 global_settings.contrast = lcd_default_contrast();
1698 #ifdef CONFIG_TUNER
1699 global_settings.fmr_file[0] = '\0';
1700 #endif
1701 global_settings.wps_file[0] = '\0';
1702 #ifdef HAVE_REMOTE_LCD
1703 global_settings.rwps_file[0] = '\0';
1704 #endif
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;
1712 #endif
1713 #ifdef HAVE_LCD_BITMAP
1714 global_settings.kbd_file[0] = '\0';
1715 #endif
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),
1724 NULL);
1727 /* wrapper to convert from int param to bool param in set_option */
1728 static void (*boolfunction)(bool);
1729 void bool_funcwrapper(int value)
1731 if (value)
1732 boolfunction(true);
1733 else
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}
1746 bool result;
1748 boolfunction = function;
1749 result = set_option(string, variable, BOOL, names, 2,
1750 function ? bool_funcwrapper : NULL);
1751 return result;
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);
1762 else
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,
1771 const char* unit,
1772 int voice_unit,
1773 int* variable,
1774 void (*function)(int),
1775 int step,
1776 int min,
1777 int max,
1778 void (*formatter)(char*, int, int, const char*) )
1780 int button;
1781 int oldvalue=*variable;
1782 struct gui_select select;
1783 gui_select_init_numeric(&select, (char *)string, *variable, min, max, step, unit,
1784 formatter);
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);
1795 if ( function )
1796 function(*variable);
1798 gui_syncstatusbar_draw(&statusbars, false);
1799 if(select.canceled)
1801 *variable=oldvalue;
1802 if ( function )
1803 function(*variable);
1804 return false;
1806 if(default_event_handler(button) == SYS_USB_CONNECTED)
1807 return true;
1809 return false;
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
1818 code. */
1820 #define set_type_fromint(type, dest, value) \
1821 if (type == INT) \
1822 *(int *)dest=value; \
1823 else \
1824 *(bool *)dest=value?true:false
1826 #define type_fromvoidptr(type, value) \
1827 (type == INT)? \
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))
1838 int button;
1839 int oldvalue;
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);
1860 if ( function )
1861 function(type_fromvoidptr(type, variable));
1863 gui_syncstatusbar_draw(&statusbars, false);
1864 if(select.canceled)
1866 /* *variable=oldvalue; */
1867 set_type_fromint(type, variable, oldvalue);
1868 if ( function )
1869 function(type_fromvoidptr(type, variable));
1870 return false;
1872 if(default_event_handler(button) == SYS_USB_CONNECTED)
1873 return true;
1875 return false;
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 */
1883 5*60, /* 00:05 */
1884 10*60, /* 00:10 */
1885 15*60, /* 00:15 */
1886 30*60, /* 00:30 */
1887 60*60, /* 01:00 */
1888 74*60, /* 74:00 */
1889 80*60, /* 80:00 */
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] = {
1920 0, HZ, 2*HZ, 5*HZ,
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]
1934 #endif