diff options
author | Björn Stenberg <bjorn@haxx.se> | 2002-08-16 14:41:47 +0000 |
---|---|---|
committer | Björn Stenberg <bjorn@haxx.se> | 2002-08-16 14:41:47 +0000 |
commit | 6224cdb16677cae7b65b0598eec3381a6fb6a4aa (patch) | |
tree | 9ad9b39557492606c853e7f14c359bca5e0a3b65 /apps | |
parent | 085e77467565aba251c31721e92bc7ebd7baa61f (diff) | |
download | rockbox-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.c | 16 | ||||
-rw-r--r-- | apps/playlist.h | 5 | ||||
-rw-r--r-- | apps/settings.c | 247 | ||||
-rw-r--r-- | apps/settings.h | 8 | ||||
-rw-r--r-- | apps/settings_menu.c | 7 | ||||
-rw-r--r-- | apps/tree.c | 129 | ||||
-rw-r--r-- | apps/wps.c | 22 |
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 | ||
69 | char* playlist_next(int steps) | 69 | char* 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 | ||
168 | void play_list(char *dir, char *file, int start_index) | 170 | void 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 | |||
40 | extern playlist_info_t playlist; | 40 | extern playlist_info_t playlist; |
41 | extern bool playlist_shuffle; | 41 | extern bool playlist_shuffle; |
42 | 42 | ||
43 | void play_list(char *dir, char *file, int start_index); | 43 | void play_list(char *dir, char *file, int start_index, |
44 | char* playlist_next(int steps); | 44 | int start_offset, int random_seed ); |
45 | char* playlist_next(int steps, int* id); | ||
45 | void randomise_playlist( unsigned int seed ); | 46 | void randomise_playlist( unsigned int seed ); |
46 | void sort_playlist(void); | 47 | void sort_playlist(void); |
47 | void empty_playlist(void); | 48 | void 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 | ||
38 | struct user_settings global_settings; | 38 | struct user_settings global_settings; |
39 | 39 | ||
40 | static 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 | |||
64 | 0x0f 0x23 <scroll speed & WPS display byte> | 63 | 0x0f 0x23 <scroll speed & WPS display byte> |
65 | 0x10 0x24 <playlist options byte> | 64 | 0x10 0x24 <playlist options byte> |
66 | 0x11 0x25 <AVC byte> | 65 | 0x11 0x25 <AVC byte> |
66 | 0x12 0x26 <(int) Resume playlist index, or -1 if no playlist resume> | ||
67 | 0x16 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 | |||
81 | needed. Memory locations not used by a given version should not be | 82 | needed. Memory locations not used by a given version should not be |
82 | modified unless the header & checksum test fails. | 83 | modified unless the header & checksum test fails. |
83 | 84 | ||
85 | |||
86 | Rest of config block, only saved to disk: | ||
87 | |||
88 | 0xF8 (int) Playlist shuffle seed | ||
89 | 0xFC (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" |
87 | static unsigned char rtc_config_block[CONFIG_BLOCK_SIZE]; | 94 | static 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 | ||
93 | static unsigned short calculate_config_checksum(void) | 100 | static 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 ) | |||
126 | static int save_config_buffer( void ) | 133 | static 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 ) | |||
173 | static int load_config_buffer( void ) | 172 | static 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 | ||
60 | static void resume(void) | ||
61 | { | ||
62 | set_bool( "[Resume]", &global_settings.resume ); | ||
63 | } | ||
64 | |||
60 | static void backlight_timer(void) | 65 | static 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 | ||
297 | bool 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 | |||
313 | void 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 | |||
295 | bool dirbrowse(char *root) | 389 | bool 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 | } |