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_TRANSLATEDSTRING
:
175 return (char*)P2STR(ID2P(token
->value
.i
));
177 case WPS_TOKEN_TRACK_TIME_ELAPSED
:
178 format_time(buf
, buf_size
,
179 id3
->elapsed
+ state
->ff_rewind_count
);
182 case WPS_TOKEN_TRACK_TIME_REMAINING
:
183 format_time(buf
, buf_size
,
184 id3
->length
- id3
->elapsed
-
185 state
->ff_rewind_count
);
188 case WPS_TOKEN_TRACK_LENGTH
:
189 format_time(buf
, buf_size
, id3
->length
);
192 case WPS_TOKEN_PLAYLIST_ENTRIES
:
193 snprintf(buf
, buf_size
, "%d", playlist_amount());
196 case WPS_TOKEN_PLAYLIST_NAME
:
197 return playlist_name(NULL
, buf
, buf_size
);
199 case WPS_TOKEN_PLAYLIST_POSITION
:
200 snprintf(buf
, buf_size
, "%d", playlist_get_display_index());
203 case WPS_TOKEN_PLAYLIST_SHUFFLE
:
204 if ( global_settings
.playlist_shuffle
)
210 case WPS_TOKEN_VOLUME
:
211 snprintf(buf
, buf_size
, "%d", global_settings
.volume
);
214 if (global_settings
.volume
== sound_min(SOUND_VOLUME
))
218 else if (global_settings
.volume
== 0)
222 else if (global_settings
.volume
> 0)
228 *intval
= (limit
- 3) * (global_settings
.volume
229 - sound_min(SOUND_VOLUME
) - 1)
230 / (-1 - sound_min(SOUND_VOLUME
)) + 2;
235 case WPS_TOKEN_TRACK_ELAPSED_PERCENT
:
236 if (id3
->length
<= 0)
241 *intval
= limit
* (id3
->elapsed
+ state
->ff_rewind_count
)
244 snprintf(buf
, buf_size
, "%d",
245 100*(id3
->elapsed
+ state
->ff_rewind_count
) / id3
->length
);
248 case WPS_TOKEN_METADATA_ARTIST
:
251 case WPS_TOKEN_METADATA_COMPOSER
:
252 return id3
->composer
;
254 case WPS_TOKEN_METADATA_ALBUM
:
257 case WPS_TOKEN_METADATA_ALBUM_ARTIST
:
258 return id3
->albumartist
;
260 case WPS_TOKEN_METADATA_GROUPING
:
261 return id3
->grouping
;
263 case WPS_TOKEN_METADATA_GENRE
:
264 return id3
->genre_string
;
266 case WPS_TOKEN_METADATA_DISC_NUMBER
:
267 if (id3
->disc_string
)
268 return id3
->disc_string
;
270 snprintf(buf
, buf_size
, "%d", id3
->discnum
);
275 case WPS_TOKEN_METADATA_TRACK_NUMBER
:
276 if (id3
->track_string
)
277 return id3
->track_string
;
280 snprintf(buf
, buf_size
, "%d", id3
->tracknum
);
285 case WPS_TOKEN_METADATA_TRACK_TITLE
:
288 case WPS_TOKEN_METADATA_VERSION
:
289 switch (id3
->id3version
)
310 case WPS_TOKEN_METADATA_YEAR
:
311 if( id3
->year_string
)
312 return id3
->year_string
;
315 snprintf(buf
, buf_size
, "%d", id3
->year
);
320 case WPS_TOKEN_METADATA_COMMENT
:
324 case WPS_TOKEN_ALBUMART_FOUND
:
325 if (data
->albumart
&& audio_current_aa_hid() >= 0) {
330 case WPS_TOKEN_ALBUMART_DISPLAY
:
333 if (!data
->albumart
->draw
)
334 data
->albumart
->draw
= true;
338 case WPS_TOKEN_FILE_BITRATE
:
340 snprintf(buf
, buf_size
, "%d", id3
->bitrate
);
345 case WPS_TOKEN_FILE_CODEC
:
348 if(id3
->codectype
== AFMT_UNKNOWN
)
349 *intval
= AFMT_NUM_CODECS
;
351 *intval
= id3
->codectype
;
353 return get_codectype(id3
);
355 case WPS_TOKEN_FILE_FREQUENCY
:
356 snprintf(buf
, buf_size
, "%ld", id3
->frequency
);
359 case WPS_TOKEN_FILE_FREQUENCY_KHZ
:
360 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
361 if ((id3
->frequency
% 1000) < 100)
362 snprintf(buf
, buf_size
, "%ld", id3
->frequency
/ 1000);
364 snprintf(buf
, buf_size
, "%ld.%d",
365 id3
->frequency
/ 1000,
366 (id3
->frequency
% 1000) / 100);
369 case WPS_TOKEN_FILE_NAME
:
370 if (get_dir(buf
, buf_size
, id3
->path
, 0)) {
371 /* Remove extension */
372 char* sep
= strrchr(buf
, '.');
382 case WPS_TOKEN_FILE_NAME_WITH_EXTENSION
:
383 return get_dir(buf
, buf_size
, id3
->path
, 0);
385 case WPS_TOKEN_FILE_PATH
:
388 case WPS_TOKEN_FILE_SIZE
:
389 snprintf(buf
, buf_size
, "%ld", id3
->filesize
/ 1024);
392 case WPS_TOKEN_FILE_VBR
:
393 return id3
->vbr
? "(avg)" : NULL
;
395 case WPS_TOKEN_FILE_DIRECTORY
:
396 return get_dir(buf
, buf_size
, id3
->path
, token
->value
.i
);
398 case WPS_TOKEN_BATTERY_PERCENT
:
400 int l
= battery_level();
404 limit
= MAX(limit
, 2);
406 /* First enum is used for "unknown level". */
407 *intval
= (limit
- 1) * l
/ 100 + 2;
414 snprintf(buf
, buf_size
, "%d", l
);
421 case WPS_TOKEN_BATTERY_VOLTS
:
423 unsigned int v
= battery_voltage();
424 snprintf(buf
, buf_size
, "%d.%02d", v
/ 1000, (v
% 1000) / 10);
428 case WPS_TOKEN_BATTERY_TIME
:
430 int t
= battery_time();
432 snprintf(buf
, buf_size
, "%dh %dm", t
/ 60, t
% 60);
439 case WPS_TOKEN_BATTERY_CHARGER_CONNECTED
:
441 if(charger_input_state
==CHARGER
)
447 #if CONFIG_CHARGING >= CHARGING_MONITOR
448 case WPS_TOKEN_BATTERY_CHARGING
:
450 if (charge_state
== CHARGING
|| charge_state
== TOPOFF
) {
457 case WPS_TOKEN_BATTERY_SLEEPTIME
:
459 if (get_sleep_timer() == 0)
463 format_time(buf
, buf_size
, get_sleep_timer() * 1000);
468 case WPS_TOKEN_PLAYBACK_STATUS
:
470 int status
= audio_status();
472 if (status
== AUDIO_STATUS_PLAY
)
474 if (is_wps_fading() ||
475 (status
& AUDIO_STATUS_PAUSE
&& !status_get_ffmode()))
477 if (status_get_ffmode() == STATUS_FASTFORWARD
)
479 if (status_get_ffmode() == STATUS_FASTBACKWARD
)
486 snprintf(buf
, buf_size
, "%d", mode
-1);
490 case WPS_TOKEN_REPEAT_MODE
:
492 *intval
= global_settings
.repeat_mode
+ 1;
493 snprintf(buf
, buf_size
, "%d", global_settings
.repeat_mode
);
496 case WPS_TOKEN_RTC_PRESENT
:
504 case WPS_TOKEN_RTC_12HOUR_CFG
:
506 *intval
= global_settings
.timeformat
+ 1;
507 snprintf(buf
, buf_size
, "%d", global_settings
.timeformat
);
510 case WPS_TOKEN_RTC_DAY_OF_MONTH
:
511 /* d: day of month (01..31) */
512 snprintf(buf
, buf_size
, "%02d", tm
->tm_mday
);
515 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
:
516 /* e: day of month, blank padded ( 1..31) */
517 snprintf(buf
, buf_size
, "%2d", tm
->tm_mday
);
520 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
:
521 /* H: hour (00..23) */
522 snprintf(buf
, buf_size
, "%02d", tm
->tm_hour
);
525 case WPS_TOKEN_RTC_HOUR_24
:
526 /* k: hour ( 0..23) */
527 snprintf(buf
, buf_size
, "%2d", tm
->tm_hour
);
530 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
:
531 /* I: hour (01..12) */
532 snprintf(buf
, buf_size
, "%02d",
533 (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12);
536 case WPS_TOKEN_RTC_HOUR_12
:
537 /* l: hour ( 1..12) */
538 snprintf(buf
, buf_size
, "%2d",
539 (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12);
542 case WPS_TOKEN_RTC_MONTH
:
543 /* m: month (01..12) */
545 *intval
= tm
->tm_mon
+ 1;
546 snprintf(buf
, buf_size
, "%02d", tm
->tm_mon
+ 1);
549 case WPS_TOKEN_RTC_MINUTE
:
550 /* M: minute (00..59) */
551 snprintf(buf
, buf_size
, "%02d", tm
->tm_min
);
554 case WPS_TOKEN_RTC_SECOND
:
555 /* S: second (00..59) */
556 snprintf(buf
, buf_size
, "%02d", tm
->tm_sec
);
559 case WPS_TOKEN_RTC_YEAR_2_DIGITS
:
560 /* y: last two digits of year (00..99) */
561 snprintf(buf
, buf_size
, "%02d", tm
->tm_year
% 100);
564 case WPS_TOKEN_RTC_YEAR_4_DIGITS
:
565 /* Y: year (1970...) */
566 snprintf(buf
, buf_size
, "%04d", tm
->tm_year
+ 1900);
569 case WPS_TOKEN_RTC_AM_PM_UPPER
:
570 /* p: upper case AM or PM indicator */
571 return tm
->tm_hour
/12 == 0 ? "AM" : "PM";
573 case WPS_TOKEN_RTC_AM_PM_LOWER
:
574 /* P: lower case am or pm indicator */
575 return tm
->tm_hour
/12 == 0 ? "am" : "pm";
577 case WPS_TOKEN_RTC_WEEKDAY_NAME
:
578 /* a: abbreviated weekday name (Sun..Sat) */
579 return str(LANG_WEEKDAY_SUNDAY
+ tm
->tm_wday
);
581 case WPS_TOKEN_RTC_MONTH_NAME
:
582 /* b: abbreviated month name (Jan..Dec) */
583 return str(LANG_MONTH_JANUARY
+ tm
->tm_mon
);
585 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
:
586 /* u: day of week (1..7); 1 is Monday */
588 *intval
= (tm
->tm_wday
== 0) ? 7 : tm
->tm_wday
;
589 snprintf(buf
, buf_size
, "%1d", tm
->tm_wday
+ 1);
592 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
:
593 /* w: day of week (0..6); 0 is Sunday */
595 *intval
= tm
->tm_wday
+ 1;
596 snprintf(buf
, buf_size
, "%1d", tm
->tm_wday
);
599 case WPS_TOKEN_RTC_DAY_OF_MONTH
:
600 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
:
601 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
:
602 case WPS_TOKEN_RTC_HOUR_24
:
603 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
:
604 case WPS_TOKEN_RTC_HOUR_12
:
605 case WPS_TOKEN_RTC_MONTH
:
606 case WPS_TOKEN_RTC_MINUTE
:
607 case WPS_TOKEN_RTC_SECOND
:
608 case WPS_TOKEN_RTC_AM_PM_UPPER
:
609 case WPS_TOKEN_RTC_AM_PM_LOWER
:
610 case WPS_TOKEN_RTC_YEAR_2_DIGITS
:
612 case WPS_TOKEN_RTC_YEAR_4_DIGITS
:
614 case WPS_TOKEN_RTC_WEEKDAY_NAME
:
615 case WPS_TOKEN_RTC_MONTH_NAME
:
617 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
:
618 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
:
622 #ifdef HAVE_LCD_CHARCELLS
623 case WPS_TOKEN_PROGRESSBAR
:
625 char *end
= utf8encode(data
->wps_progress_pat
[0], buf
);
630 case WPS_TOKEN_PLAYER_PROGRESSBAR
:
633 /* we need 11 characters (full line) for
635 strlcpy(buf
, " ", buf_size
);
639 /* Tell the user if we have an OldPlayer */
640 strlcpy(buf
, " <Old LCD> ", buf_size
);
646 case WPS_TOKEN_DATABASE_PLAYCOUNT
:
648 *intval
= id3
->playcount
+ 1;
650 snprintf(buf
, buf_size
, "%ld", id3
->playcount
);
653 case WPS_TOKEN_DATABASE_RATING
:
655 *intval
= id3
->rating
+ 1;
657 snprintf(buf
, buf_size
, "%d", id3
->rating
);
660 case WPS_TOKEN_DATABASE_AUTOSCORE
:
662 *intval
= id3
->score
+ 1;
664 snprintf(buf
, buf_size
, "%d", id3
->score
);
668 #if (CONFIG_CODEC == SWCODEC)
669 case WPS_TOKEN_CROSSFADE
:
671 *intval
= global_settings
.crossfade
+ 1;
672 snprintf(buf
, buf_size
, "%d", global_settings
.crossfade
);
675 case WPS_TOKEN_REPLAYGAIN
:
679 if (global_settings
.replaygain_type
== REPLAYGAIN_OFF
)
684 get_replaygain_mode(id3
->track_gain_string
!= NULL
,
685 id3
->album_gain_string
!= NULL
);
687 val
= 6; /* no tag */
691 if (global_settings
.replaygain_type
== REPLAYGAIN_SHUFFLE
)
706 strlcpy(buf
, id3
->track_gain_string
, buf_size
);
710 strlcpy(buf
, id3
->album_gain_string
, buf_size
);
715 #endif /* (CONFIG_CODEC == SWCODEC) */
717 #if (CONFIG_CODEC != MAS3507D)
718 case WPS_TOKEN_SOUND_PITCH
:
720 int val
= sound_get_pitch();
721 snprintf(buf
, buf_size
, "%d.%d",
727 case WPS_TOKEN_MAIN_HOLD
:
728 #ifdef HAS_BUTTON_HOLD
731 if (is_keys_locked())
732 #endif /*hold switch or softlock*/
737 #ifdef HAS_REMOTE_BUTTON_HOLD
738 case WPS_TOKEN_REMOTE_HOLD
:
739 if (remote_button_hold())
745 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
746 case WPS_TOKEN_VLED_HDD
:
752 case WPS_TOKEN_BUTTON_VOLUME
:
753 if (data
->button_time_volume
&&
754 TIME_BEFORE(current_tick
, data
->button_time_volume
+
755 token
->value
.i
* TIMEOUT_UNIT
))
758 case WPS_TOKEN_LASTTOUCH
:
759 #ifdef HAVE_TOUCHSCREEN
760 if (TIME_BEFORE(current_tick
, token
->value
.i
* TIMEOUT_UNIT
+
761 touchscreen_last_touch()))
766 case WPS_TOKEN_SETTING
:
770 /* Handle contionals */
771 const struct settings_list
*s
= settings
+token
->value
.i
;
772 switch (s
->flags
&F_T_MASK
)
777 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
778 /* shouldn't overflow since colors are stored
780 * but this is pretty useless anyway */
781 *intval
= *(int*)s
->setting
+ 1;
782 else if (s
->cfg_vals
== NULL
)
783 /* %?St|name|<1st choice|2nd choice|...> */
784 *intval
= (*(int*)s
->setting
-s
->int_setting
->min
)
785 /s
->int_setting
->step
+ 1;
787 /* %?St|name|<1st choice|2nd choice|...> */
788 /* Not sure about this one. cfg_name/vals are
789 * indexed from 0 right? */
790 *intval
= *(int*)s
->setting
+ 1;
793 /* %?St|name|<if true|if false> */
794 *intval
= *(bool*)s
->setting
?1:2;
797 /* %?St|name|<if non empty string|if empty>
798 * The string's emptyness discards the setting's
799 * prefix and suffix */
800 *intval
= ((char*)s
->setting
)[0]?1:2;
803 /* This shouldn't happen ... but you never know */
808 cfg_to_string(token
->value
.i
,buf
,buf_size
);