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 ****************************************************************************/
31 #include "backlight.h"
34 #include "mp3_playback.h"
40 #include "backlight.h"
41 #include "powermgmt.h"
50 #include "timefuncs.h"
51 #ifdef HAVE_LCD_BITMAP
54 #include "peakmeter.h"
59 #include "wps-display.h"
60 #include "powermgmt.h"
66 #if CONFIG_HWCODEC == MAS3507D
67 void dac_line_in(bool enable
);
69 struct user_settings global_settings
;
70 const char rec_base_directory
[] = REC_BASE_DIR
;
74 #define CONFIG_BLOCK_VERSION 19
75 #define CONFIG_BLOCK_SIZE 512
76 #define RTC_BLOCK_SIZE 44
78 #ifdef HAVE_LCD_BITMAP
85 static int config_sector
= 0; /* mark uninitialized */
86 static unsigned char config_block
[CONFIG_BLOCK_SIZE
];
89 /* descriptor for a configuration value */
90 /* (watch the struct packing and member sizes to keep this small) */
93 /* how many bits within the bitfield (1-32), MSB set if value is signed */
94 unsigned char bit_size
; /* min 6+1 bit */
95 /* how many bytes in the global_settings struct (1,2,4) */
96 unsigned char byte_size
; /* min 3 bits */
97 /* store position in global_settings struct */
98 short settings_offset
; /* min 9 bit, better 10 */
100 int default_val
; /* min 15 bit */
101 /* variable name in a .cfg file, NULL if not to be saved */
102 const char* cfg_name
;
103 /* set of values, or NULL for a numerical value */
107 /********************************************
109 Config block as saved on the battery-packed RTC user RAM memory block
110 of 44 bytes, starting at offset 0x14 of the RTC memory space.
113 0x00 0x14 "Roc" header signature: 0x52 0x6f 0x63
114 0x03 0x17 <version byte: 0x0>
115 0x04 0x18 start of bit-table
117 0x28,0x29 unused, not reachable by set_bits() without disturbing the next 2
118 0x2A,0x2B <checksum 2 bytes: xor of 0x00-0x29>
120 Config memory is reset to 0xff and initialized with 'factory defaults' if
121 a valid header & checksum is not found. Config version number is only
122 increased when information is _relocated_ or space is _reused_ so that old
123 versions can read and modify configuration changed by new versions.
124 Memory locations not used by a given version should not be
125 modified unless the header & checksum test fails.
127 Rest of config block, only saved to disk:
128 0x2C start of 2nd bit-table
130 0xB8 (char[20]) WPS file
131 0xCC (char[20]) Lang file
132 0xE0 (char[20]) Font file
135 *************************************/
137 /* The persistence of the global_settings members is now controlled by
138 the two tables below, rtc_bits and hd_bits.
139 New values can just be added to the end, it will be backwards
140 compatible. If you however change order, bitsize, etc. of existing
141 entries, you need to bump CONFIG_BLOCK_VERSION to break compatibility.
145 /* convenience macro for both size and offset of global_settings member */
146 #define S_O(val) sizeof(global_settings.val), offsetof(struct user_settings, val)
147 #define SIGNED 0x80 /* for bitsize value with signed attribute */
149 /* some sets of values which are used more than once, to save memory */
150 static const char off_on
[] = "off,on";
151 static const char off_on_ask
[] = "off,on,ask";
152 static const char graphic_numeric
[] = "graphic,numeric";
153 static const char off_number_spell_hover
[] = "off,number,spell,hover";
155 /* the part of the settings which ends up in the RTC RAM, where available
156 (those we either need early, save frequently, or without spinup) */
157 static const struct bit_entry rtc_bits
[] =
159 /* placeholder, containing the size information */
160 {9, 0, 0, 0, NULL
, NULL
}, /* 9 bit to tell how far this is populated */
162 /* # of bits, offset+size, default, .cfg name, .cfg values */
164 {7, S_O(volume
), 70, "volume", NULL
}, /* 0...100 */
165 {8 | SIGNED
, S_O(balance
), 0, "balance", NULL
}, /* -100...100 */
166 {5 | SIGNED
, S_O(bass
), 0, "bass", NULL
}, /* -15..+15 / -12..+12 */
167 {5 | SIGNED
, S_O(treble
), 0, "treble", NULL
}, /* -15..+15 / -12..+12 */
168 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
169 {5, S_O(loudness
), 0, "loudness", NULL
}, /* 0...17 */
170 {3, S_O(avc
), 0, "auto volume", "off,20ms,2,4,8" },
171 {1, S_O(superbass
), false, "superbass", off_on
},
173 {3, S_O(channel_config
), 0, "channels",
174 "stereo,mono,custom,mono left,mono right,karaoke" },
175 {8, S_O(stereo_width
), 100, "stereo width", NULL
},
177 {2, S_O(resume
), RESUME_ASK
, "resume", "off,ask,ask once,on" },
178 {1, S_O(playlist_shuffle
), false, "shuffle", off_on
},
179 {16 | SIGNED
, S_O(resume_index
), -1, NULL
, NULL
},
180 {16 | SIGNED
, S_O(resume_first_index
), 0, NULL
, NULL
},
181 {32 | SIGNED
, S_O(resume_offset
), -1, NULL
, NULL
},
182 {32 | SIGNED
, S_O(resume_seed
), -1, NULL
, NULL
},
183 {2, S_O(repeat_mode
), REPEAT_ALL
, "repeat", "off,all,one" },
185 {6, S_O(contrast
), 40, "contrast", NULL
},
186 #ifdef CONFIG_BACKLIGHT
188 {1, S_O(backlight_on_when_charging
), false,
189 "backlight when plugged", off_on
},
191 {5, S_O(backlight_timeout
), 5, "backlight timeout",
192 "off,on,1,2,3,4,5,6,7,8,9,10,15,20,25,30,45,60,90" },
193 #endif /* CONFIG_BACKLIGHT */
194 #ifdef HAVE_LCD_BITMAP
195 {1, S_O(invert
), false, "invert", off_on
},
196 {1, S_O(flip_display
), false, "flip display", off_on
},
198 {1, S_O(invert_cursor
), false, "invert cursor", off_on
},
199 {1, S_O(statusbar
), true, "statusbar", off_on
},
200 {1, S_O(scrollbar
), true, "scrollbar", off_on
},
201 #if CONFIG_KEYPAD == RECORDER_PAD
202 {1, S_O(buttonbar
), true, "buttonbar", off_on
},
204 {1, S_O(volume_type
), 0, "volume display", graphic_numeric
},
205 {1, S_O(battery_type
), 0, "battery display", graphic_numeric
},
206 {1, S_O(timeformat
), 0, "time format", "24hour,12hour" },
208 {1, S_O(show_icons
), true, "show icons", off_on
},
210 {4, S_O(poweroff
), 10,
211 "idle poweroff", "off,1,2,3,4,5,6,7,8,9,10,15,30,45,60" },
212 {18, S_O(runtime
), 0, NULL
, NULL
},
213 {18, S_O(topruntime
), 0, NULL
, NULL
},
214 {15, S_O(max_files_in_playlist
), 10000,
215 "max files in playlist", NULL
}, /* 1000...20000 */
216 {14, S_O(max_files_in_dir
), 400,
217 "max files in dir", NULL
}, /* 50...10000 */
219 #ifdef HAVE_CHARGE_CTRL
220 {1, S_O(discharge
), 0, "deep discharge", off_on
},
221 {1, S_O(trickle_charge
), true, "trickle charge", off_on
},
223 {12, S_O(battery_capacity
), BATTERY_CAPACITY_MIN
, "battery capacity",
224 NULL
}, /* 1500...3200 for NiMH, 2200...3200 for LiIon,
225 500...1500 for Alkaline */
227 {1, S_O(car_adapter_mode
), false, "car adapter mode", off_on
},
231 {1, S_O(fm_force_mono
), false, "force fm mono", off_on
},
232 {8, S_O(last_frequency
), 0, NULL
, NULL
}, /* Default: MIN_FREQ */
235 /* new stuff to be added here */
236 /* If values are just added to the end, no need to bump the version. */
238 /* Current sum of bits: 259 (worst case) */
239 /* Sum of all bit sizes must not grow beyond 288! */
243 /* the part of the settings which ends up in HD sector only */
244 static const struct bit_entry hd_bits
[] =
246 /* This table starts after the 44 RTC bytes = 352 bits. */
247 /* Here we need 11 bits to tell how far this is populated. */
249 /* placeholder, containing the size information */
250 {11, 0, 0, 0, NULL
, NULL
}, /* 11 bit to tell how far this is populated */
252 /* # of bits, offset+size, default, .cfg name, .cfg values */
254 #ifdef CONFIG_BACKLIGHT
255 {1, S_O(caption_backlight
), false, "caption backlight", off_on
},
257 {4, S_O(scroll_speed
), 9, "scroll speed", NULL
}, /* 0...15 */
258 {7, S_O(scroll_step
), 6, "scroll step", NULL
}, /* 1...112 */
259 {8, S_O(scroll_delay
), 100, "scroll delay", NULL
}, /* 0...250 */
260 {8, S_O(bidir_limit
), 50, "bidir limit", NULL
}, /* 0...200 */
261 #ifdef HAVE_LCD_CHARCELLS
262 {3, S_O(jump_scroll
), 0, "jump scroll", NULL
}, /* 0...5 */
263 {8, S_O(jump_scroll_delay
), 50, "jump scroll delay", NULL
}, /* 0...250 */
266 {1, S_O(play_selected
), true, "play selected", off_on
},
267 {1, S_O(fade_on_stop
), true, "volume fade", off_on
},
268 {4, S_O(ff_rewind_min_step
), FF_REWIND_1000
,
269 "scan min step", "1,2,3,4,5,6,8,10,15,20,25,30,45,60" },
270 {4, S_O(ff_rewind_accel
), 3, "scan accel", NULL
},
271 {3, S_O(buffer_margin
), 0, "antiskip", NULL
},
274 #ifdef HAVE_ATA_POWER_OFF
275 {1, S_O(disk_poweroff
), false, "disk poweroff", off_on
},
277 {8, S_O(disk_spindown
), 5, "disk spindown", NULL
},
280 {3, S_O(dirfilter
), SHOW_MUSIC
,
281 "show files", "all,supported,music,playlists,id3 database" },
282 {1, S_O(sort_case
), false, "sort case", off_on
},
283 {1, S_O(browse_current
), false, "follow playlist", off_on
},
285 {1, S_O(playlist_viewer_icons
), true, "playlist viewer icons", off_on
},
286 {1, S_O(playlist_viewer_indices
), true,
287 "playlist viewer indices", off_on
},
288 {1, S_O(playlist_viewer_track_display
), 0,
289 "playlist viewer track display", "track name,full path" },
290 {2, S_O(recursive_dir_insert
), RECURSE_OFF
,
291 "recursive directory insert", off_on_ask
},
293 {3, S_O(autocreatebookmark
), BOOKMARK_NO
, "autocreate bookmarks",
294 "off,on,ask,recent only - on,recent only - ask" },
295 {2, S_O(autoloadbookmark
), BOOKMARK_NO
,
296 "autoload bookmarks", off_on_ask
},
297 {2, S_O(usemrb
), BOOKMARK_NO
,
298 "use most-recent-bookmarks", "off,on,unique only" },
299 #ifdef HAVE_LCD_BITMAP
301 {5, S_O(peak_meter_clip_hold
), 16, "peak meter clip hold", /* 0...25 */
302 "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" },
303 {1, S_O(peak_meter_performance
), false, "peak meter busy", off_on
},
304 {5, S_O(peak_meter_hold
), 3, "peak meter hold",
305 "off,200ms,300ms,500ms,1,2,3,4,5,6,7,8,9,10,15,20,30,1min" },
306 {7, S_O(peak_meter_release
), 8, "peak meter release", NULL
}, /* 0...126 */
307 {1, S_O(peak_meter_dbfs
), true, "peak meter dbfs", off_on
},
308 {7, S_O(peak_meter_min
), 60, "peak meter min", NULL
}, /* 0...100 */
309 {7, S_O(peak_meter_max
), 0, "peak meter max", NULL
}, /* 0...100 */
311 #if CONFIG_HWCODEC == MAS3587F
313 {1, S_O(rec_editable
), false, "editable recordings", off_on
},
314 {4, S_O(rec_timesplit
), 0, "rec timesplit", /* 0...15 */
315 "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" },
316 {1, S_O(rec_channels
), 0, "rec channels", "stereo,mono" },
317 {4, S_O(rec_mic_gain
), 8, "rec mic gain", NULL
},
318 {3, S_O(rec_quality
), 5, "rec quality", NULL
},
319 {2, S_O(rec_source
), 0, /* 0=mic */
320 "rec source", "mic,line,spdif" },
321 {3, S_O(rec_frequency
), 0, /* 0=44.1kHz */
322 "rec frequency", "44,48,32,22,24,16" },
323 {4, S_O(rec_left_gain
), 2, /* 0dB */
324 "rec left gain", NULL
}, /* 0...15 */
325 {4, S_O(rec_right_gain
), 2, /* 0dB */
326 "rec right gain", NULL
}, /* 0...15 */
327 {5, S_O(rec_prerecord_time
), 0, "prerecording time", NULL
}, /* 0...30 */
328 {1, S_O(rec_directory
), 0, /* rec_base_directory */
329 "rec directory", REC_BASE_DIR
",current" },
331 #if CONFIG_HWCODEC == MAS3507D
332 {1, S_O(line_in
), false, "line in", off_on
},
335 {2, S_O(talk_dir
), 0, "talk dir", off_number_spell_hover
},
336 {2, S_O(talk_file
), 0, "talk file", off_number_spell_hover
},
337 {1, S_O(talk_menu
), true, "talk menu", off_on
},
339 /* If values are just added to the end, no need to bump the version. */
340 {2, S_O(sort_file
), 0, "sort files", "alpha,oldest,newest,type" },
341 {2, S_O(sort_dir
), 0, "sort dirs", "alpha,oldest,newest" },
342 {7, S_O(mdb_strength
), 0, "mdb strength", NULL
},
343 {7, S_O(mdb_harmonics
), 0, "mdb harmonics", NULL
},
344 {9, S_O(mdb_center
), 0, "mdb center", NULL
},
345 {9, S_O(mdb_shape
), 0, "mdb shape", NULL
},
346 {1, S_O(mdb_enable
), 0, "mdb enable", off_on
},
347 {1, S_O(id3_v1_first
), 0, "id3 tag priority", "v2-v1,v1-v2"},
349 /* new stuff to be added at the end */
351 /* Sum of all bit sizes must not grow beyond 0xB8*8 = 1472 */
355 /* helper function to extract n (<=32) bits from an arbitrary position */
356 static unsigned long get_bits(
357 const unsigned long* p
, /* the start of the bitfield array */
358 unsigned int from
, /* bit no. to start reading from */
359 unsigned int size
) /* how many bits to read */
361 unsigned int bit_index
;
362 unsigned int bits_to_use
;
365 unsigned long result
;
369 return (p
[from
/32] & 1<<from
%32) != 0;
375 bit_index
= from
% 32;
376 bits_to_use
= MIN(32 - bit_index
, size
);
377 mask
= 0xFFFFFFFF >> (32 - bits_to_use
);
380 result
<<= bits_to_use
; /* from last round */
381 result
|= (p
[from
/32] & mask
) >> bit_index
;
390 /* helper function to set n (<=32) bits to an arbitrary position */
391 static void set_bits(
392 unsigned long* p
, /* the start of the bitfield array */
393 unsigned int from
, /* bit no. to start writing into */
394 unsigned int size
, /* how many bits to change */
395 unsigned long value
) /* content (LSBs will be taken) */
398 unsigned int word_index
, bit_index
;
399 unsigned int bits_to_use
;
406 p
[from
/32] |= 1<<from
%32;
408 p
[from
/32] &= ~(1<<from
%32);
412 end
= from
+ size
- 1;
414 /* write back to front, least to most significant */
417 word_index
= end
/ 32;
418 bit_index
= (end
% 32) + 1;
419 bits_to_use
= MIN(bit_index
, size
);
420 bit_index
-= bits_to_use
;
421 mask
= 0xFFFFFFFF >> (32 - bits_to_use
);
424 p
[word_index
] = (p
[word_index
] & ~mask
) | (value
<<bit_index
& mask
);
426 value
>>= bits_to_use
;
433 * Calculates the checksum for the config block and returns it
436 static unsigned short calculate_config_checksum(const unsigned char* buf
)
439 unsigned char cksum
[2];
440 cksum
[0] = cksum
[1] = 0;
442 for (i
=0; i
< RTC_BLOCK_SIZE
- 2; i
+=2 ) {
444 cksum
[1] ^= buf
[i
+1];
447 return (cksum
[0] << 8) | cksum
[1];
451 * initialize the config block buffer
453 static void init_config_buffer( void )
455 DEBUGF( "init_config_buffer()\n" );
457 /* reset to 0 - all unused */
458 memset(config_block
, 0, CONFIG_BLOCK_SIZE
);
460 config_block
[0] = 'R';
461 config_block
[1] = 'o';
462 config_block
[2] = 'c';
463 config_block
[3] = CONFIG_BLOCK_VERSION
;
467 * save the config block buffer to disk or RTC RAM
469 static int save_config_buffer( void )
471 unsigned short chksum
;
476 /* update the checksum in the end of the block before saving */
477 chksum
= calculate_config_checksum(config_block
);
478 config_block
[ RTC_BLOCK_SIZE
- 2 ] = chksum
>> 8;
479 config_block
[ RTC_BLOCK_SIZE
- 1 ] = chksum
& 0xff;
482 /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so
483 that it would write a number of bytes at a time since the RTC chip
484 supports that, but this will have to do for now 8-) */
485 for (i
=0; i
< RTC_BLOCK_SIZE
; i
++ ) {
486 int r
= rtc_write(0x14+i
, config_block
[i
]);
488 DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n",
496 if (config_sector
!= 0)
497 ata_delayed_write( config_sector
, config_block
);
505 * load the config block buffer from disk or RTC RAM
507 static int load_config_buffer(int which
)
509 unsigned short chksum
;
510 bool correct
= false;
513 DEBUGF( "load_config_buffer()\n" );
515 if (which
& SETTINGS_HD
)
517 if (config_sector
!= 0) {
518 ata_read_sectors(IF_MV2(0,) config_sector
, 1, config_block
);
519 /* calculate the checksum, check it and the header */
520 chksum
= calculate_config_checksum(config_block
);
522 if (config_block
[0] == 'R' &&
523 config_block
[1] == 'o' &&
524 config_block
[2] == 'c' &&
525 config_block
[3] == CONFIG_BLOCK_VERSION
&&
526 (chksum
>> 8) == config_block
[RTC_BLOCK_SIZE
- 2] &&
527 (chksum
& 0xff) == config_block
[RTC_BLOCK_SIZE
- 1])
529 DEBUGF( "load_config_buffer: header & checksum test ok\n" );
538 /* If the disk sector was incorrect, reinit the buffer */
539 memset(config_block
, 0, CONFIG_BLOCK_SIZE
);
542 if (which
& SETTINGS_RTC
)
545 unsigned char rtc_block
[RTC_BLOCK_SIZE
];
548 for (i
=0; i
< RTC_BLOCK_SIZE
; i
++ )
549 rtc_block
[i
] = rtc_read(0x14+i
);
551 chksum
= calculate_config_checksum(rtc_block
);
553 /* if rtc block is ok, use that */
554 if (rtc_block
[0] == 'R' &&
555 rtc_block
[1] == 'o' &&
556 rtc_block
[2] == 'c' &&
557 rtc_block
[3] == CONFIG_BLOCK_VERSION
&&
558 (chksum
>> 8) == rtc_block
[RTC_BLOCK_SIZE
- 2] &&
559 (chksum
& 0xff) == rtc_block
[RTC_BLOCK_SIZE
- 1])
561 memcpy(config_block
, rtc_block
, RTC_BLOCK_SIZE
);
568 /* if checksum is not valid, clear the config buffer */
569 DEBUGF( "load_config_buffer: header & checksum test failed\n" );
570 init_config_buffer();
578 /* helper to save content of global_settings into a bitfield,
579 as described per table */
580 static void save_bit_table(const struct bit_entry
* p_table
, int count
, int bitstart
)
582 unsigned long* p_bitfield
= (unsigned long*)config_block
; /* 32 bit addr. */
583 unsigned long value
; /* 32 bit content */
585 const struct bit_entry
* p_run
= p_table
; /* start after the size info */
586 int curr_bit
= bitstart
+ p_table
->bit_size
;
587 count
--; /* first is excluded from loop */
589 for (i
=0; i
<count
; i
++)
592 /* could do a memcpy, but that would be endian-dependent */
593 switch(p_run
->byte_size
)
596 value
= ((unsigned char*)&global_settings
)[p_run
->settings_offset
];
599 value
= ((unsigned short*)&global_settings
)[p_run
->settings_offset
/2];
602 value
= ((unsigned int*)&global_settings
)[p_run
->settings_offset
/4];
605 DEBUGF( "illegal size!" );
608 set_bits(p_bitfield
, curr_bit
, p_run
->bit_size
& 0x3F, value
);
609 curr_bit
+= p_run
->bit_size
& 0x3F;
611 set_bits(p_bitfield
, bitstart
, p_table
->bit_size
, /* write size */
612 curr_bit
); /* = position after last element */
616 * figure out the config sector from the partition table and the
617 * mounted file system
619 void settings_calc_config_sector(void)
624 int i
, partition_start
;
627 if (fat_startsector(IF_MV(0)) != 0) /* There is a partition table */
630 for (i
= 0; i
< 4; i
++)
632 partition_start
= disk_partinfo(i
)->start
;
633 if (partition_start
!= 0 && (partition_start
- 2) < sector
)
634 sector
= partition_start
- 2;
640 config_sector
= sector
;
645 * persist all runtime user settings to disk or RTC RAM
647 int settings_save( void )
652 elapsed_secs
= (current_tick
- lasttime
) / HZ
;
653 global_settings
.runtime
+= elapsed_secs
;
654 lasttime
+= (elapsed_secs
* HZ
);
656 if ( global_settings
.runtime
> global_settings
.topruntime
)
657 global_settings
.topruntime
= global_settings
.runtime
;
660 /* serialize scalar values into RTC and HD sector, specified via table */
661 save_bit_table(rtc_bits
, sizeof(rtc_bits
)/sizeof(rtc_bits
[0]), 4*8);
662 save_bit_table(hd_bits
, sizeof(hd_bits
)/sizeof(hd_bits
[0]), RTC_BLOCK_SIZE
*8);
664 strncpy(&config_block
[0xb8], global_settings
.wps_file
, MAX_FILENAME
);
665 strncpy(&config_block
[0xcc], global_settings
.lang_file
, MAX_FILENAME
);
666 strncpy(&config_block
[0xe0], global_settings
.font_file
, MAX_FILENAME
);
668 if(save_config_buffer())
671 #ifdef HAVE_LCD_CHARCELLS
672 lcd_puts(0, 0, str(LANG_SETTINGS_SAVE_PLAYER
));
673 lcd_puts(0, 1, str(LANG_SETTINGS_BATTERY_PLAYER
));
675 lcd_puts(4, 2, str(LANG_SETTINGS_SAVE_RECORDER
));
676 lcd_puts(2, 4, str(LANG_SETTINGS_BATTERY_RECORDER
));
685 #ifdef HAVE_LCD_BITMAP
687 * Applies the range infos stored in global_settings to
690 void settings_apply_pm_range(void)
694 /* depending on the scale mode (dBfs or percent) the values
695 of global_settings.peak_meter_dbfs have different meanings */
696 if (global_settings
.peak_meter_dbfs
)
698 /* convert to dBfs * 100 */
699 pm_min
= -(((int)global_settings
.peak_meter_min
) * 100);
700 pm_max
= -(((int)global_settings
.peak_meter_max
) * 100);
704 /* percent is stored directly -> no conversion */
705 pm_min
= global_settings
.peak_meter_min
;
706 pm_max
= global_settings
.peak_meter_max
;
709 /* apply the range */
710 peak_meter_init_range(global_settings
.peak_meter_dbfs
, pm_min
, pm_max
);
712 #endif /* HAVE_LCD_BITMAP */
714 void sound_settings_apply(void)
716 mpeg_sound_set(SOUND_BASS
, global_settings
.bass
);
717 mpeg_sound_set(SOUND_TREBLE
, global_settings
.treble
);
718 mpeg_sound_set(SOUND_BALANCE
, global_settings
.balance
);
719 mpeg_sound_set(SOUND_VOLUME
, global_settings
.volume
);
720 mpeg_sound_set(SOUND_CHANNELS
, global_settings
.channel_config
);
721 mpeg_sound_set(SOUND_STEREO_WIDTH
, global_settings
.stereo_width
);
722 #if (CONFIG_HWCODEC == MAS3587F) || (CONFIG_HWCODEC == MAS3539F)
723 mpeg_sound_set(SOUND_LOUDNESS
, global_settings
.loudness
);
724 mpeg_sound_set(SOUND_AVC
, global_settings
.avc
);
725 mpeg_sound_set(SOUND_MDB_STRENGTH
, global_settings
.mdb_strength
);
726 mpeg_sound_set(SOUND_MDB_HARMONICS
, global_settings
.mdb_harmonics
);
727 mpeg_sound_set(SOUND_MDB_CENTER
, global_settings
.mdb_center
);
728 mpeg_sound_set(SOUND_MDB_SHAPE
, global_settings
.mdb_shape
);
729 mpeg_sound_set(SOUND_MDB_ENABLE
, global_settings
.mdb_enable
);
730 mpeg_sound_set(SOUND_SUPERBASS
, global_settings
.superbass
);
734 void settings_apply(void)
738 sound_settings_apply();
740 mpeg_set_buffer_margin(global_settings
.buffer_margin
);
742 lcd_set_contrast(global_settings
.contrast
);
743 lcd_scroll_speed(global_settings
.scroll_speed
);
744 backlight_set_timeout(global_settings
.backlight_timeout
);
745 backlight_set_on_when_charging(global_settings
.backlight_on_when_charging
);
746 ata_spindown(global_settings
.disk_spindown
);
747 #if CONFIG_HWCODEC == MAS3507D
748 dac_line_in(global_settings
.line_in
);
750 #ifdef HAVE_ATA_POWER_OFF
751 ata_poweroff(global_settings
.disk_poweroff
);
754 set_poweroff_timeout(global_settings
.poweroff
);
755 #ifdef HAVE_CHARGE_CTRL
756 charge_restart_level
= global_settings
.discharge
?
757 CHARGE_RESTART_LO
: CHARGE_RESTART_HI
;
758 enable_trickle_charge(global_settings
.trickle_charge
);
761 set_battery_capacity(global_settings
.battery_capacity
);
763 #ifdef HAVE_LCD_BITMAP
764 lcd_set_invert_display(global_settings
.invert
);
765 lcd_set_flip(global_settings
.flip_display
);
766 button_set_flip(global_settings
.flip_display
);
767 lcd_update(); /* refresh after flipping the screen */
768 settings_apply_pm_range();
769 peak_meter_init_times(
770 global_settings
.peak_meter_release
, global_settings
.peak_meter_hold
,
771 global_settings
.peak_meter_clip_hold
);
774 if ( global_settings
.wps_file
[0] &&
775 global_settings
.wps_file
[0] != 0xff ) {
776 snprintf(buf
, sizeof buf
, ROCKBOX_DIR
"/%s.wps",
777 global_settings
.wps_file
);
778 wps_load(buf
, false);
783 #ifdef HAVE_LCD_BITMAP
784 if ( global_settings
.font_file
[0] &&
785 global_settings
.font_file
[0] != 0xff ) {
786 snprintf(buf
, sizeof buf
, ROCKBOX_DIR FONT_DIR
"/%s.fnt",
787 global_settings
.font_file
);
793 lcd_scroll_step(global_settings
.scroll_step
);
795 lcd_jump_scroll(global_settings
.jump_scroll
);
796 lcd_jump_scroll_delay(global_settings
.jump_scroll_delay
* (HZ
/10));
798 lcd_bidir_scroll(global_settings
.bidir_limit
);
799 lcd_scroll_delay(global_settings
.scroll_delay
* (HZ
/10));
801 if ( global_settings
.lang_file
[0] &&
802 global_settings
.lang_file
[0] != 0xff ) {
803 snprintf(buf
, sizeof buf
, ROCKBOX_DIR LANG_DIR
"/%s.lng",
804 global_settings
.lang_file
);
806 talk_init(); /* use voice of same language */
809 set_car_adapter_mode(global_settings
.car_adapter_mode
);
813 /* helper to load global_settings from a bitfield, as described per table */
814 static void load_bit_table(const struct bit_entry
* p_table
, int count
, int bitstart
)
816 unsigned long* p_bitfield
= (unsigned long*)config_block
; /* 32 bit addr. */
817 unsigned long value
; /* 32 bit content */
819 int maxbit
; /* how many bits are valid in the saved part */
820 const struct bit_entry
* p_run
= p_table
; /* start after the size info */
821 count
--; /* first is excluded from loop */
822 maxbit
= get_bits(p_bitfield
, bitstart
, p_table
->bit_size
);
823 bitstart
+= p_table
->bit_size
;
825 for (i
=0; i
<count
; i
++)
830 size
= p_run
->bit_size
& 0x3F; /* mask off abused bits */
831 if (bitstart
+ size
> maxbit
)
832 break; /* exit if this is not valid any more in bitfield */
834 value
= get_bits(p_bitfield
, bitstart
, size
);
836 if (p_run
->bit_size
& SIGNED
)
837 { // sign extend the read value
838 unsigned long mask
= 0xFFFFFFFF << (size
- 1);
839 if (value
& mask
) /* true if MSB of value is set */
843 /* could do a memcpy, but that would be endian-dependent */
844 switch(p_run
->byte_size
)
847 ((unsigned char*)&global_settings
)[p_run
->settings_offset
] =
848 (unsigned char)value
;
851 ((unsigned short*)&global_settings
)[p_run
->settings_offset
/2] =
852 (unsigned short)value
;
855 ((unsigned int*)&global_settings
)[p_run
->settings_offset
/4] =
859 DEBUGF( "illegal size!" );
867 * load settings from disk or RTC RAM
869 void settings_load(int which
)
871 DEBUGF( "reload_all_settings()\n" );
873 /* load the buffer from the RTC (resets it to all-unused if the block
874 is invalid) and decode the settings which are set in the block */
875 if (!load_config_buffer(which
))
877 /* load scalar values from RTC and HD sector, specified via table */
878 if (which
& SETTINGS_RTC
)
880 load_bit_table(rtc_bits
, sizeof(rtc_bits
)/sizeof(rtc_bits
[0]), 4*8);
882 if (which
& SETTINGS_HD
)
884 load_bit_table(hd_bits
, sizeof(hd_bits
)/sizeof(hd_bits
[0]),
888 if ( global_settings
.contrast
< MIN_CONTRAST_SETTING
)
889 global_settings
.contrast
= lcd_default_contrast();
891 strncpy(global_settings
.wps_file
, &config_block
[0xb8], MAX_FILENAME
);
892 strncpy(global_settings
.lang_file
, &config_block
[0xcc], MAX_FILENAME
);
893 strncpy(global_settings
.font_file
, &config_block
[0xe0], MAX_FILENAME
);
897 void set_file(char* filename
, char* setting
, int maxlen
)
899 char* fptr
= strrchr(filename
,'/');
912 while (*ptr
!= '.') {
917 if (strncasecmp(ROCKBOX_DIR
, filename
,strlen(ROCKBOX_DIR
)) ||
918 (len
-extlen
> maxlen
))
921 strncpy(setting
, fptr
, len
-extlen
);
922 setting
[len
-extlen
]=0;
927 /* helper to sort a .cfg file entry into a global_settings member,
928 as described per table. Returns the position if found, else 0. */
929 static int load_cfg_table(
930 const struct bit_entry
* p_table
, /* the table which describes the entries */
931 int count
, /* number of entries in the table, including the first */
932 const char* name
, /* the item to be searched */
933 const char* value
, /* the value which got loaded for that item */
934 int hint
) /* position to start looking */
940 if (p_table
[i
].cfg_name
!= NULL
&& !strcasecmp(name
, p_table
[i
].cfg_name
))
943 if (p_table
[i
].cfg_val
== NULL
)
944 { /* numerical value, just convert the string */
948 { /* set of string values, find the index */
951 int len
= strlen(value
);
953 item
= run
= p_table
[i
].cfg_val
;
957 /* count the length of the field */
958 while (*run
!= ',' && *run
!= '\0')
961 if (!strncasecmp(value
, item
, MAX(run
-item
, len
)))
962 break; /* match, exit the search */
964 if (*run
== '\0') /* reached the end of the choices */
965 return i
; /* return the position, but don't update */
967 val
++; /* count the item up */
968 run
++; /* behind the ',' */
973 /* could do a memcpy, but that would be endian-dependent */
974 switch(p_table
[i
].byte_size
)
977 ((unsigned char*)&global_settings
)[p_table
[i
].settings_offset
] =
981 ((unsigned short*)&global_settings
)[p_table
[i
].settings_offset
/2] =
985 ((unsigned int*)&global_settings
)[p_table
[i
].settings_offset
/4] =
989 DEBUGF( "illegal size!" );
993 return i
; /* return the position */
998 i
=1; /* wraparound */
999 } while (i
!= hint
); /* back where we started, all searched */
1001 return 0; /* indicate not found */
1005 bool settings_load_config(const char* file
)
1010 fd
= open(file
, O_RDONLY
);
1014 while (read_line(fd
, line
, sizeof line
) > 0)
1018 const struct bit_entry
* table
[2] = { rtc_bits
, hd_bits
};
1019 const int ta_size
[2] = {
1020 sizeof(rtc_bits
)/sizeof(rtc_bits
[0]),
1021 sizeof(hd_bits
)/sizeof(hd_bits
[0])
1023 int last_table
= 0; /* which table was used last round */
1024 int last_pos
= 1; /* at which position did we succeed */
1025 int pos
; /* currently returned position */
1027 if (!settings_parseline(line
, &name
, &value
))
1030 /* check for the string values */
1031 if (!strcasecmp(name
, "wps")) {
1032 if (wps_load(value
,false))
1033 set_file(value
, global_settings
.wps_file
, MAX_FILENAME
);
1035 else if (!strcasecmp(name
, "lang")) {
1036 if (!lang_load(value
))
1038 set_file(value
, global_settings
.lang_file
, MAX_FILENAME
);
1039 talk_init(); /* use voice of same language */
1042 #ifdef HAVE_LCD_BITMAP
1043 else if (!strcasecmp(name
, "font")) {
1044 if (font_load(value
))
1045 set_file(value
, global_settings
.font_file
, MAX_FILENAME
);
1049 /* check for scalar values, using the two tables */
1050 pos
= load_cfg_table(table
[last_table
], ta_size
[last_table
],
1051 name
, value
, last_pos
);
1052 if (pos
) /* success */
1054 last_pos
= pos
; /* remember as a position hint for next round */
1058 last_table
= 1-last_table
; /* try other table */
1059 last_pos
= 1; /* search from start */
1060 pos
= load_cfg_table(table
[last_table
], ta_size
[last_table
],
1061 name
, value
, last_pos
);
1062 if (pos
) /* success */
1064 last_pos
= pos
; /* remember as a position hint for next round */
1076 /* helper to save content of global_settings into a file,
1077 as described per table */
1078 static void save_cfg_table(const struct bit_entry
* p_table
, int count
, int fd
)
1080 long value
; /* 32 bit content */
1082 const struct bit_entry
* p_run
= p_table
; /* start after the size info */
1083 count
--; /* first is excluded from loop */
1085 for (i
=0; i
<count
; i
++)
1089 if (p_run
->cfg_name
== NULL
)
1090 continue; /* this value is not to be saved */
1092 /* could do a memcpy, but that would be endian-dependent */
1093 switch(p_run
->byte_size
)
1096 if (p_run
->bit_size
& SIGNED
) /* signed? */
1097 value
= ((char*)&global_settings
)[p_run
->settings_offset
];
1099 value
= ((unsigned char*)&global_settings
)[p_run
->settings_offset
];
1102 if (p_run
->bit_size
& SIGNED
) /* signed? */
1103 value
= ((short*)&global_settings
)[p_run
->settings_offset
/2];
1105 value
= ((unsigned short*)&global_settings
)[p_run
->settings_offset
/2];
1108 value
= ((unsigned int*)&global_settings
)[p_run
->settings_offset
/4];
1111 DEBUGF( "illegal size!" );
1115 if (p_run
->cfg_val
== NULL
) /* write as number */
1117 fprintf(fd
, "%s: %d\r\n", p_run
->cfg_name
, value
);
1119 else /* write as item */
1121 const char* p
= p_run
->cfg_val
;
1123 fprintf(fd
, "%s: ", p_run
->cfg_name
);
1127 char c
= *p
++; /* currently processed char */
1128 if (c
== ',') /* separator */
1130 else if (c
== '\0') /* end of string */
1131 break; /* not found */
1132 else if (value
== 0) /* the right place */
1133 write(fd
, &c
, 1); /* char by char, this is lame, OK */
1136 fprintf(fd
, "\r\n");
1137 if (p_run
->cfg_val
!= off_on
) /* explaination for non-bool */
1138 fprintf(fd
, "# (possible values: %s)\r\n", p_run
->cfg_val
);
1144 bool settings_save_config(void)
1148 char filename
[MAX_PATH
];
1150 /* find unused filename */
1152 snprintf(filename
, sizeof filename
, ROCKBOX_DIR
"/config%02d.cfg", i
);
1153 fd
= open(filename
, O_RDONLY
);
1159 /* allow user to modify filename */
1161 if (!kbd_input(filename
, sizeof filename
)) {
1162 fd
= creat(filename
,0);
1164 lcd_clear_display();
1165 lcd_puts(0,0,str(LANG_FAILED
));
1176 /* abort if file couldn't be created */
1178 lcd_clear_display();
1179 lcd_puts(0,0,str(LANG_RESET_DONE_CANCEL
));
1185 fprintf(fd
, "# >>> .cfg file created by rockbox %s <<<\r\n", appsversion
);
1186 fprintf(fd
, "# >>> http://rockbox.haxx.se <<<\r\n#\r\n");
1187 fprintf(fd
, "#\r\n# wps / language / font \r\n#\r\n");
1189 if (global_settings
.wps_file
[0] != 0)
1190 fprintf(fd
, "wps: %s/%s.wps\r\n", ROCKBOX_DIR
,
1191 global_settings
.wps_file
);
1193 if (global_settings
.lang_file
[0] != 0)
1194 fprintf(fd
, "lang: %s/%s.lng\r\n", ROCKBOX_DIR LANG_DIR
,
1195 global_settings
.lang_file
);
1197 #ifdef HAVE_LCD_BITMAP
1198 if (global_settings
.font_file
[0] != 0)
1199 fprintf(fd
, "font: %s/%s.fnt\r\n", ROCKBOX_DIR FONT_DIR
,
1200 global_settings
.font_file
);
1203 /* here's the action: write values to file, specified via table */
1204 save_cfg_table(rtc_bits
, sizeof(rtc_bits
)/sizeof(rtc_bits
[0]), fd
);
1205 save_cfg_table(hd_bits
, sizeof(hd_bits
)/sizeof(hd_bits
[0]), fd
);
1209 lcd_clear_display();
1210 lcd_puts(0,0,str(LANG_SETTINGS_SAVED1
));
1211 lcd_puts(0,1,str(LANG_SETTINGS_SAVED2
));
1218 /* helper to load defaults from table into global_settings members */
1219 static void default_table(const struct bit_entry
* p_table
, int count
)
1223 for (i
=1; i
<count
; i
++) /* exclude the first, the size placeholder */
1225 /* could do a memcpy, but that would be endian-dependent */
1226 switch(p_table
[i
].byte_size
)
1229 ((unsigned char*)&global_settings
)[p_table
[i
].settings_offset
] =
1230 (unsigned char)p_table
[i
].default_val
;
1233 ((unsigned short*)&global_settings
)[p_table
[i
].settings_offset
/2] =
1234 (unsigned short)p_table
[i
].default_val
;
1237 ((unsigned int*)&global_settings
)[p_table
[i
].settings_offset
/4] =
1238 (unsigned int)p_table
[i
].default_val
;
1241 DEBUGF( "illegal size!" );
1249 * reset all settings to their default value
1251 void settings_reset(void) {
1253 DEBUGF( "settings_reset()\n" );
1255 /* read defaults from table(s) into global_settings */
1256 default_table(rtc_bits
, sizeof(rtc_bits
)/sizeof(rtc_bits
[0]));
1257 default_table(hd_bits
, sizeof(hd_bits
)/sizeof(hd_bits
[0]));
1259 /* do some special cases not covered by table */
1260 global_settings
.volume
= mpeg_sound_default(SOUND_VOLUME
);
1261 global_settings
.balance
= mpeg_sound_default(SOUND_BALANCE
);
1262 global_settings
.bass
= mpeg_sound_default(SOUND_BASS
);
1263 global_settings
.treble
= mpeg_sound_default(SOUND_TREBLE
);
1264 global_settings
.loudness
= mpeg_sound_default(SOUND_LOUDNESS
);
1265 global_settings
.avc
= mpeg_sound_default(SOUND_AVC
);
1266 global_settings
.channel_config
= mpeg_sound_default(SOUND_CHANNELS
);
1267 global_settings
.stereo_width
= mpeg_sound_default(SOUND_STEREO_WIDTH
);
1268 global_settings
.mdb_strength
= mpeg_sound_default(SOUND_MDB_STRENGTH
);
1269 global_settings
.mdb_harmonics
= mpeg_sound_default(SOUND_MDB_HARMONICS
);
1270 global_settings
.mdb_center
= mpeg_sound_default(SOUND_MDB_CENTER
);
1271 global_settings
.mdb_shape
= mpeg_sound_default(SOUND_MDB_SHAPE
);
1272 global_settings
.mdb_enable
= mpeg_sound_default(SOUND_MDB_ENABLE
);
1273 global_settings
.superbass
= mpeg_sound_default(SOUND_SUPERBASS
);
1274 global_settings
.contrast
= lcd_default_contrast();
1275 global_settings
.wps_file
[0] = '\0';
1276 global_settings
.font_file
[0] = '\0';
1277 global_settings
.lang_file
[0] = '\0';
1281 bool set_bool(const char* string
, bool* variable
)
1283 return set_bool_options(string
, variable
,
1284 STR(LANG_SET_BOOL_YES
),
1285 STR(LANG_SET_BOOL_NO
),
1289 /* wrapper to convert from int param to bool param in set_option */
1290 static void (*boolfunction
)(bool);
1291 void bool_funcwrapper(int value
)
1296 boolfunction(false);
1299 bool set_bool_options(const char* string
, bool* variable
,
1300 const char* yes_str
, int yes_voice
,
1301 const char* no_str
, int no_voice
,
1302 void (*function
)(bool))
1304 struct opt_items names
[] = { {no_str
, no_voice
}, {yes_str
, yes_voice
} };
1307 boolfunction
= function
;
1308 result
= set_option(string
, variable
, BOOL
, names
, 2,
1309 function
? bool_funcwrapper
: NULL
);
1313 bool set_int(const char* string
,
1317 void (*function
)(int),
1324 int org_value
=*variable
;
1325 int last_value
= 0x7FFFFFFF; /* out of range init */
1327 #ifdef HAVE_LCD_BITMAP
1328 if(global_settings
.statusbar
)
1329 lcd_setmargins(0, STATUSBAR_HEIGHT
);
1331 lcd_setmargins(0, 0);
1334 lcd_clear_display();
1335 lcd_puts_scroll(0, 0, string
);
1339 snprintf(str
,sizeof str
,"%d %s ", *variable
, unit
);
1340 lcd_puts(0, 1, str
);
1341 #ifdef HAVE_LCD_BITMAP
1346 if (global_settings
.talk_menu
&& *variable
!= last_value
)
1348 if (voice_unit
< UNIT_LAST
)
1349 { /* use the available unit definition */
1350 talk_value(*variable
, voice_unit
, false);
1353 { /* say the number, followed by an arbitrary voice ID */
1354 talk_number(*variable
, false);
1355 talk_id(voice_unit
, true);
1357 last_value
= *variable
;
1360 button
= button_get_w_tmo(HZ
/2);
1363 case SETTINGS_INC
| BUTTON_REPEAT
:
1368 case SETTINGS_DEC
| BUTTON_REPEAT
:
1379 case SETTINGS_CANCEL
:
1380 #ifdef SETTINGS_CANCEL2
1381 case SETTINGS_CANCEL2
:
1383 if (*variable
!= org_value
) {
1384 *variable
=org_value
;
1386 lcd_puts(0, 0, str(LANG_MENU_SETTING_CANCEL
));
1394 if(default_event_handler(button
) == SYS_USB_CONNECTED
)
1398 if(*variable
> max
)
1401 if(*variable
< min
)
1404 if ( function
&& button
!= BUTTON_NONE
)
1405 function(*variable
);
1412 /* NOTE: the 'type' parameter specifies the actual type of the variable
1413 that 'variable' points to. not the value within. Only variables with
1414 type 'bool' should use parameter BOOL.
1416 The type separation is necessary since int and bool are fundamentally
1417 different and bit-incompatible types and can not share the same access
1420 bool set_option(const char* string
, void* variable
, enum optiontype type
,
1421 const struct opt_items
* options
, int numoptions
, void (*function
)(int))
1425 int* intvar
= (int*)variable
;
1426 bool* boolvar
= (bool*)variable
;
1428 int index
, oldindex
= -1; /* remember what we said */
1435 #ifdef HAVE_LCD_BITMAP
1436 if(global_settings
.statusbar
)
1437 lcd_setmargins(0, STATUSBAR_HEIGHT
);
1439 lcd_setmargins(0, 0);
1442 lcd_clear_display();
1443 lcd_puts_scroll(0, 0, string
);
1446 index
= type
==INT
? *intvar
: (int)*boolvar
;
1447 lcd_puts(0, 1, P2STR(options
[index
].string
));
1448 if (global_settings
.talk_menu
&& index
!= oldindex
)
1450 talk_id(options
[index
].voice_id
, false);
1453 #ifdef HAVE_LCD_BITMAP
1458 button
= button_get_w_tmo(HZ
/2);
1461 case SETTINGS_INC
| BUTTON_REPEAT
:
1463 if ( *intvar
< (numoptions
-1) )
1466 (*intvar
) -= (numoptions
-1);
1469 *boolvar
= !*boolvar
;
1473 case SETTINGS_DEC
| BUTTON_REPEAT
:
1478 (*intvar
) += (numoptions
-1);
1481 *boolvar
= !*boolvar
;
1491 case SETTINGS_CANCEL
:
1492 #ifdef SETTINGS_CANCEL2
1493 case SETTINGS_CANCEL2
:
1495 if (((type
==INT
) && (*intvar
!= oldval
)) ||
1496 ((type
==BOOL
) && (*boolvar
!= (bool)oldval
))) {
1502 lcd_puts(0, 0, str(LANG_MENU_SETTING_CANCEL
));
1510 if(default_event_handler(button
) == SYS_USB_CONNECTED
)
1515 if ( function
&& button
!= BUTTON_NONE
) {
1526 #if CONFIG_HWCODEC == MAS3587F
1527 /* This array holds the record timer interval lengths, in seconds */
1528 static const unsigned long rec_timer_seconds
[] =
1530 24*60*60, /* OFF really means 24 hours, to avoid >2Gbyte files */
1538 2*60*60, /* 02:00 */
1539 4*60*60, /* 04:00 */
1540 6*60*60, /* 06:00 */
1541 8*60*60, /* 08:00 */
1542 10*60*60, /* 10:00 */
1543 12*60*60, /* 12:00 */
1544 18*60*60, /* 18:00 */
1545 24*60*60 /* 24:00 */
1548 unsigned int rec_timesplit_seconds(void)
1550 return rec_timer_seconds
[global_settings
.rec_timesplit
];