summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorBjörn Stenberg <bjorn@haxx.se>2002-08-16 14:41:47 +0000
committerBjörn Stenberg <bjorn@haxx.se>2002-08-16 14:41:47 +0000
commit6224cdb16677cae7b65b0598eec3381a6fb6a4aa (patch)
tree9ad9b39557492606c853e7f14c359bca5e0a3b65 /apps
parent085e77467565aba251c31721e92bc7ebd7baa61f (diff)
downloadrockbox-6224cdb16677cae7b65b0598eec3381a6fb6a4aa.tar.gz
rockbox-6224cdb16677cae7b65b0598eec3381a6fb6a4aa.zip
Added resume. Works in dirs and playlists, shuffled or not. Resumes mid-song, but press pause on players before you shutdown so they get a chance to store the position on disk. Recorders use RTC ram. Todo: Time display is wrong after mid-track resume and ffd/rew is not handled.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@1787 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/playlist.c16
-rw-r--r--apps/playlist.h5
-rw-r--r--apps/settings.c247
-rw-r--r--apps/settings.h8
-rw-r--r--apps/settings_menu.c7
-rw-r--r--apps/tree.c129
-rw-r--r--apps/wps.c22
7 files changed, 320 insertions, 114 deletions
diff --git a/apps/playlist.c b/apps/playlist.c
index 0cb9d09f32..f3081397f6 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -66,7 +66,7 @@ int playlist_add(char *filename)
66 return 0; 66 return 0;
67} 67}
68 68
69char* playlist_next(int steps) 69char* playlist_next(int steps, int* index)
70{ 70{
71 int seek; 71 int seek;
72 int max; 72 int max;
@@ -103,7 +103,9 @@ char* playlist_next(int steps)
103 else 103 else
104 return NULL; 104 return NULL;
105 } 105 }
106 106
107 if (index)
108 *index = playlist.index;
107 109
108 /* Zero-terminate the file name */ 110 /* Zero-terminate the file name */
109 seek=0; 111 seek=0;
@@ -165,7 +167,11 @@ char* playlist_next(int steps)
165 } 167 }
166} 168}
167 169
168void play_list(char *dir, char *file, int start_index) 170void play_list(char *dir,
171 char *file,
172 int start_index,
173 int start_offset,
174 int random_seed )
169{ 175{
170 char *sep=""; 176 char *sep="";
171 int dirlen; 177 int dirlen;
@@ -211,7 +217,7 @@ void play_list(char *dir, char *file, int start_index)
211 status_draw(); 217 status_draw();
212 lcd_update(); 218 lcd_update();
213 } 219 }
214 randomise_playlist( current_tick ); 220 randomise_playlist( random_seed );
215 } 221 }
216 222
217 if(!playlist.in_ram) { 223 if(!playlist.in_ram) {
@@ -220,7 +226,7 @@ void play_list(char *dir, char *file, int start_index)
220 lcd_update(); 226 lcd_update();
221 } 227 }
222 /* also make the first song get playing */ 228 /* also make the first song get playing */
223 mpeg_play(playlist_next(0)); 229 mpeg_play(start_offset);
224} 230}
225 231
226/* 232/*
diff --git a/apps/playlist.h b/apps/playlist.h
index 312964fd8c..e0c0841207 100644
--- a/apps/playlist.h
+++ b/apps/playlist.h
@@ -40,8 +40,9 @@ typedef struct
40extern playlist_info_t playlist; 40extern playlist_info_t playlist;
41extern bool playlist_shuffle; 41extern bool playlist_shuffle;
42 42
43void play_list(char *dir, char *file, int start_index); 43void play_list(char *dir, char *file, int start_index,
44char* playlist_next(int steps); 44 int start_offset, int random_seed );
45char* playlist_next(int steps, int* id);
45void randomise_playlist( unsigned int seed ); 46void randomise_playlist( unsigned int seed );
46void sort_playlist(void); 47void sort_playlist(void);
47void empty_playlist(void); 48void empty_playlist(void);
diff --git a/apps/settings.c b/apps/settings.c
index f8b6870863..41d04c2819 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -37,10 +37,9 @@
37 37
38struct user_settings global_settings; 38struct user_settings global_settings;
39 39
40static unsigned short last_checksum = 0;
41
42#define CONFIG_BLOCK_VERSION 1 40#define CONFIG_BLOCK_VERSION 1
43#define CONFIG_BLOCK_SIZE 44 41#define CONFIG_BLOCK_SIZE 512
42#define RTC_BLOCK_SIZE 44
44 43
45/******************************************** 44/********************************************
46 45
@@ -64,6 +63,8 @@ offset abs
640x0f 0x23 <scroll speed & WPS display byte> 630x0f 0x23 <scroll speed & WPS display byte>
650x10 0x24 <playlist options byte> 640x10 0x24 <playlist options byte>
660x11 0x25 <AVC byte> 650x11 0x25 <AVC byte>
660x12 0x26 <(int) Resume playlist index, or -1 if no playlist resume>
670x16 0x2b <(int) Byte offset into resume file>
67 68
68 <all unused space filled with 0xff> 69 <all unused space filled with 0xff>
69 70
@@ -81,24 +82,30 @@ location used, and reset the setting in question with a factory default if
81needed. Memory locations not used by a given version should not be 82needed. Memory locations not used by a given version should not be
82modified unless the header & checksum test fails. 83modified unless the header & checksum test fails.
83 84
85
86Rest of config block, only saved to disk:
87
880xF8 (int) Playlist shuffle seed
890xFC (char[260]) Resume playlist (path/to/dir or path/to/playlist.m3u)
90
84*************************************/ 91*************************************/
85 92
86#include "rtc.h" 93#include "rtc.h"
87static unsigned char rtc_config_block[CONFIG_BLOCK_SIZE]; 94static unsigned char config_block[CONFIG_BLOCK_SIZE];
88 95
89/* 96/*
90 * Calculates the checksum for the config block and places it in the given 2-byte buffer 97 * Calculates the checksum for the config block and returns it
91 */ 98 */
92 99
93static unsigned short calculate_config_checksum(void) 100static unsigned short calculate_config_checksum(unsigned char* buf)
94{ 101{
95 unsigned int i; 102 unsigned int i;
96 unsigned char cksum[2]; 103 unsigned char cksum[2];
97 cksum[0] = cksum[1] = 0; 104 cksum[0] = cksum[1] = 0;
98 105
99 for (i=0; i < CONFIG_BLOCK_SIZE - 2; i+=2 ) { 106 for (i=0; i < RTC_BLOCK_SIZE - 2; i+=2 ) {
100 cksum[0] ^= rtc_config_block[i]; 107 cksum[0] ^= buf[i];
101 cksum[1] ^= rtc_config_block[i+1]; 108 cksum[1] ^= buf[i+1];
102 } 109 }
103 110
104 return (cksum[0] << 8) | cksum[1]; 111 return (cksum[0] << 8) | cksum[1];
@@ -112,12 +119,12 @@ static void init_config_buffer( void )
112 DEBUGF( "init_config_buffer()\n" ); 119 DEBUGF( "init_config_buffer()\n" );
113 120
114 /* reset to 0xff - all unused */ 121 /* reset to 0xff - all unused */
115 memset(rtc_config_block, 0xff, CONFIG_BLOCK_SIZE); 122 memset(config_block, 0xff, CONFIG_BLOCK_SIZE);
116 /* insert header */ 123 /* insert header */
117 rtc_config_block[0] = 'R'; 124 config_block[0] = 'R';
118 rtc_config_block[1] = 'o'; 125 config_block[1] = 'o';
119 rtc_config_block[2] = 'c'; 126 config_block[2] = 'c';
120 rtc_config_block[3] = CONFIG_BLOCK_VERSION; 127 config_block[3] = CONFIG_BLOCK_VERSION;
121} 128}
122 129
123/* 130/*
@@ -126,7 +133,6 @@ static void init_config_buffer( void )
126static int save_config_buffer( void ) 133static int save_config_buffer( void )
127{ 134{
128 unsigned short chksum; 135 unsigned short chksum;
129
130#ifdef HAVE_RTC 136#ifdef HAVE_RTC
131 unsigned int i; 137 unsigned int i;
132#endif 138#endif
@@ -134,36 +140,29 @@ static int save_config_buffer( void )
134 DEBUGF( "save_config_buffer()\n" ); 140 DEBUGF( "save_config_buffer()\n" );
135 141
136 /* update the checksum in the end of the block before saving */ 142 /* update the checksum in the end of the block before saving */
137 chksum = calculate_config_checksum(); 143 chksum = calculate_config_checksum(config_block);
138 rtc_config_block[ CONFIG_BLOCK_SIZE - 2 ] = chksum >> 8; 144 config_block[ RTC_BLOCK_SIZE - 2 ] = chksum >> 8;
139 rtc_config_block[ CONFIG_BLOCK_SIZE - 1 ] = chksum & 0xff; 145 config_block[ RTC_BLOCK_SIZE - 1 ] = chksum & 0xff;
140
141 /* don't save if no changes were made */
142 if ( chksum == last_checksum )
143 return 0;
144 last_checksum = chksum;
145 146
146#ifdef HAVE_RTC 147#ifdef HAVE_RTC
147 /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so 148 /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so
148 that it would write a number of bytes at a time since the RTC chip 149 that it would write a number of bytes at a time since the RTC chip
149 supports that, but this will have to do for now 8-) */ 150 supports that, but this will have to do for now 8-) */
150 for (i=0; i < CONFIG_BLOCK_SIZE; i++ ) { 151 for (i=0; i < RTC_BLOCK_SIZE; i++ ) {
151 int r = rtc_write(0x14+i, rtc_config_block[i]); 152 int r = rtc_write(0x14+i, config_block[i]);
152 if (r) { 153 if (r) {
153 DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n", 14+i, r ); 154 DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n", 14+i, r );
154 return r; 155 return r;
155 } 156 }
156 } 157 }
157 158
158#else 159#endif
159 160
160 if(battery_level_safe() && (fat_startsector()!=0)) 161 if (fat_startsector() != 0)
161 ata_delayed_write( 61, rtc_config_block); 162 ata_delayed_write( 61, config_block);
162 else 163 else
163 return -1; 164 return -1;
164 165
165#endif
166
167 return 0; 166 return 0;
168} 167}
169 168
@@ -173,40 +172,61 @@ static int save_config_buffer( void )
173static int load_config_buffer( void ) 172static int load_config_buffer( void )
174{ 173{
175 unsigned short chksum; 174 unsigned short chksum;
175 bool correct = false;
176 176
177#ifdef HAVE_RTC 177#ifdef HAVE_RTC
178 unsigned int i; 178 unsigned int i;
179 unsigned char rtc_block[RTC_BLOCK_SIZE];
179#endif 180#endif
180 181
181 DEBUGF( "load_config_buffer()\n" ); 182 DEBUGF( "load_config_buffer()\n" );
182 183
184 if (fat_startsector() != 0) {
185 ata_read_sectors( 61, 1, config_block);
186
187 /* calculate the checksum, check it and the header */
188 chksum = calculate_config_checksum(config_block);
189
190 if (config_block[0] == 'R' &&
191 config_block[1] == 'o' &&
192 config_block[2] == 'c' &&
193 config_block[3] == CONFIG_BLOCK_VERSION &&
194 (chksum >> 8) == config_block[RTC_BLOCK_SIZE - 2] &&
195 (chksum & 0xff) == config_block[RTC_BLOCK_SIZE - 1])
196 {
197 DEBUGF( "load_config_buffer: header & checksum test ok\n" );
198 correct = true;
199 }
200 }
201
183#ifdef HAVE_RTC 202#ifdef HAVE_RTC
184 /* FIXME: the same comment applies here as for rtc_write */ 203 /* read rtc block */
185 for (i=0; i < CONFIG_BLOCK_SIZE; i++ ) 204 for (i=0; i < RTC_BLOCK_SIZE; i++ )
186 rtc_config_block[i] = rtc_read(0x14+i); 205 rtc_block[i] = rtc_read(0x14+i);
187#else 206
188 ata_read_sectors( 61, 1, rtc_config_block); 207 chksum = calculate_config_checksum(rtc_block);
189#endif
190
191 /* calculate the checksum, check it and the header */
192 chksum = calculate_config_checksum();
193 208
194 if (rtc_config_block[0] == 'R' && 209 /* if rtc block is ok, use that */
195 rtc_config_block[1] == 'o' && 210 if (rtc_block[0] == 'R' &&
196 rtc_config_block[2] == 'c' && 211 rtc_block[1] == 'o' &&
197 rtc_config_block[3] == CONFIG_BLOCK_VERSION && 212 rtc_block[2] == 'c' &&
198 (chksum >> 8) == rtc_config_block[CONFIG_BLOCK_SIZE - 2] && 213 rtc_block[3] == CONFIG_BLOCK_VERSION &&
199 (chksum & 0xff) == rtc_config_block[CONFIG_BLOCK_SIZE - 1]) 214 (chksum >> 8) == rtc_block[RTC_BLOCK_SIZE - 2] &&
215 (chksum & 0xff) == rtc_block[RTC_BLOCK_SIZE - 1])
200 { 216 {
201 DEBUGF( "load_config_buffer: header & checksum test ok\n" ); 217 memcpy(config_block, rtc_block, RTC_BLOCK_SIZE);
202 last_checksum = chksum; 218 correct = true;
203 return 0; /* header and checksum is valid */
204 } 219 }
220#endif
205 221
206 /* if checksum is not valid, initialize the config buffer to all-unused */ 222 if ( !correct ) {
207 DEBUGF( "load_config_buffer: header & checksum test failed\n" ); 223 /* if checksum is not valid, clear the config buffer */
208 init_config_buffer(); 224 DEBUGF( "load_config_buffer: header & checksum test failed\n" );
209 return 1; 225 init_config_buffer();
226 return -1;
227 }
228
229 return 0;
210} 230}
211 231
212/* 232/*
@@ -218,33 +238,47 @@ int settings_save( void )
218 238
219 /* update the config block buffer with current 239 /* update the config block buffer with current
220 settings and save the block in the RTC */ 240 settings and save the block in the RTC */
221 rtc_config_block[0x4] = (unsigned char)global_settings.volume; 241 config_block[0x4] = (unsigned char)global_settings.volume;
222 rtc_config_block[0x5] = (unsigned char)global_settings.balance; 242 config_block[0x5] = (unsigned char)global_settings.balance;
223 rtc_config_block[0x6] = (unsigned char)global_settings.bass; 243 config_block[0x6] = (unsigned char)global_settings.bass;
224 rtc_config_block[0x7] = (unsigned char)global_settings.treble; 244 config_block[0x7] = (unsigned char)global_settings.treble;
225 rtc_config_block[0x8] = (unsigned char)global_settings.loudness; 245 config_block[0x8] = (unsigned char)global_settings.loudness;
226 rtc_config_block[0x9] = (unsigned char)global_settings.bass_boost; 246 config_block[0x9] = (unsigned char)global_settings.bass_boost;
227 247
228 rtc_config_block[0xa] = (unsigned char)global_settings.contrast; 248 config_block[0xa] = (unsigned char)global_settings.contrast;
229 rtc_config_block[0xb] = (unsigned char)global_settings.backlight; 249 config_block[0xb] = (unsigned char)global_settings.backlight;
230 rtc_config_block[0xc] = (unsigned char)global_settings.poweroff; 250 config_block[0xc] = (unsigned char)global_settings.poweroff;
231 rtc_config_block[0xd] = (unsigned char)global_settings.resume; 251 config_block[0xd] = (unsigned char)global_settings.resume;
232 252
233 rtc_config_block[0xe] = (unsigned char) 253 config_block[0xe] = (unsigned char)
234 ((global_settings.playlist_shuffle & 1) | 254 ((global_settings.playlist_shuffle & 1) |
235 ((global_settings.mp3filter & 1) << 1) | 255 ((global_settings.mp3filter & 1) << 1) |
236 ((global_settings.sort_case & 1) << 2) | 256 ((global_settings.sort_case & 1) << 2) |
237 ((global_settings.discharge & 1) << 3) | 257 ((global_settings.discharge & 1) << 3) |
238 ((global_settings.statusbar & 1) << 4)); 258 ((global_settings.statusbar & 1) << 4));
239 259
240 rtc_config_block[0xf] = (unsigned char) 260 config_block[0xf] = (unsigned char)
241 ((global_settings.scroll_speed << 3) | 261 ((global_settings.scroll_speed << 3) |
242 (global_settings.wps_display & 7)); 262 (global_settings.wps_display & 7));
243 263
244 rtc_config_block[0x11] = (unsigned char)global_settings.avc; 264 config_block[0x10] = (unsigned char)global_settings.ff_rewind;
265 config_block[0x11] = (unsigned char)global_settings.avc;
245 266
246 memcpy(&rtc_config_block[0x24], &global_settings.total_uptime, 4); 267 memcpy(&config_block[0x12], &global_settings.resume_index, 4);
268 memcpy(&config_block[0x16], &global_settings.resume_offset, 4);
269 memcpy(&config_block[0xF8], &global_settings.resume_seed, 4);
270
271 memcpy(&config_block[0x24], &global_settings.total_uptime, 4);
272 strncpy(&config_block[0xFC], global_settings.resume_file, MAX_PATH);
247 273
274 DEBUGF("+Resume file %s\n",global_settings.resume_file);
275 DEBUGF("+Resume index %X offset %X\n",
276 global_settings.resume_index,
277 global_settings.resume_offset);
278 DEBUGF("+Resume shuffle %s seed %X\n",
279 global_settings.playlist_shuffle?"on":"off",
280 global_settings.resume_seed);
281
248 if(save_config_buffer()) 282 if(save_config_buffer())
249 { 283 {
250 lcd_clear_display(); 284 lcd_clear_display();
@@ -277,51 +311,65 @@ void settings_load(void)
277 /* load the buffer from the RTC (resets it to all-unused if the block 311 /* load the buffer from the RTC (resets it to all-unused if the block
278 is invalid) and decode the settings which are set in the block */ 312 is invalid) and decode the settings which are set in the block */
279 if (!load_config_buffer()) { 313 if (!load_config_buffer()) {
280 if (rtc_config_block[0x4] != 0xFF) 314 if (config_block[0x4] != 0xFF)
281 global_settings.volume = rtc_config_block[0x4]; 315 global_settings.volume = config_block[0x4];
282 if (rtc_config_block[0x5] != 0xFF) 316 if (config_block[0x5] != 0xFF)
283 global_settings.balance = rtc_config_block[0x5]; 317 global_settings.balance = config_block[0x5];
284 if (rtc_config_block[0x6] != 0xFF) 318 if (config_block[0x6] != 0xFF)
285 global_settings.bass = rtc_config_block[0x6]; 319 global_settings.bass = config_block[0x6];
286 if (rtc_config_block[0x7] != 0xFF) 320 if (config_block[0x7] != 0xFF)
287 global_settings.treble = rtc_config_block[0x7]; 321 global_settings.treble = config_block[0x7];
288 if (rtc_config_block[0x8] != 0xFF) 322 if (config_block[0x8] != 0xFF)
289 global_settings.loudness = rtc_config_block[0x8]; 323 global_settings.loudness = config_block[0x8];
290 if (rtc_config_block[0x9] != 0xFF) 324 if (config_block[0x9] != 0xFF)
291 global_settings.bass_boost = rtc_config_block[0x9]; 325 global_settings.bass_boost = config_block[0x9];
292 326
293 if (rtc_config_block[0xa] != 0xFF) { 327 if (config_block[0xa] != 0xFF) {
294 global_settings.contrast = rtc_config_block[0xa]; 328 global_settings.contrast = config_block[0xa];
295 if ( global_settings.contrast < MIN_CONTRAST_SETTING ) 329 if ( global_settings.contrast < MIN_CONTRAST_SETTING )
296 global_settings.contrast = DEFAULT_CONTRAST_SETTING; 330 global_settings.contrast = DEFAULT_CONTRAST_SETTING;
297 } 331 }
298 if (rtc_config_block[0xb] != 0xFF) 332 if (config_block[0xb] != 0xFF)
299 global_settings.backlight = rtc_config_block[0xb]; 333 global_settings.backlight = config_block[0xb];
300 if (rtc_config_block[0xc] != 0xFF) 334 if (config_block[0xc] != 0xFF)
301 global_settings.poweroff = rtc_config_block[0xc]; 335 global_settings.poweroff = config_block[0xc];
302 if (rtc_config_block[0xd] != 0xFF) 336 if (config_block[0xd] != 0xFF)
303 global_settings.resume = rtc_config_block[0xd]; 337 global_settings.resume = config_block[0xd];
304 if (rtc_config_block[0xe] != 0xFF) { 338 if (config_block[0xe] != 0xFF) {
305 global_settings.playlist_shuffle = rtc_config_block[0xe] & 1; 339 global_settings.playlist_shuffle = config_block[0xe] & 1;
306 global_settings.mp3filter = (rtc_config_block[0xe] >> 1) & 1; 340 global_settings.mp3filter = (config_block[0xe] >> 1) & 1;
307 global_settings.sort_case = (rtc_config_block[0xe] >> 2) & 1; 341 global_settings.sort_case = (config_block[0xe] >> 2) & 1;
308 global_settings.discharge = (rtc_config_block[0xe] >> 3) & 1; 342 global_settings.discharge = (config_block[0xe] >> 3) & 1;
309 global_settings.statusbar = (rtc_config_block[0xe] >> 4) & 1; 343 global_settings.statusbar = (config_block[0xe] >> 4) & 1;
310 } 344 }
311 345
312 c = rtc_config_block[0xf] >> 3; 346 c = config_block[0xf] >> 3;
313 if (c != 31) 347 if (c != 31)
314 global_settings.scroll_speed = c; 348 global_settings.scroll_speed = c;
315 349
316 c = rtc_config_block[0xf] & 7; 350 c = config_block[0xf] & 7;
317 if (c != 7) 351 if (c != 7)
318 global_settings.wps_display = c; 352 global_settings.wps_display = c;
319 353
320 if (rtc_config_block[0x11] != 0xFF) 354 if (config_block[0x10] != 0xFF)
321 global_settings.avc = rtc_config_block[0x11]; 355 global_settings.ff_rewind = config_block[0x10];
356
357 if (config_block[0x11] != 0xFF)
358 global_settings.avc = config_block[0x11];
359
360 if (config_block[0x12] != 0xFF)
361 memcpy(&global_settings.resume_index, &config_block[0x12], 4);
362
363 if (config_block[0x16] != 0xFF)
364 memcpy(&global_settings.resume_offset, &config_block[0x16], 4);
365
366 memcpy(&global_settings.resume_seed, &config_block[0xF8], 4);
367
368 if (config_block[0x24] != 0xFF)
369 memcpy(&global_settings.total_uptime, &config_block[0x24], 4);
322 370
323 if (rtc_config_block[0x24] != 0xFF) 371 strncpy(global_settings.resume_file, &config_block[0xFC], MAX_PATH);
324 memcpy(&global_settings.total_uptime, &rtc_config_block[0x24], 4); 372 global_settings.resume_file[MAX_PATH]=0;
325 } 373 }
326 lcd_set_contrast(global_settings.contrast); 374 lcd_set_contrast(global_settings.contrast);
327 lcd_scroll_speed(global_settings.scroll_speed); 375 lcd_scroll_speed(global_settings.scroll_speed);
@@ -345,6 +393,7 @@ void settings_reset(void) {
345 global_settings.loudness = mpeg_sound_default(SOUND_LOUDNESS); 393 global_settings.loudness = mpeg_sound_default(SOUND_LOUDNESS);
346 global_settings.bass_boost = mpeg_sound_default(SOUND_SUPERBASS); 394 global_settings.bass_boost = mpeg_sound_default(SOUND_SUPERBASS);
347 global_settings.avc = mpeg_sound_default(SOUND_AVC); 395 global_settings.avc = mpeg_sound_default(SOUND_AVC);
396 global_settings.resume = true;
348 global_settings.contrast = DEFAULT_CONTRAST_SETTING; 397 global_settings.contrast = DEFAULT_CONTRAST_SETTING;
349 global_settings.poweroff = DEFAULT_POWEROFF_SETTING; 398 global_settings.poweroff = DEFAULT_POWEROFF_SETTING;
350 global_settings.backlight = DEFAULT_BACKLIGHT_SETTING; 399 global_settings.backlight = DEFAULT_BACKLIGHT_SETTING;
@@ -358,6 +407,8 @@ void settings_reset(void) {
358 global_settings.total_uptime = 0; 407 global_settings.total_uptime = 0;
359 global_settings.scroll_speed = 8; 408 global_settings.scroll_speed = 8;
360 global_settings.ff_rewind = DEFAULT_FF_REWIND_SETTING; 409 global_settings.ff_rewind = DEFAULT_FF_REWIND_SETTING;
410 global_settings.resume_index = -1;
411 global_settings.resume_offset = -1;
361} 412}
362 413
363 414
diff --git a/apps/settings.h b/apps/settings.h
index ba2a109f1a..f3f6d84327 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -21,6 +21,7 @@
21#define __SETTINGS_H__ 21#define __SETTINGS_H__
22 22
23#include <stdbool.h> 23#include <stdbool.h>
24#include "file.h"
24 25
25/* data structures */ 26/* data structures */
26 27
@@ -49,8 +50,11 @@ struct user_settings
49 50
50 /* resume settings */ 51 /* resume settings */
51 52
52 int resume; /* power-on song resume: 0=no. 1=yes song. 2=yes pl */ 53 bool resume; /* resume option on/off */
53 int track_time; /* number of seconds into the track to resume */ 54 int resume_index; /* index in playlist (-1 for no active resume) */
55 int resume_offset; /* byte offset in mp3 file */
56 int resume_seed; /* random seed for playlist shuffle */
57 unsigned char resume_file[MAX_PATH+1]; /* playlist name (or dir) */
54 58
55 /* misc options */ 59 /* misc options */
56 60
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 0de99b0335..e66d0f389c 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -57,6 +57,11 @@ static void sort_case(void)
57 set_bool( "[Sort case sensitive]", &global_settings.sort_case ); 57 set_bool( "[Sort case sensitive]", &global_settings.sort_case );
58} 58}
59 59
60static void resume(void)
61{
62 set_bool( "[Resume]", &global_settings.resume );
63}
64
60static void backlight_timer(void) 65static void backlight_timer(void)
61{ 66{
62 char* names[] = { "off", "on ", 67 char* names[] = { "off", "on ",
@@ -153,13 +158,13 @@ void settings_menu(void)
153 { "Time/Date", timedate_set }, 158 { "Time/Date", timedate_set },
154#endif 159#endif
155 { "FF/Rewind", ff_rewind }, 160 { "FF/Rewind", ff_rewind },
161 { "Resume", resume },
156 }; 162 };
157 bool old_shuffle = global_settings.playlist_shuffle; 163 bool old_shuffle = global_settings.playlist_shuffle;
158 164
159 m=menu_init( items, sizeof items / sizeof(struct menu_items) ); 165 m=menu_init( items, sizeof items / sizeof(struct menu_items) );
160 menu_run(m); 166 menu_run(m);
161 menu_exit(m); 167 menu_exit(m);
162 settings_save();
163 168
164 if (old_shuffle != global_settings.playlist_shuffle) 169 if (old_shuffle != global_settings.playlist_shuffle)
165 { 170 {
diff --git a/apps/tree.c b/apps/tree.c
index d2660513a5..5312885f19 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -102,12 +102,14 @@ extern unsigned char bitmap_icons_6x8[LastIcon][6];
102#define TREE_EXIT BUTTON_LEFT 102#define TREE_EXIT BUTTON_LEFT
103#define TREE_ENTER BUTTON_RIGHT 103#define TREE_ENTER BUTTON_RIGHT
104#define TREE_MENU BUTTON_F1 104#define TREE_MENU BUTTON_F1
105#define RELEASE_MASK (BUTTON_OFF)
105#else 106#else
106#define TREE_NEXT BUTTON_RIGHT 107#define TREE_NEXT BUTTON_RIGHT
107#define TREE_PREV BUTTON_LEFT 108#define TREE_PREV BUTTON_LEFT
108#define TREE_EXIT BUTTON_STOP 109#define TREE_EXIT BUTTON_STOP
109#define TREE_ENTER BUTTON_PLAY 110#define TREE_ENTER BUTTON_PLAY
110#define TREE_MENU BUTTON_MENU 111#define TREE_MENU BUTTON_MENU
112#define RELEASE_MASK (BUTTON_STOP)
111#endif /* HAVE_RECORDER_KEYPAD */ 113#endif /* HAVE_RECORDER_KEYPAD */
112 114
113#define TREE_ATTR_M3U 0x80 /* unused by FAT attributes */ 115#define TREE_ATTR_M3U 0x80 /* unused by FAT attributes */
@@ -292,6 +294,98 @@ static int showdir(char *path, int start)
292 return filesindir; 294 return filesindir;
293} 295}
294 296
297bool ask_resume(void)
298{
299 lcd_clear_display();
300 lcd_puts(0,0,"Resume?");
301#ifdef HAVE_LCD_CHARCELLS
302 lcd_puts(0,1,"(Play/Stop)");
303#else
304 lcd_puts(0,1,"Play = Yes");
305 lcd_puts(0,2,"Any other = No");
306#endif
307 lcd_update();
308 if (button_get(true) == BUTTON_PLAY)
309 return true;
310 return false;
311}
312
313void start_resume(void)
314{
315 if ( global_settings.resume &&
316 global_settings.resume_index != -1 ) {
317 int len = strlen(global_settings.resume_file);
318
319 DEBUGF("Resume file %s\n",global_settings.resume_file);
320 DEBUGF("Resume index %X offset %X\n",
321 global_settings.resume_index,
322 global_settings.resume_offset);
323 DEBUGF("Resume shuffle %s seed %X\n",
324 global_settings.playlist_shuffle?"on":"off",
325 global_settings.resume_seed);
326
327 /* playlist? */
328 if (!strcasecmp(&global_settings.resume_file[len-4], ".m3u")) {
329 char* slash;
330
331 /* check that the file exists */
332 int fd = open(global_settings.resume_file, O_RDONLY);
333 if(fd<0)
334 return;
335 close(fd);
336
337 if (!ask_resume())
338 return;
339
340 slash = strrchr(global_settings.resume_file,'/');
341 if (slash) {
342 *slash=0;
343 play_list(global_settings.resume_file,
344 slash+1,
345 global_settings.resume_index,
346 global_settings.resume_offset,
347 global_settings.resume_seed );
348 *slash='/';
349 }
350 else {
351 /* check that the dir exists */
352 DIR* dir = opendir(global_settings.resume_file);
353 if(!dir)
354 return;
355 closedir(dir);
356
357 if (!ask_resume())
358 return;
359
360 play_list("/",
361 global_settings.resume_file,
362 global_settings.resume_index,
363 global_settings.resume_offset,
364 global_settings.resume_seed );
365 }
366 }
367 else {
368 int start_index;
369
370 if (!ask_resume())
371 return;
372
373 if (showdir(global_settings.resume_file, 0) < 0 )
374 return;
375 start_index = build_playlist(global_settings.resume_index);
376 play_list(global_settings.resume_file,
377 NULL,
378 start_index,
379 global_settings.resume_offset,
380 global_settings.resume_seed);
381 }
382
383 status_set_playmode(STATUS_PLAY);
384 status_draw();
385 wps_show();
386 }
387}
388
295bool dirbrowse(char *root) 389bool dirbrowse(char *root)
296{ 390{
297 int numentries=0; 391 int numentries=0;
@@ -317,6 +411,9 @@ bool dirbrowse(char *root)
317 tree_max_on_screen = TREE_MAX_ON_SCREEN; 411 tree_max_on_screen = TREE_MAX_ON_SCREEN;
318#endif 412#endif
319 413
414 start_resume();
415 button_set_release(RELEASE_MASK);
416
320 memcpy(currdir,root,sizeof(currdir)); 417 memcpy(currdir,root,sizeof(currdir));
321 numentries = showdir(root, start); 418 numentries = showdir(root, start);
322 if (numentries == -1) 419 if (numentries == -1)
@@ -350,6 +447,7 @@ bool dirbrowse(char *root)
350 restore = true; 447 restore = true;
351 } 448 }
352 break; 449 break;
450
353#ifdef HAVE_RECORDER_KEYPAD 451#ifdef HAVE_RECORDER_KEYPAD
354 case BUTTON_OFF: 452 case BUTTON_OFF:
355 mpeg_stop(); 453 mpeg_stop();
@@ -357,7 +455,15 @@ bool dirbrowse(char *root)
357 status_draw(); 455 status_draw();
358 restore = true; 456 restore = true;
359 break; 457 break;
458
459 case BUTTON_OFF | BUTTON_REL:
460#else
461 case BUTTON_STOP | BUTTON_REL:
360#endif 462#endif
463 global_settings.resume_index = -1;
464 settings_save();
465 break;
466
361 467
362 case TREE_ENTER: 468 case TREE_ENTER:
363#ifdef HAVE_RECORDER_KEYPAD 469#ifdef HAVE_RECORDER_KEYPAD
@@ -383,16 +489,34 @@ bool dirbrowse(char *root)
383 dircursor=0; 489 dircursor=0;
384 start=0; 490 start=0;
385 } else { 491 } else {
492 int seed = current_tick;
386 lcd_stop_scroll(); 493 lcd_stop_scroll();
387 if(dircache[dircursor+start].attr & TREE_ATTR_M3U ) 494 if(dircache[dircursor+start].attr & TREE_ATTR_M3U )
388 { 495 {
496 if ( global_settings.resume )
497 snprintf(global_settings.resume_file,
498 MAX_PATH, "%s/%s",
499 currdir,
500 dircache[dircursor+start].name);
389 play_list(currdir, 501 play_list(currdir,
390 dircache[dircursor+start].name, 0); 502 dircache[dircursor+start].name,
503 0, 0, seed );
391 } 504 }
392 else { 505 else {
506 if ( global_settings.resume )
507 strncpy(global_settings.resume_file,
508 currdir, MAX_PATH);
393 start_index = build_playlist(dircursor+start); 509 start_index = build_playlist(dircursor+start);
394 play_list(currdir, NULL, start_index); 510 play_list(currdir, NULL, start_index, 0, seed);
395 } 511 }
512
513 if ( global_settings.resume ) {
514 global_settings.resume_index = 0;
515 global_settings.resume_offset = 0;
516 global_settings.resume_seed = seed;
517 settings_save();
518 }
519
396 status_set_playmode(STATUS_PLAY); 520 status_set_playmode(STATUS_PLAY);
397 status_draw(); 521 status_draw();
398 lcd_stop_scroll(); 522 lcd_stop_scroll();
@@ -405,6 +529,7 @@ bool dirbrowse(char *root)
405 dirlevel = 0; 529 dirlevel = 0;
406 dircursor = 0; 530 dircursor = 0;
407 start = 0; 531 start = 0;
532 global_settings.resume_index = -1;
408 } 533 }
409 } 534 }
410 restore = true; 535 restore = true;
diff --git a/apps/wps.c b/apps/wps.c
index 240bc96f07..5b30d2ba0e 100644
--- a/apps/wps.c
+++ b/apps/wps.c
@@ -34,6 +34,7 @@
34#include "powermgmt.h" 34#include "powermgmt.h"
35#include "status.h" 35#include "status.h"
36#include "main_menu.h" 36#include "main_menu.h"
37#include "ata.h"
37#ifdef HAVE_LCD_BITMAP 38#ifdef HAVE_LCD_BITMAP
38#include "icons.h" 39#include "icons.h"
39#include "widgets.h" 40#include "widgets.h"
@@ -462,6 +463,13 @@ int wps_show(void)
462 { 463 {
463 mpeg_pause(); 464 mpeg_pause();
464 status_set_playmode(STATUS_PAUSE); 465 status_set_playmode(STATUS_PAUSE);
466 if (global_settings.resume) {
467 status_draw();
468 settings_save();
469#ifndef HAVE_RTC
470 ata_flush();
471#endif
472 }
465 } 473 }
466 else 474 else
467 { 475 {
@@ -577,7 +585,6 @@ int wps_show(void)
577 mpeg_ff_rewind(ff_rewind_count); 585 mpeg_ff_rewind(ff_rewind_count);
578 ff_rewind_count = 0; 586 ff_rewind_count = 0;
579 ff_rewind = false; 587 ff_rewind = false;
580 status_set_playmode(STATUS_PLAY);
581#ifdef HAVE_LCD_CHARCELLS 588#ifdef HAVE_LCD_CHARCELLS
582 draw_screen(id3); 589 draw_screen(id3);
583#endif 590#endif
@@ -589,7 +596,6 @@ int wps_show(void)
589#endif 596#endif
590 { 597 {
591 mpeg_prev(); 598 mpeg_prev();
592 status_set_playmode(STATUS_PLAY);
593 } 599 }
594 } 600 }
595#ifdef HAVE_PLAYER_KEYPAD 601#ifdef HAVE_PLAYER_KEYPAD
@@ -612,7 +618,6 @@ int wps_show(void)
612 mpeg_ff_rewind(ff_rewind_count); 618 mpeg_ff_rewind(ff_rewind_count);
613 ff_rewind_count = 0; 619 ff_rewind_count = 0;
614 ff_rewind = false; 620 ff_rewind = false;
615 status_set_playmode(STATUS_PLAY);
616#ifdef HAVE_LCD_CHARCELLS 621#ifdef HAVE_LCD_CHARCELLS
617 draw_screen(id3); 622 draw_screen(id3);
618#endif 623#endif
@@ -624,7 +629,6 @@ int wps_show(void)
624#endif 629#endif
625 { 630 {
626 mpeg_next(); 631 mpeg_next();
627 status_set_playmode(STATUS_PLAY);
628 } 632 }
629 } 633 }
630#ifdef HAVE_PLAYER_KEYPAD 634#ifdef HAVE_PLAYER_KEYPAD
@@ -862,6 +866,16 @@ int wps_show(void)
862 if (mpeg_is_playing() && id3) 866 if (mpeg_is_playing() && id3)
863 display_file_time(id3->elapsed, id3->length); 867 display_file_time(id3->elapsed, id3->length);
864 868
869 /* save resume data */
870 if ( id3 &&
871 global_settings.resume &&
872 global_settings.resume_offset != id3->offset ) {
873 DEBUGF("R%X,%X (%X)\n",global_settings.resume_offset,id3->offset,id3);
874 global_settings.resume_index = id3->index;
875 global_settings.resume_offset = id3->offset;
876 settings_save();
877 }
878
865 status_draw(); 879 status_draw();
866 break; 880 break;
867 } 881 }