1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002-2007 Björn Stenberg
11 * Copyright (C) 2007-2008 Nicolas Pennequin
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
29 #include "settings_list.h"
30 #include "rbunicode.h"
31 #include "timefuncs.h"
35 #include "powermgmt.h"
38 #ifdef HAVE_LCD_CHARCELLS
42 #include "mp3_playback.h"
46 #ifdef HAVE_LCD_BITMAP
52 #if CONFIG_CODEC == SWCODEC
57 #include "wps_internals.h"
60 static char* get_codectype(const struct mp3entry
* id3
)
62 if (id3
->codectype
< AFMT_NUM_CODECS
) {
63 return (char*)audio_formats
[id3
->codectype
].label
;
69 /* Extract a part from a path.
71 * buf - buffer extract part to.
72 * buf_size - size of buffer.
73 * path - path to extract from.
74 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
75 * parent of parent, etc.
77 * Returns buf if the desired level was found, NULL otherwise.
79 static char* get_dir(char* buf
, int buf_size
, const char* path
, int level
)
85 sep
= path
+ strlen(path
);
100 if (level
|| (last_sep
<= sep
))
103 len
= MIN(last_sep
- sep
, buf_size
- 1);
104 strlcpy(buf
, sep
+ 1, len
+ 1);
108 /* Return the tag found at index i and write its value in buf.
109 The return value is buf if the tag had a value, or NULL if not.
111 intval is used with conditionals/enums: when this function is called,
112 intval should contain the number of options in the conditional/enum.
113 When this function returns, intval is -1 if the tag is non numeric or,
114 if the tag is numeric, *intval is the enum case we want to go to (between 1
115 and the original value of *intval, inclusive).
116 When not treating a conditional/enum, intval should be NULL.
118 const char *get_token_value(struct gui_wps
*gwps
,
119 struct wps_token
*token
,
120 char *buf
, int buf_size
,
126 struct wps_data
*data
= gwps
->data
;
127 struct wps_state
*state
= gwps
->state
;
132 struct mp3entry
*id3
;
143 struct tm
* tm
= NULL
;
145 /* if the token is an RTC one, update the time
146 and do the necessary checks */
147 if (token
->type
>= WPS_TOKENS_RTC_BEGIN
148 && token
->type
<= WPS_TOKENS_RTC_END
)
166 case WPS_TOKEN_CHARACTER
:
167 if (token
->value
.c
== '\n')
169 return &(token
->value
.c
);
171 case WPS_TOKEN_STRING
:
172 return (char*)token
->value
.data
;
174 case WPS_TOKEN_TRACK_TIME_ELAPSED
:
175 format_time(buf
, buf_size
,
176 id3
->elapsed
+ state
->ff_rewind_count
);
179 case WPS_TOKEN_TRACK_TIME_REMAINING
:
180 format_time(buf
, buf_size
,
181 id3
->length
- id3
->elapsed
-
182 state
->ff_rewind_count
);
185 case WPS_TOKEN_TRACK_LENGTH
:
186 format_time(buf
, buf_size
, id3
->length
);
189 case WPS_TOKEN_PLAYLIST_ENTRIES
:
190 snprintf(buf
, buf_size
, "%d", playlist_amount());
193 case WPS_TOKEN_PLAYLIST_NAME
:
194 return playlist_name(NULL
, buf
, buf_size
);
196 case WPS_TOKEN_PLAYLIST_POSITION
:
197 snprintf(buf
, buf_size
, "%d", playlist_get_display_index());
200 case WPS_TOKEN_PLAYLIST_SHUFFLE
:
201 if ( global_settings
.playlist_shuffle
)
207 case WPS_TOKEN_VOLUME
:
208 snprintf(buf
, buf_size
, "%d", global_settings
.volume
);
211 if (global_settings
.volume
== sound_min(SOUND_VOLUME
))
215 else if (global_settings
.volume
== 0)
219 else if (global_settings
.volume
> 0)
225 *intval
= (limit
- 3) * (global_settings
.volume
226 - sound_min(SOUND_VOLUME
) - 1)
227 / (-1 - sound_min(SOUND_VOLUME
)) + 2;
232 case WPS_TOKEN_TRACK_ELAPSED_PERCENT
:
233 if (id3
->length
<= 0)
238 *intval
= limit
* (id3
->elapsed
+ state
->ff_rewind_count
)
241 snprintf(buf
, buf_size
, "%d",
242 100*(id3
->elapsed
+ state
->ff_rewind_count
) / id3
->length
);
245 case WPS_TOKEN_METADATA_ARTIST
:
248 case WPS_TOKEN_METADATA_COMPOSER
:
249 return id3
->composer
;
251 case WPS_TOKEN_METADATA_ALBUM
:
254 case WPS_TOKEN_METADATA_ALBUM_ARTIST
:
255 return id3
->albumartist
;
257 case WPS_TOKEN_METADATA_GROUPING
:
258 return id3
->grouping
;
260 case WPS_TOKEN_METADATA_GENRE
:
261 return id3
->genre_string
;
263 case WPS_TOKEN_METADATA_DISC_NUMBER
:
264 if (id3
->disc_string
)
265 return id3
->disc_string
;
267 snprintf(buf
, buf_size
, "%d", id3
->discnum
);
272 case WPS_TOKEN_METADATA_TRACK_NUMBER
:
273 if (id3
->track_string
)
274 return id3
->track_string
;
277 snprintf(buf
, buf_size
, "%d", id3
->tracknum
);
282 case WPS_TOKEN_METADATA_TRACK_TITLE
:
285 case WPS_TOKEN_METADATA_VERSION
:
286 switch (id3
->id3version
)
307 case WPS_TOKEN_METADATA_YEAR
:
308 if( id3
->year_string
)
309 return id3
->year_string
;
312 snprintf(buf
, buf_size
, "%d", id3
->year
);
317 case WPS_TOKEN_METADATA_COMMENT
:
321 case WPS_TOKEN_ALBUMART_FOUND
:
322 if (data
->albumart
&& audio_current_aa_hid() >= 0) {
327 case WPS_TOKEN_ALBUMART_DISPLAY
:
330 data
->albumart
->draw
= true;
334 case WPS_TOKEN_FILE_BITRATE
:
336 snprintf(buf
, buf_size
, "%d", id3
->bitrate
);
341 case WPS_TOKEN_FILE_CODEC
:
344 if(id3
->codectype
== AFMT_UNKNOWN
)
345 *intval
= AFMT_NUM_CODECS
;
347 *intval
= id3
->codectype
;
349 return get_codectype(id3
);
351 case WPS_TOKEN_FILE_FREQUENCY
:
352 snprintf(buf
, buf_size
, "%ld", id3
->frequency
);
355 case WPS_TOKEN_FILE_FREQUENCY_KHZ
:
356 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
357 if ((id3
->frequency
% 1000) < 100)
358 snprintf(buf
, buf_size
, "%ld", id3
->frequency
/ 1000);
360 snprintf(buf
, buf_size
, "%ld.%d",
361 id3
->frequency
/ 1000,
362 (id3
->frequency
% 1000) / 100);
365 case WPS_TOKEN_FILE_NAME
:
366 if (get_dir(buf
, buf_size
, id3
->path
, 0)) {
367 /* Remove extension */
368 char* sep
= strrchr(buf
, '.');
378 case WPS_TOKEN_FILE_NAME_WITH_EXTENSION
:
379 return get_dir(buf
, buf_size
, id3
->path
, 0);
381 case WPS_TOKEN_FILE_PATH
:
384 case WPS_TOKEN_FILE_SIZE
:
385 snprintf(buf
, buf_size
, "%ld", id3
->filesize
/ 1024);
388 case WPS_TOKEN_FILE_VBR
:
389 return id3
->vbr
? "(avg)" : NULL
;
391 case WPS_TOKEN_FILE_DIRECTORY
:
392 return get_dir(buf
, buf_size
, id3
->path
, token
->value
.i
);
394 case WPS_TOKEN_BATTERY_PERCENT
:
396 int l
= battery_level();
400 limit
= MAX(limit
, 2);
402 /* First enum is used for "unknown level". */
403 *intval
= (limit
- 1) * l
/ 100 + 2;
410 snprintf(buf
, buf_size
, "%d", l
);
417 case WPS_TOKEN_BATTERY_VOLTS
:
419 unsigned int v
= battery_voltage();
420 snprintf(buf
, buf_size
, "%d.%02d", v
/ 1000, (v
% 1000) / 10);
424 case WPS_TOKEN_BATTERY_TIME
:
426 int t
= battery_time();
428 snprintf(buf
, buf_size
, "%dh %dm", t
/ 60, t
% 60);
435 case WPS_TOKEN_BATTERY_CHARGER_CONNECTED
:
437 if(charger_input_state
==CHARGER
)
443 #if CONFIG_CHARGING >= CHARGING_MONITOR
444 case WPS_TOKEN_BATTERY_CHARGING
:
446 if (charge_state
== CHARGING
|| charge_state
== TOPOFF
) {
453 case WPS_TOKEN_BATTERY_SLEEPTIME
:
455 if (get_sleep_timer() == 0)
459 format_time(buf
, buf_size
, get_sleep_timer() * 1000);
464 case WPS_TOKEN_PLAYBACK_STATUS
:
466 int status
= audio_status();
468 if (status
== AUDIO_STATUS_PLAY
)
470 if (is_wps_fading() ||
471 (status
& AUDIO_STATUS_PAUSE
&& !status_get_ffmode()))
473 if (status_get_ffmode() == STATUS_FASTFORWARD
)
475 if (status_get_ffmode() == STATUS_FASTBACKWARD
)
482 snprintf(buf
, buf_size
, "%d", mode
-1);
486 case WPS_TOKEN_REPEAT_MODE
:
488 *intval
= global_settings
.repeat_mode
+ 1;
489 snprintf(buf
, buf_size
, "%d", global_settings
.repeat_mode
);
492 case WPS_TOKEN_RTC_PRESENT
:
500 case WPS_TOKEN_RTC_12HOUR_CFG
:
502 *intval
= global_settings
.timeformat
+ 1;
503 snprintf(buf
, buf_size
, "%d", global_settings
.timeformat
);
506 case WPS_TOKEN_RTC_DAY_OF_MONTH
:
507 /* d: day of month (01..31) */
508 snprintf(buf
, buf_size
, "%02d", tm
->tm_mday
);
511 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
:
512 /* e: day of month, blank padded ( 1..31) */
513 snprintf(buf
, buf_size
, "%2d", tm
->tm_mday
);
516 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
:
517 /* H: hour (00..23) */
518 snprintf(buf
, buf_size
, "%02d", tm
->tm_hour
);
521 case WPS_TOKEN_RTC_HOUR_24
:
522 /* k: hour ( 0..23) */
523 snprintf(buf
, buf_size
, "%2d", tm
->tm_hour
);
526 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
:
527 /* I: hour (01..12) */
528 snprintf(buf
, buf_size
, "%02d",
529 (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12);
532 case WPS_TOKEN_RTC_HOUR_12
:
533 /* l: hour ( 1..12) */
534 snprintf(buf
, buf_size
, "%2d",
535 (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12);
538 case WPS_TOKEN_RTC_MONTH
:
539 /* m: month (01..12) */
541 *intval
= tm
->tm_mon
+ 1;
542 snprintf(buf
, buf_size
, "%02d", tm
->tm_mon
+ 1);
545 case WPS_TOKEN_RTC_MINUTE
:
546 /* M: minute (00..59) */
547 snprintf(buf
, buf_size
, "%02d", tm
->tm_min
);
550 case WPS_TOKEN_RTC_SECOND
:
551 /* S: second (00..59) */
552 snprintf(buf
, buf_size
, "%02d", tm
->tm_sec
);
555 case WPS_TOKEN_RTC_YEAR_2_DIGITS
:
556 /* y: last two digits of year (00..99) */
557 snprintf(buf
, buf_size
, "%02d", tm
->tm_year
% 100);
560 case WPS_TOKEN_RTC_YEAR_4_DIGITS
:
561 /* Y: year (1970...) */
562 snprintf(buf
, buf_size
, "%04d", tm
->tm_year
+ 1900);
565 case WPS_TOKEN_RTC_AM_PM_UPPER
:
566 /* p: upper case AM or PM indicator */
567 return tm
->tm_hour
/12 == 0 ? "AM" : "PM";
569 case WPS_TOKEN_RTC_AM_PM_LOWER
:
570 /* P: lower case am or pm indicator */
571 return tm
->tm_hour
/12 == 0 ? "am" : "pm";
573 case WPS_TOKEN_RTC_WEEKDAY_NAME
:
574 /* a: abbreviated weekday name (Sun..Sat) */
575 return str(LANG_WEEKDAY_SUNDAY
+ tm
->tm_wday
);
577 case WPS_TOKEN_RTC_MONTH_NAME
:
578 /* b: abbreviated month name (Jan..Dec) */
579 return str(LANG_MONTH_JANUARY
+ tm
->tm_mon
);
581 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
:
582 /* u: day of week (1..7); 1 is Monday */
584 *intval
= (tm
->tm_wday
== 0) ? 7 : tm
->tm_wday
;
585 snprintf(buf
, buf_size
, "%1d", tm
->tm_wday
+ 1);
588 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
:
589 /* w: day of week (0..6); 0 is Sunday */
591 *intval
= tm
->tm_wday
+ 1;
592 snprintf(buf
, buf_size
, "%1d", tm
->tm_wday
);
595 case WPS_TOKEN_RTC_DAY_OF_MONTH
:
596 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
:
597 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
:
598 case WPS_TOKEN_RTC_HOUR_24
:
599 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
:
600 case WPS_TOKEN_RTC_HOUR_12
:
601 case WPS_TOKEN_RTC_MONTH
:
602 case WPS_TOKEN_RTC_MINUTE
:
603 case WPS_TOKEN_RTC_SECOND
:
604 case WPS_TOKEN_RTC_AM_PM_UPPER
:
605 case WPS_TOKEN_RTC_AM_PM_LOWER
:
606 case WPS_TOKEN_RTC_YEAR_2_DIGITS
:
608 case WPS_TOKEN_RTC_YEAR_4_DIGITS
:
610 case WPS_TOKEN_RTC_WEEKDAY_NAME
:
611 case WPS_TOKEN_RTC_MONTH_NAME
:
613 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
:
614 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
:
618 #ifdef HAVE_LCD_CHARCELLS
619 case WPS_TOKEN_PROGRESSBAR
:
621 char *end
= utf8encode(data
->wps_progress_pat
[0], buf
);
626 case WPS_TOKEN_PLAYER_PROGRESSBAR
:
629 /* we need 11 characters (full line) for
631 strlcpy(buf
, " ", buf_size
);
635 /* Tell the user if we have an OldPlayer */
636 strlcpy(buf
, " <Old LCD> ", buf_size
);
642 case WPS_TOKEN_DATABASE_PLAYCOUNT
:
644 *intval
= id3
->playcount
+ 1;
646 snprintf(buf
, buf_size
, "%ld", id3
->playcount
);
649 case WPS_TOKEN_DATABASE_RATING
:
651 *intval
= id3
->rating
+ 1;
653 snprintf(buf
, buf_size
, "%d", id3
->rating
);
656 case WPS_TOKEN_DATABASE_AUTOSCORE
:
658 *intval
= id3
->score
+ 1;
660 snprintf(buf
, buf_size
, "%d", id3
->score
);
664 #if (CONFIG_CODEC == SWCODEC)
665 case WPS_TOKEN_CROSSFADE
:
667 *intval
= global_settings
.crossfade
+ 1;
668 snprintf(buf
, buf_size
, "%d", global_settings
.crossfade
);
671 case WPS_TOKEN_REPLAYGAIN
:
675 if (global_settings
.replaygain_type
== REPLAYGAIN_OFF
)
680 get_replaygain_mode(id3
->track_gain_string
!= NULL
,
681 id3
->album_gain_string
!= NULL
);
683 val
= 6; /* no tag */
687 if (global_settings
.replaygain_type
== REPLAYGAIN_SHUFFLE
)
702 strlcpy(buf
, id3
->track_gain_string
, buf_size
);
706 strlcpy(buf
, id3
->album_gain_string
, buf_size
);
711 #endif /* (CONFIG_CODEC == SWCODEC) */
713 #if (CONFIG_CODEC != MAS3507D)
714 case WPS_TOKEN_SOUND_PITCH
:
716 int val
= sound_get_pitch();
717 snprintf(buf
, buf_size
, "%d.%d",
723 case WPS_TOKEN_MAIN_HOLD
:
724 #ifdef HAS_BUTTON_HOLD
727 if (is_keys_locked())
728 #endif /*hold switch or softlock*/
733 #ifdef HAS_REMOTE_BUTTON_HOLD
734 case WPS_TOKEN_REMOTE_HOLD
:
735 if (remote_button_hold())
741 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
742 case WPS_TOKEN_VLED_HDD
:
748 case WPS_TOKEN_BUTTON_VOLUME
:
749 if (data
->button_time_volume
&&
750 TIME_BEFORE(current_tick
, data
->button_time_volume
+
751 token
->value
.i
* TIMEOUT_UNIT
))
754 case WPS_TOKEN_LASTTOUCH
:
755 #ifdef HAVE_TOUCHSCREEN
756 if (TIME_BEFORE(current_tick
, token
->value
.i
* TIMEOUT_UNIT
+
757 touchscreen_last_touch()))
762 case WPS_TOKEN_SETTING
:
766 /* Handle contionals */
767 const struct settings_list
*s
= settings
+token
->value
.i
;
768 switch (s
->flags
&F_T_MASK
)
773 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
774 /* shouldn't overflow since colors are stored
776 * but this is pretty useless anyway */
777 *intval
= *(int*)s
->setting
+ 1;
778 else if (s
->cfg_vals
== NULL
)
779 /* %?St|name|<1st choice|2nd choice|...> */
780 *intval
= (*(int*)s
->setting
-s
->int_setting
->min
)
781 /s
->int_setting
->step
+ 1;
783 /* %?St|name|<1st choice|2nd choice|...> */
784 /* Not sure about this one. cfg_name/vals are
785 * indexed from 0 right? */
786 *intval
= *(int*)s
->setting
+ 1;
789 /* %?St|name|<if true|if false> */
790 *intval
= *(bool*)s
->setting
?1:2;
793 /* %?St|name|<if non empty string|if empty>
794 * The string's emptyness discards the setting's
795 * prefix and suffix */
796 *intval
= ((char*)s
->setting
)[0]?1:2;
799 /* This shouldn't happen ... but you never know */
804 cfg_to_string(token
->value
.i
,buf
,buf_size
);