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"
59 #include "root_menu.h"
61 #include "recording.h"
64 static char* get_codectype(const struct mp3entry
* id3
)
66 if (id3
->codectype
< AFMT_NUM_CODECS
) {
67 return (char*)audio_formats
[id3
->codectype
].label
;
73 /* Extract a part from a path.
75 * buf - buffer extract part to.
76 * buf_size - size of buffer.
77 * path - path to extract from.
78 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
79 * parent of parent, etc.
81 * Returns buf if the desired level was found, NULL otherwise.
83 static char* get_dir(char* buf
, int buf_size
, const char* path
, int level
)
89 sep
= path
+ strlen(path
);
104 if (level
|| (last_sep
<= sep
))
107 len
= MIN(last_sep
- sep
, buf_size
- 1);
108 strlcpy(buf
, sep
+ 1, len
+ 1);
112 /* Return the tag found at index i and write its value in buf.
113 The return value is buf if the tag had a value, or NULL if not.
115 intval is used with conditionals/enums: when this function is called,
116 intval should contain the number of options in the conditional/enum.
117 When this function returns, intval is -1 if the tag is non numeric or,
118 if the tag is numeric, *intval is the enum case we want to go to (between 1
119 and the original value of *intval, inclusive).
120 When not treating a conditional/enum, intval should be NULL.
122 const char *get_token_value(struct gui_wps
*gwps
,
123 struct wps_token
*token
,
124 char *buf
, int buf_size
,
130 struct wps_data
*data
= gwps
->data
;
131 struct wps_state
*state
= gwps
->state
;
136 struct mp3entry
*id3
;
147 struct tm
* tm
= NULL
;
149 /* if the token is an RTC one, update the time
150 and do the necessary checks */
151 if (token
->type
>= WPS_TOKENS_RTC_BEGIN
152 && token
->type
<= WPS_TOKENS_RTC_END
)
170 case WPS_TOKEN_CHARACTER
:
171 if (token
->value
.c
== '\n')
173 return &(token
->value
.c
);
175 case WPS_TOKEN_STRING
:
176 return (char*)token
->value
.data
;
178 case WPS_TOKEN_TRANSLATEDSTRING
:
179 return (char*)P2STR(ID2P(token
->value
.i
));
181 case WPS_TOKEN_TRACK_TIME_ELAPSED
:
182 format_time(buf
, buf_size
,
183 id3
->elapsed
+ state
->ff_rewind_count
);
186 case WPS_TOKEN_TRACK_TIME_REMAINING
:
187 format_time(buf
, buf_size
,
188 id3
->length
- id3
->elapsed
-
189 state
->ff_rewind_count
);
192 case WPS_TOKEN_TRACK_LENGTH
:
193 format_time(buf
, buf_size
, id3
->length
);
196 case WPS_TOKEN_PLAYLIST_ENTRIES
:
197 snprintf(buf
, buf_size
, "%d", playlist_amount());
200 case WPS_TOKEN_PLAYLIST_NAME
:
201 return playlist_name(NULL
, buf
, buf_size
);
203 case WPS_TOKEN_PLAYLIST_POSITION
:
204 snprintf(buf
, buf_size
, "%d", playlist_get_display_index());
207 case WPS_TOKEN_PLAYLIST_SHUFFLE
:
208 if ( global_settings
.playlist_shuffle
)
214 case WPS_TOKEN_VOLUME
:
215 snprintf(buf
, buf_size
, "%d", global_settings
.volume
);
218 if (global_settings
.volume
== sound_min(SOUND_VOLUME
))
222 else if (global_settings
.volume
== 0)
226 else if (global_settings
.volume
> 0)
232 *intval
= (limit
- 3) * (global_settings
.volume
233 - sound_min(SOUND_VOLUME
) - 1)
234 / (-1 - sound_min(SOUND_VOLUME
)) + 2;
239 case WPS_TOKEN_TRACK_ELAPSED_PERCENT
:
240 if (id3
->length
<= 0)
245 *intval
= limit
* (id3
->elapsed
+ state
->ff_rewind_count
)
248 snprintf(buf
, buf_size
, "%d",
249 100*(id3
->elapsed
+ state
->ff_rewind_count
) / id3
->length
);
252 case WPS_TOKEN_METADATA_ARTIST
:
255 case WPS_TOKEN_METADATA_COMPOSER
:
256 return id3
->composer
;
258 case WPS_TOKEN_METADATA_ALBUM
:
261 case WPS_TOKEN_METADATA_ALBUM_ARTIST
:
262 return id3
->albumartist
;
264 case WPS_TOKEN_METADATA_GROUPING
:
265 return id3
->grouping
;
267 case WPS_TOKEN_METADATA_GENRE
:
268 return id3
->genre_string
;
270 case WPS_TOKEN_METADATA_DISC_NUMBER
:
271 if (id3
->disc_string
)
272 return id3
->disc_string
;
274 snprintf(buf
, buf_size
, "%d", id3
->discnum
);
279 case WPS_TOKEN_METADATA_TRACK_NUMBER
:
280 if (id3
->track_string
)
281 return id3
->track_string
;
284 snprintf(buf
, buf_size
, "%d", id3
->tracknum
);
289 case WPS_TOKEN_METADATA_TRACK_TITLE
:
292 case WPS_TOKEN_METADATA_VERSION
:
293 switch (id3
->id3version
)
314 case WPS_TOKEN_METADATA_YEAR
:
315 if( id3
->year_string
)
316 return id3
->year_string
;
319 snprintf(buf
, buf_size
, "%d", id3
->year
);
324 case WPS_TOKEN_METADATA_COMMENT
:
328 case WPS_TOKEN_ALBUMART_FOUND
:
329 if (data
->albumart
&& audio_current_aa_hid() >= 0) {
334 case WPS_TOKEN_ALBUMART_DISPLAY
:
337 if (!data
->albumart
->draw
)
338 data
->albumart
->draw
= true;
342 case WPS_TOKEN_FILE_BITRATE
:
344 snprintf(buf
, buf_size
, "%d", id3
->bitrate
);
349 case WPS_TOKEN_FILE_CODEC
:
352 if(id3
->codectype
== AFMT_UNKNOWN
)
353 *intval
= AFMT_NUM_CODECS
;
355 *intval
= id3
->codectype
;
357 return get_codectype(id3
);
359 case WPS_TOKEN_FILE_FREQUENCY
:
360 snprintf(buf
, buf_size
, "%ld", id3
->frequency
);
363 case WPS_TOKEN_FILE_FREQUENCY_KHZ
:
364 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
365 if ((id3
->frequency
% 1000) < 100)
366 snprintf(buf
, buf_size
, "%ld", id3
->frequency
/ 1000);
368 snprintf(buf
, buf_size
, "%ld.%d",
369 id3
->frequency
/ 1000,
370 (id3
->frequency
% 1000) / 100);
373 case WPS_TOKEN_FILE_NAME
:
374 if (get_dir(buf
, buf_size
, id3
->path
, 0)) {
375 /* Remove extension */
376 char* sep
= strrchr(buf
, '.');
386 case WPS_TOKEN_FILE_NAME_WITH_EXTENSION
:
387 return get_dir(buf
, buf_size
, id3
->path
, 0);
389 case WPS_TOKEN_FILE_PATH
:
392 case WPS_TOKEN_FILE_SIZE
:
393 snprintf(buf
, buf_size
, "%ld", id3
->filesize
/ 1024);
396 case WPS_TOKEN_FILE_VBR
:
397 return id3
->vbr
? "(avg)" : NULL
;
399 case WPS_TOKEN_FILE_DIRECTORY
:
400 return get_dir(buf
, buf_size
, id3
->path
, token
->value
.i
);
402 case WPS_TOKEN_BATTERY_PERCENT
:
404 int l
= battery_level();
408 limit
= MAX(limit
, 2);
410 /* First enum is used for "unknown level". */
411 *intval
= (limit
- 1) * l
/ 100 + 2;
418 snprintf(buf
, buf_size
, "%d", l
);
425 case WPS_TOKEN_BATTERY_VOLTS
:
427 unsigned int v
= battery_voltage();
428 snprintf(buf
, buf_size
, "%d.%02d", v
/ 1000, (v
% 1000) / 10);
432 case WPS_TOKEN_BATTERY_TIME
:
434 int t
= battery_time();
436 snprintf(buf
, buf_size
, "%dh %dm", t
/ 60, t
% 60);
443 case WPS_TOKEN_BATTERY_CHARGER_CONNECTED
:
445 if(charger_input_state
==CHARGER
)
451 #if CONFIG_CHARGING >= CHARGING_MONITOR
452 case WPS_TOKEN_BATTERY_CHARGING
:
454 if (charge_state
== CHARGING
|| charge_state
== TOPOFF
) {
461 case WPS_TOKEN_BATTERY_SLEEPTIME
:
463 if (get_sleep_timer() == 0)
467 format_time(buf
, buf_size
, get_sleep_timer() * 1000);
472 case WPS_TOKEN_PLAYBACK_STATUS
:
474 int status
= current_playmode();
476 int mode
= 1; /* stop */
477 if (status
== STATUS_PLAY
)
479 if (is_wps_fading() ||
480 (status
== STATUS_PAUSE
&& !status_get_ffmode()))
481 mode
= 3; /* pause */
484 if (status_get_ffmode() == STATUS_FASTFORWARD
)
486 if (status_get_ffmode() == STATUS_FASTBACKWARD
)
489 #ifdef HAVE_RECORDING
491 if (status
== STATUS_RECORD
)
493 else if (status
== STATUS_RECORD_PAUSE
)
498 if (status
== STATUS_RADIO
)
500 else if (status
== STATUS_RADIO_PAUSE
)
508 snprintf(buf
, buf_size
, "%d", mode
-1);
512 case WPS_TOKEN_REPEAT_MODE
:
514 *intval
= global_settings
.repeat_mode
+ 1;
515 snprintf(buf
, buf_size
, "%d", global_settings
.repeat_mode
);
518 case WPS_TOKEN_RTC_PRESENT
:
526 case WPS_TOKEN_RTC_12HOUR_CFG
:
528 *intval
= global_settings
.timeformat
+ 1;
529 snprintf(buf
, buf_size
, "%d", global_settings
.timeformat
);
532 case WPS_TOKEN_RTC_DAY_OF_MONTH
:
533 /* d: day of month (01..31) */
534 snprintf(buf
, buf_size
, "%02d", tm
->tm_mday
);
537 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
:
538 /* e: day of month, blank padded ( 1..31) */
539 snprintf(buf
, buf_size
, "%2d", tm
->tm_mday
);
542 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
:
543 /* H: hour (00..23) */
544 snprintf(buf
, buf_size
, "%02d", tm
->tm_hour
);
547 case WPS_TOKEN_RTC_HOUR_24
:
548 /* k: hour ( 0..23) */
549 snprintf(buf
, buf_size
, "%2d", tm
->tm_hour
);
552 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
:
553 /* I: hour (01..12) */
554 snprintf(buf
, buf_size
, "%02d",
555 (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12);
558 case WPS_TOKEN_RTC_HOUR_12
:
559 /* l: hour ( 1..12) */
560 snprintf(buf
, buf_size
, "%2d",
561 (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12);
564 case WPS_TOKEN_RTC_MONTH
:
565 /* m: month (01..12) */
567 *intval
= tm
->tm_mon
+ 1;
568 snprintf(buf
, buf_size
, "%02d", tm
->tm_mon
+ 1);
571 case WPS_TOKEN_RTC_MINUTE
:
572 /* M: minute (00..59) */
573 snprintf(buf
, buf_size
, "%02d", tm
->tm_min
);
576 case WPS_TOKEN_RTC_SECOND
:
577 /* S: second (00..59) */
578 snprintf(buf
, buf_size
, "%02d", tm
->tm_sec
);
581 case WPS_TOKEN_RTC_YEAR_2_DIGITS
:
582 /* y: last two digits of year (00..99) */
583 snprintf(buf
, buf_size
, "%02d", tm
->tm_year
% 100);
586 case WPS_TOKEN_RTC_YEAR_4_DIGITS
:
587 /* Y: year (1970...) */
588 snprintf(buf
, buf_size
, "%04d", tm
->tm_year
+ 1900);
591 case WPS_TOKEN_RTC_AM_PM_UPPER
:
592 /* p: upper case AM or PM indicator */
593 return tm
->tm_hour
/12 == 0 ? "AM" : "PM";
595 case WPS_TOKEN_RTC_AM_PM_LOWER
:
596 /* P: lower case am or pm indicator */
597 return tm
->tm_hour
/12 == 0 ? "am" : "pm";
599 case WPS_TOKEN_RTC_WEEKDAY_NAME
:
600 /* a: abbreviated weekday name (Sun..Sat) */
601 return str(LANG_WEEKDAY_SUNDAY
+ tm
->tm_wday
);
603 case WPS_TOKEN_RTC_MONTH_NAME
:
604 /* b: abbreviated month name (Jan..Dec) */
605 return str(LANG_MONTH_JANUARY
+ tm
->tm_mon
);
607 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
:
608 /* u: day of week (1..7); 1 is Monday */
610 *intval
= (tm
->tm_wday
== 0) ? 7 : tm
->tm_wday
;
611 snprintf(buf
, buf_size
, "%1d", tm
->tm_wday
+ 1);
614 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
:
615 /* w: day of week (0..6); 0 is Sunday */
617 *intval
= tm
->tm_wday
+ 1;
618 snprintf(buf
, buf_size
, "%1d", tm
->tm_wday
);
621 case WPS_TOKEN_RTC_DAY_OF_MONTH
:
622 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
:
623 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
:
624 case WPS_TOKEN_RTC_HOUR_24
:
625 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
:
626 case WPS_TOKEN_RTC_HOUR_12
:
627 case WPS_TOKEN_RTC_MONTH
:
628 case WPS_TOKEN_RTC_MINUTE
:
629 case WPS_TOKEN_RTC_SECOND
:
630 case WPS_TOKEN_RTC_AM_PM_UPPER
:
631 case WPS_TOKEN_RTC_AM_PM_LOWER
:
632 case WPS_TOKEN_RTC_YEAR_2_DIGITS
:
634 case WPS_TOKEN_RTC_YEAR_4_DIGITS
:
636 case WPS_TOKEN_RTC_WEEKDAY_NAME
:
637 case WPS_TOKEN_RTC_MONTH_NAME
:
639 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
:
640 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
:
644 #ifdef HAVE_LCD_CHARCELLS
645 case WPS_TOKEN_PROGRESSBAR
:
647 char *end
= utf8encode(data
->wps_progress_pat
[0], buf
);
652 case WPS_TOKEN_PLAYER_PROGRESSBAR
:
655 /* we need 11 characters (full line) for
657 strlcpy(buf
, " ", buf_size
);
661 /* Tell the user if we have an OldPlayer */
662 strlcpy(buf
, " <Old LCD> ", buf_size
);
668 case WPS_TOKEN_DATABASE_PLAYCOUNT
:
670 *intval
= id3
->playcount
+ 1;
672 snprintf(buf
, buf_size
, "%ld", id3
->playcount
);
675 case WPS_TOKEN_DATABASE_RATING
:
677 *intval
= id3
->rating
+ 1;
679 snprintf(buf
, buf_size
, "%d", id3
->rating
);
682 case WPS_TOKEN_DATABASE_AUTOSCORE
:
684 *intval
= id3
->score
+ 1;
686 snprintf(buf
, buf_size
, "%d", id3
->score
);
690 #if (CONFIG_CODEC == SWCODEC)
691 case WPS_TOKEN_CROSSFADE
:
693 *intval
= global_settings
.crossfade
+ 1;
694 snprintf(buf
, buf_size
, "%d", global_settings
.crossfade
);
697 case WPS_TOKEN_REPLAYGAIN
:
701 if (global_settings
.replaygain_type
== REPLAYGAIN_OFF
)
706 get_replaygain_mode(id3
->track_gain_string
!= NULL
,
707 id3
->album_gain_string
!= NULL
);
709 val
= 6; /* no tag */
713 if (global_settings
.replaygain_type
== REPLAYGAIN_SHUFFLE
)
728 strlcpy(buf
, id3
->track_gain_string
, buf_size
);
732 strlcpy(buf
, id3
->album_gain_string
, buf_size
);
737 #endif /* (CONFIG_CODEC == SWCODEC) */
739 #if (CONFIG_CODEC != MAS3507D)
740 case WPS_TOKEN_SOUND_PITCH
:
742 int32_t pitch
= sound_get_pitch();
743 snprintf(buf
, buf_size
, "%ld.%ld",
744 pitch
/ PITCH_SPEED_PRECISION
,
745 (pitch
% PITCH_SPEED_PRECISION
) / (PITCH_SPEED_PRECISION
/ 10));
750 case WPS_TOKEN_MAIN_HOLD
:
751 #ifdef HAS_BUTTON_HOLD
754 if (is_keys_locked())
755 #endif /*hold switch or softlock*/
760 #ifdef HAS_REMOTE_BUTTON_HOLD
761 case WPS_TOKEN_REMOTE_HOLD
:
762 if (remote_button_hold())
768 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
769 case WPS_TOKEN_VLED_HDD
:
775 case WPS_TOKEN_BUTTON_VOLUME
:
776 if (data
->button_time_volume
&&
777 TIME_BEFORE(current_tick
, data
->button_time_volume
+
778 token
->value
.i
* TIMEOUT_UNIT
))
781 case WPS_TOKEN_LASTTOUCH
:
782 #ifdef HAVE_TOUCHSCREEN
783 if (TIME_BEFORE(current_tick
, token
->value
.i
* TIMEOUT_UNIT
+
784 touchscreen_last_touch()))
789 case WPS_TOKEN_SETTING
:
793 /* Handle contionals */
794 const struct settings_list
*s
= settings
+token
->value
.i
;
795 switch (s
->flags
&F_T_MASK
)
800 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
801 /* shouldn't overflow since colors are stored
803 * but this is pretty useless anyway */
804 *intval
= *(int*)s
->setting
+ 1;
805 else if (s
->cfg_vals
== NULL
)
806 /* %?St|name|<1st choice|2nd choice|...> */
807 *intval
= (*(int*)s
->setting
-s
->int_setting
->min
)
808 /s
->int_setting
->step
+ 1;
810 /* %?St|name|<1st choice|2nd choice|...> */
811 /* Not sure about this one. cfg_name/vals are
812 * indexed from 0 right? */
813 *intval
= *(int*)s
->setting
+ 1;
816 /* %?St|name|<if true|if false> */
817 *intval
= *(bool*)s
->setting
?1:2;
820 /* %?St|name|<if non empty string|if empty>
821 * The string's emptyness discards the setting's
822 * prefix and suffix */
823 *intval
= ((char*)s
->setting
)[0]?1:2;
826 /* This shouldn't happen ... but you never know */
831 cfg_to_string(token
->value
.i
,buf
,buf_size
);
834 case WPS_TOKEN_CURRENT_SCREEN
:
836 int curr_screen
= current_screen();
838 #ifdef HAVE_RECORDING
839 /* override current_screen() for recording screen since it may
840 * be entered from the radio screen */
841 if (in_recording_screen())
842 curr_screen
= GO_TO_RECSCREEN
;
850 #ifdef HAVE_RECORDING
851 case GO_TO_RECSCREEN
:
867 *intval
= curr_screen
;
869 snprintf(buf
, buf_size
, "%d", curr_screen
);