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 return &(token
->value
.c
);
169 case WPS_TOKEN_STRING
:
170 return data
->strings
[token
->value
.i
];
172 case WPS_TOKEN_TRACK_TIME_ELAPSED
:
173 format_time(buf
, buf_size
,
174 id3
->elapsed
+ state
->ff_rewind_count
);
177 case WPS_TOKEN_TRACK_TIME_REMAINING
:
178 format_time(buf
, buf_size
,
179 id3
->length
- id3
->elapsed
-
180 state
->ff_rewind_count
);
183 case WPS_TOKEN_TRACK_LENGTH
:
184 format_time(buf
, buf_size
, id3
->length
);
187 case WPS_TOKEN_PLAYLIST_ENTRIES
:
188 snprintf(buf
, buf_size
, "%d", playlist_amount());
191 case WPS_TOKEN_PLAYLIST_NAME
:
192 return playlist_name(NULL
, buf
, buf_size
);
194 case WPS_TOKEN_PLAYLIST_POSITION
:
195 snprintf(buf
, buf_size
, "%d", playlist_get_display_index());
198 case WPS_TOKEN_PLAYLIST_SHUFFLE
:
199 if ( global_settings
.playlist_shuffle
)
205 case WPS_TOKEN_VOLUME
:
206 snprintf(buf
, buf_size
, "%d", global_settings
.volume
);
209 if (global_settings
.volume
== sound_min(SOUND_VOLUME
))
213 else if (global_settings
.volume
== 0)
217 else if (global_settings
.volume
> 0)
223 *intval
= (limit
- 3) * (global_settings
.volume
224 - sound_min(SOUND_VOLUME
) - 1)
225 / (-1 - sound_min(SOUND_VOLUME
)) + 2;
230 case WPS_TOKEN_TRACK_ELAPSED_PERCENT
:
231 if (id3
->length
<= 0)
236 *intval
= limit
* (id3
->elapsed
+ state
->ff_rewind_count
)
239 snprintf(buf
, buf_size
, "%d",
240 100*(id3
->elapsed
+ state
->ff_rewind_count
) / id3
->length
);
243 case WPS_TOKEN_METADATA_ARTIST
:
246 case WPS_TOKEN_METADATA_COMPOSER
:
247 return id3
->composer
;
249 case WPS_TOKEN_METADATA_ALBUM
:
252 case WPS_TOKEN_METADATA_ALBUM_ARTIST
:
253 return id3
->albumartist
;
255 case WPS_TOKEN_METADATA_GROUPING
:
256 return id3
->grouping
;
258 case WPS_TOKEN_METADATA_GENRE
:
259 return id3
->genre_string
;
261 case WPS_TOKEN_METADATA_DISC_NUMBER
:
262 if (id3
->disc_string
)
263 return id3
->disc_string
;
265 snprintf(buf
, buf_size
, "%d", id3
->discnum
);
270 case WPS_TOKEN_METADATA_TRACK_NUMBER
:
271 if (id3
->track_string
)
272 return id3
->track_string
;
275 snprintf(buf
, buf_size
, "%d", id3
->tracknum
);
280 case WPS_TOKEN_METADATA_TRACK_TITLE
:
283 case WPS_TOKEN_METADATA_VERSION
:
284 switch (id3
->id3version
)
305 case WPS_TOKEN_METADATA_YEAR
:
306 if( id3
->year_string
)
307 return id3
->year_string
;
310 snprintf(buf
, buf_size
, "%d", id3
->year
);
315 case WPS_TOKEN_METADATA_COMMENT
:
319 case WPS_TOKEN_ALBUMART_DISPLAY
:
320 draw_album_art(gwps
, audio_current_aa_hid(), false);
323 case WPS_TOKEN_ALBUMART_FOUND
:
324 if (audio_current_aa_hid() >= 0) {
330 case WPS_TOKEN_FILE_BITRATE
:
332 snprintf(buf
, buf_size
, "%d", id3
->bitrate
);
337 case WPS_TOKEN_FILE_CODEC
:
340 if(id3
->codectype
== AFMT_UNKNOWN
)
341 *intval
= AFMT_NUM_CODECS
;
343 *intval
= id3
->codectype
;
345 return get_codectype(id3
);
347 case WPS_TOKEN_FILE_FREQUENCY
:
348 snprintf(buf
, buf_size
, "%ld", id3
->frequency
);
351 case WPS_TOKEN_FILE_FREQUENCY_KHZ
:
352 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
353 if ((id3
->frequency
% 1000) < 100)
354 snprintf(buf
, buf_size
, "%ld", id3
->frequency
/ 1000);
356 snprintf(buf
, buf_size
, "%ld.%d",
357 id3
->frequency
/ 1000,
358 (id3
->frequency
% 1000) / 100);
361 case WPS_TOKEN_FILE_NAME
:
362 if (get_dir(buf
, buf_size
, id3
->path
, 0)) {
363 /* Remove extension */
364 char* sep
= strrchr(buf
, '.');
374 case WPS_TOKEN_FILE_NAME_WITH_EXTENSION
:
375 return get_dir(buf
, buf_size
, id3
->path
, 0);
377 case WPS_TOKEN_FILE_PATH
:
380 case WPS_TOKEN_FILE_SIZE
:
381 snprintf(buf
, buf_size
, "%ld", id3
->filesize
/ 1024);
384 case WPS_TOKEN_FILE_VBR
:
385 return id3
->vbr
? "(avg)" : NULL
;
387 case WPS_TOKEN_FILE_DIRECTORY
:
388 return get_dir(buf
, buf_size
, id3
->path
, token
->value
.i
);
390 case WPS_TOKEN_BATTERY_PERCENT
:
392 int l
= battery_level();
396 limit
= MAX(limit
, 2);
398 /* First enum is used for "unknown level". */
399 *intval
= (limit
- 1) * l
/ 100 + 2;
406 snprintf(buf
, buf_size
, "%d", l
);
413 case WPS_TOKEN_BATTERY_VOLTS
:
415 unsigned int v
= battery_voltage();
416 snprintf(buf
, buf_size
, "%d.%02d", v
/ 1000, (v
% 1000) / 10);
420 case WPS_TOKEN_BATTERY_TIME
:
422 int t
= battery_time();
424 snprintf(buf
, buf_size
, "%dh %dm", t
/ 60, t
% 60);
431 case WPS_TOKEN_BATTERY_CHARGER_CONNECTED
:
433 if(charger_input_state
==CHARGER
)
439 #if CONFIG_CHARGING >= CHARGING_MONITOR
440 case WPS_TOKEN_BATTERY_CHARGING
:
442 if (charge_state
== CHARGING
|| charge_state
== TOPOFF
) {
449 case WPS_TOKEN_BATTERY_SLEEPTIME
:
451 if (get_sleep_timer() == 0)
455 format_time(buf
, buf_size
, get_sleep_timer() * 1000);
460 case WPS_TOKEN_PLAYBACK_STATUS
:
462 int status
= audio_status();
464 if (status
== AUDIO_STATUS_PLAY
)
466 if (is_wps_fading() ||
467 (status
& AUDIO_STATUS_PAUSE
&& !status_get_ffmode()))
469 if (status_get_ffmode() == STATUS_FASTFORWARD
)
471 if (status_get_ffmode() == STATUS_FASTBACKWARD
)
478 snprintf(buf
, buf_size
, "%d", mode
-1);
482 case WPS_TOKEN_REPEAT_MODE
:
484 *intval
= global_settings
.repeat_mode
+ 1;
485 snprintf(buf
, buf_size
, "%d", global_settings
.repeat_mode
);
488 case WPS_TOKEN_RTC_PRESENT
:
496 case WPS_TOKEN_RTC_12HOUR_CFG
:
498 *intval
= global_settings
.timeformat
+ 1;
499 snprintf(buf
, buf_size
, "%d", global_settings
.timeformat
);
502 case WPS_TOKEN_RTC_DAY_OF_MONTH
:
503 /* d: day of month (01..31) */
504 snprintf(buf
, buf_size
, "%02d", tm
->tm_mday
);
507 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
:
508 /* e: day of month, blank padded ( 1..31) */
509 snprintf(buf
, buf_size
, "%2d", tm
->tm_mday
);
512 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
:
513 /* H: hour (00..23) */
514 snprintf(buf
, buf_size
, "%02d", tm
->tm_hour
);
517 case WPS_TOKEN_RTC_HOUR_24
:
518 /* k: hour ( 0..23) */
519 snprintf(buf
, buf_size
, "%2d", tm
->tm_hour
);
522 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
:
523 /* I: hour (01..12) */
524 snprintf(buf
, buf_size
, "%02d",
525 (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12);
528 case WPS_TOKEN_RTC_HOUR_12
:
529 /* l: hour ( 1..12) */
530 snprintf(buf
, buf_size
, "%2d",
531 (tm
->tm_hour
% 12 == 0) ? 12 : tm
->tm_hour
% 12);
534 case WPS_TOKEN_RTC_MONTH
:
535 /* m: month (01..12) */
537 *intval
= tm
->tm_mon
+ 1;
538 snprintf(buf
, buf_size
, "%02d", tm
->tm_mon
+ 1);
541 case WPS_TOKEN_RTC_MINUTE
:
542 /* M: minute (00..59) */
543 snprintf(buf
, buf_size
, "%02d", tm
->tm_min
);
546 case WPS_TOKEN_RTC_SECOND
:
547 /* S: second (00..59) */
548 snprintf(buf
, buf_size
, "%02d", tm
->tm_sec
);
551 case WPS_TOKEN_RTC_YEAR_2_DIGITS
:
552 /* y: last two digits of year (00..99) */
553 snprintf(buf
, buf_size
, "%02d", tm
->tm_year
% 100);
556 case WPS_TOKEN_RTC_YEAR_4_DIGITS
:
557 /* Y: year (1970...) */
558 snprintf(buf
, buf_size
, "%04d", tm
->tm_year
+ 1900);
561 case WPS_TOKEN_RTC_AM_PM_UPPER
:
562 /* p: upper case AM or PM indicator */
563 return tm
->tm_hour
/12 == 0 ? "AM" : "PM";
565 case WPS_TOKEN_RTC_AM_PM_LOWER
:
566 /* P: lower case am or pm indicator */
567 return tm
->tm_hour
/12 == 0 ? "am" : "pm";
569 case WPS_TOKEN_RTC_WEEKDAY_NAME
:
570 /* a: abbreviated weekday name (Sun..Sat) */
571 return str(LANG_WEEKDAY_SUNDAY
+ tm
->tm_wday
);
573 case WPS_TOKEN_RTC_MONTH_NAME
:
574 /* b: abbreviated month name (Jan..Dec) */
575 return str(LANG_MONTH_JANUARY
+ tm
->tm_mon
);
577 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
:
578 /* u: day of week (1..7); 1 is Monday */
580 *intval
= (tm
->tm_wday
== 0) ? 7 : tm
->tm_wday
;
581 snprintf(buf
, buf_size
, "%1d", tm
->tm_wday
+ 1);
584 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
:
585 /* w: day of week (0..6); 0 is Sunday */
587 *intval
= tm
->tm_wday
+ 1;
588 snprintf(buf
, buf_size
, "%1d", tm
->tm_wday
);
591 case WPS_TOKEN_RTC_DAY_OF_MONTH
:
592 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED
:
593 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED
:
594 case WPS_TOKEN_RTC_HOUR_24
:
595 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED
:
596 case WPS_TOKEN_RTC_HOUR_12
:
597 case WPS_TOKEN_RTC_MONTH
:
598 case WPS_TOKEN_RTC_MINUTE
:
599 case WPS_TOKEN_RTC_SECOND
:
600 case WPS_TOKEN_RTC_AM_PM_UPPER
:
601 case WPS_TOKEN_RTC_AM_PM_LOWER
:
602 case WPS_TOKEN_RTC_YEAR_2_DIGITS
:
604 case WPS_TOKEN_RTC_YEAR_4_DIGITS
:
606 case WPS_TOKEN_RTC_WEEKDAY_NAME
:
607 case WPS_TOKEN_RTC_MONTH_NAME
:
609 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON
:
610 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN
:
614 #ifdef HAVE_LCD_CHARCELLS
615 case WPS_TOKEN_PROGRESSBAR
:
617 char *end
= utf8encode(data
->wps_progress_pat
[0], buf
);
622 case WPS_TOKEN_PLAYER_PROGRESSBAR
:
625 /* we need 11 characters (full line) for
627 strlcpy(buf
, " ", buf_size
);
631 /* Tell the user if we have an OldPlayer */
632 strlcpy(buf
, " <Old LCD> ", buf_size
);
638 case WPS_TOKEN_DATABASE_PLAYCOUNT
:
640 *intval
= id3
->playcount
+ 1;
642 snprintf(buf
, buf_size
, "%ld", id3
->playcount
);
645 case WPS_TOKEN_DATABASE_RATING
:
647 *intval
= id3
->rating
+ 1;
649 snprintf(buf
, buf_size
, "%d", id3
->rating
);
652 case WPS_TOKEN_DATABASE_AUTOSCORE
:
654 *intval
= id3
->score
+ 1;
656 snprintf(buf
, buf_size
, "%d", id3
->score
);
660 #if (CONFIG_CODEC == SWCODEC)
661 case WPS_TOKEN_CROSSFADE
:
663 *intval
= global_settings
.crossfade
+ 1;
664 snprintf(buf
, buf_size
, "%d", global_settings
.crossfade
);
667 case WPS_TOKEN_REPLAYGAIN
:
671 if (global_settings
.replaygain_type
== REPLAYGAIN_OFF
)
676 get_replaygain_mode(id3
->track_gain_string
!= NULL
,
677 id3
->album_gain_string
!= NULL
);
679 val
= 6; /* no tag */
683 if (global_settings
.replaygain_type
== REPLAYGAIN_SHUFFLE
)
698 strlcpy(buf
, id3
->track_gain_string
, buf_size
);
702 strlcpy(buf
, id3
->album_gain_string
, buf_size
);
707 #endif /* (CONFIG_CODEC == SWCODEC) */
709 #if (CONFIG_CODEC != MAS3507D)
710 case WPS_TOKEN_SOUND_PITCH
:
712 int val
= sound_get_pitch();
713 snprintf(buf
, buf_size
, "%d.%d",
719 case WPS_TOKEN_MAIN_HOLD
:
720 #ifdef HAS_BUTTON_HOLD
723 if (is_keys_locked())
724 #endif /*hold switch or softlock*/
729 #ifdef HAS_REMOTE_BUTTON_HOLD
730 case WPS_TOKEN_REMOTE_HOLD
:
731 if (remote_button_hold())
737 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
738 case WPS_TOKEN_VLED_HDD
:
744 case WPS_TOKEN_BUTTON_VOLUME
:
745 if (data
->button_time_volume
&&
746 TIME_BEFORE(current_tick
, data
->button_time_volume
+
747 token
->value
.i
* TIMEOUT_UNIT
))
750 case WPS_TOKEN_LASTTOUCH
:
751 #ifdef HAVE_TOUCHSCREEN
752 if (TIME_BEFORE(current_tick
, token
->value
.i
* TIMEOUT_UNIT
+
753 touchscreen_last_touch()))
758 case WPS_TOKEN_SETTING
:
762 /* Handle contionals */
763 const struct settings_list
*s
= settings
+token
->value
.i
;
764 switch (s
->flags
&F_T_MASK
)
769 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
770 /* shouldn't overflow since colors are stored
772 * but this is pretty useless anyway */
773 *intval
= *(int*)s
->setting
+ 1;
774 else if (s
->cfg_vals
== NULL
)
775 /* %?St|name|<1st choice|2nd choice|...> */
776 *intval
= (*(int*)s
->setting
-s
->int_setting
->min
)
777 /s
->int_setting
->step
+ 1;
779 /* %?St|name|<1st choice|2nd choice|...> */
780 /* Not sure about this one. cfg_name/vals are
781 * indexed from 0 right? */
782 *intval
= *(int*)s
->setting
+ 1;
785 /* %?St|name|<if true|if false> */
786 *intval
= *(bool*)s
->setting
?1:2;
789 /* %?St|name|<if non empty string|if empty>
790 * The string's emptyness discards the setting's
791 * prefix and suffix */
792 *intval
= ((char*)s
->setting
)[0]?1:2;
795 /* This shouldn't happen ... but you never know */
800 cfg_to_string(token
->value
.i
,buf
,buf_size
);