Correct detection of the absence of the current preset
[kugel-rb.git] / apps / gui / skin_engine / skin_tokens.c
blobb9d4bd6b1503daedc02b5bb64bc5e7fd65fc5ddd
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
22 #include "font.h"
23 #include <stdio.h>
24 #include "string-extra.h"
25 #include <stdlib.h>
26 #include "action.h"
27 #include "system.h"
28 #include "settings.h"
29 #include "settings_list.h"
30 #include "rbunicode.h"
31 #include "timefuncs.h"
32 #include "status.h"
33 #include "power.h"
34 #include "powermgmt.h"
35 #include "sound.h"
36 #include "debug.h"
37 #ifdef HAVE_LCD_CHARCELLS
38 #include "hwcompat.h"
39 #endif
40 #include "abrepeat.h"
41 #include "lang.h"
42 #include "misc.h"
43 #include "led.h"
44 #ifdef HAVE_LCD_BITMAP
45 /* Image stuff */
46 #include "albumart.h"
47 #endif
48 #include "dsp.h"
49 #include "playlist.h"
50 #if CONFIG_CODEC == SWCODEC
51 #include "playback.h"
52 #include "tdspeed.h"
53 #endif
54 #include "viewport.h"
56 #include "wps_internals.h"
57 #include "root_menu.h"
58 #ifdef HAVE_RECORDING
59 #include "recording.h"
60 #include "pcm_record.h"
61 #endif
62 #include "language.h"
63 #include "usb.h"
64 #if CONFIG_TUNER
65 #include "radio.h"
66 #include "tuner.h"
67 #endif
69 extern struct wps_state wps_state;
71 static const char* get_codectype(const struct mp3entry* id3)
73 if (id3 && id3->codectype < AFMT_NUM_CODECS) {
74 return audio_formats[id3->codectype].label;
75 } else {
76 return NULL;
80 /* Extract a part from a path.
82 * buf - buffer extract part to.
83 * buf_size - size of buffer.
84 * path - path to extract from.
85 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
86 * parent of parent, etc.
88 * Returns buf if the desired level was found, NULL otherwise.
90 char* get_dir(char* buf, int buf_size, const char* path, int level)
92 const char* sep;
93 const char* last_sep;
94 int len;
96 sep = path + strlen(path);
97 last_sep = sep;
99 while (sep > path)
101 if ('/' == *(--sep))
103 if (!level)
104 break;
106 level--;
107 last_sep = sep - 1;
111 if (level || (last_sep <= sep))
112 return NULL;
114 len = MIN(last_sep - sep, buf_size - 1);
115 strlcpy(buf, sep + 1, len + 1);
116 return buf;
119 #if (CONFIG_CODEC != MAS3507D)
120 /* A helper to determine the enum value for pitch/speed.
122 When there are two choices (i.e. boolean), return 1 if the value is
123 different from normal value and 2 if the value is the same as the
124 normal value. E.g. "%?Sp<%Sp>" would show the pitch only when
125 playing at a modified pitch.
127 When there are more than two choices (i.e. enum), the left half of
128 the choices are to show 0..normal range, and the right half of the
129 choices are to show values over that. The last entry is used when
130 it is set to the normal setting, following the rockbox convention
131 to use the last entry for special values.
133 E.g.
135 2 items: %?Sp<0..99 or 101..infinity|100>
136 3 items: %?Sp<0..99|101..infinity|100>
137 4 items: %?Sp<0..49|50..99|101..infinity|100>
138 5 items: %?Sp<0..49|50..99|101..149|150..infinity|100>
139 6 items: %?Sp<0..33|34..66|67..99|101..133|134..infinity|100>
140 7 items: %?Sp<0..33|34..66|67..99|101..133|134..167|167..infinity|100>
142 static int pitch_speed_enum(int range, int32_t val, int32_t normval)
144 int center;
145 int n;
147 if (range < 3)
148 return (val == normval) + 1;
149 if (val == normval)
150 return range;
151 center = range / 2;
152 n = (center * val) / normval + 1;
153 return (range <= n) ? (range - 1) : n;
155 #endif
158 /* All tokens which only need the info to return a value go in here */
159 const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
160 char *buf, int buf_size, int limit, int *intval)
162 struct wps_state *state = &wps_state;
163 if (id3)
165 unsigned long length = id3->length;
166 unsigned long elapsed = id3->elapsed + state->ff_rewind_count;
167 switch (token->type)
169 case WPS_TOKEN_METADATA_ARTIST:
170 return id3->artist;
171 case WPS_TOKEN_METADATA_COMPOSER:
172 return id3->composer;
173 case WPS_TOKEN_METADATA_ALBUM:
174 return id3->album;
175 case WPS_TOKEN_METADATA_ALBUM_ARTIST:
176 return id3->albumartist;
177 case WPS_TOKEN_METADATA_GROUPING:
178 return id3->grouping;
179 case WPS_TOKEN_METADATA_GENRE:
180 return id3->genre_string;
181 case WPS_TOKEN_METADATA_DISC_NUMBER:
182 if (id3->disc_string)
183 return id3->disc_string;
184 if (id3->discnum) {
185 snprintf(buf, buf_size, "%d", id3->discnum);
186 return buf;
188 return NULL;
189 case WPS_TOKEN_METADATA_TRACK_NUMBER:
190 if (id3->track_string)
191 return id3->track_string;
192 if (id3->tracknum) {
193 snprintf(buf, buf_size, "%d", id3->tracknum);
194 return buf;
196 return NULL;
197 case WPS_TOKEN_METADATA_TRACK_TITLE:
198 return id3->title;
199 case WPS_TOKEN_METADATA_VERSION:
200 switch (id3->id3version)
202 case ID3_VER_1_0:
203 return "1";
204 case ID3_VER_1_1:
205 return "1.1";
206 case ID3_VER_2_2:
207 return "2.2";
208 case ID3_VER_2_3:
209 return "2.3";
210 case ID3_VER_2_4:
211 return "2.4";
212 default:
213 break;
215 return NULL;
216 case WPS_TOKEN_METADATA_YEAR:
217 if( id3->year_string )
218 return id3->year_string;
219 if (id3->year) {
220 snprintf(buf, buf_size, "%d", id3->year);
221 return buf;
223 return NULL;
224 case WPS_TOKEN_METADATA_COMMENT:
225 return id3->comment;
226 case WPS_TOKEN_FILE_PATH:
227 return id3->path;
228 case WPS_TOKEN_FILE_BITRATE:
229 if(id3->bitrate)
230 snprintf(buf, buf_size, "%d", id3->bitrate);
231 else
232 return "?";
233 return buf;
234 case WPS_TOKEN_TRACK_TIME_ELAPSED:
235 format_time(buf, buf_size, elapsed);
236 return buf;
238 case WPS_TOKEN_TRACK_TIME_REMAINING:
239 format_time(buf, buf_size, length - elapsed);
240 return buf;
242 case WPS_TOKEN_TRACK_LENGTH:
243 format_time(buf, buf_size, length);
244 return buf;
246 case WPS_TOKEN_TRACK_ELAPSED_PERCENT:
247 if (length <= 0)
248 return NULL;
250 if (intval)
252 *intval = limit * elapsed / length + 1;
254 snprintf(buf, buf_size, "%lu", 100 * elapsed / length);
255 return buf;
258 case WPS_TOKEN_FILE_CODEC:
259 if (intval)
261 if(id3->codectype == AFMT_UNKNOWN)
262 *intval = AFMT_NUM_CODECS;
263 else
264 *intval = id3->codectype;
266 return get_codectype(id3);
268 case WPS_TOKEN_FILE_FREQUENCY:
269 snprintf(buf, buf_size, "%ld", id3->frequency);
270 return buf;
271 case WPS_TOKEN_FILE_FREQUENCY_KHZ:
272 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
273 if ((id3->frequency % 1000) < 100)
274 snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
275 else
276 snprintf(buf, buf_size, "%ld.%lu",
277 id3->frequency / 1000,
278 (id3->frequency % 1000) / 100);
279 return buf;
280 case WPS_TOKEN_FILE_NAME:
281 if (get_dir(buf, buf_size, id3->path, 0)) {
282 /* Remove extension */
283 char* sep = strrchr(buf, '.');
284 if (NULL != sep) {
285 *sep = 0;
287 return buf;
289 return NULL;
290 case WPS_TOKEN_FILE_NAME_WITH_EXTENSION:
291 return get_dir(buf, buf_size, id3->path, 0);
292 case WPS_TOKEN_FILE_SIZE:
293 snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
294 return buf;
295 case WPS_TOKEN_FILE_VBR:
296 return (id3->vbr) ? "(avg)" : NULL;
297 case WPS_TOKEN_FILE_DIRECTORY:
298 return get_dir(buf, buf_size, id3->path, token->value.i);
300 #ifdef HAVE_TAGCACHE
301 case WPS_TOKEN_DATABASE_PLAYCOUNT:
302 if (intval)
303 *intval = id3->playcount + 1;
304 snprintf(buf, buf_size, "%ld", id3->playcount);
305 return buf;
306 case WPS_TOKEN_DATABASE_RATING:
307 if (intval)
308 *intval = id3->rating + 1;
309 snprintf(buf, buf_size, "%d", id3->rating);
310 return buf;
311 case WPS_TOKEN_DATABASE_AUTOSCORE:
312 if (intval)
313 *intval = id3->score + 1;
314 snprintf(buf, buf_size, "%d", id3->score);
315 return buf;
316 #endif
318 default:
319 return NULL;
322 else /* id3 == NULL, handle the error based on the expected return type */
324 switch (token->type)
326 /* Most tokens expect NULL on error so leave that for the default case,
327 * The ones that expect "0" need to be handled */
328 case WPS_TOKEN_FILE_FREQUENCY:
329 case WPS_TOKEN_FILE_FREQUENCY_KHZ:
330 case WPS_TOKEN_FILE_SIZE:
331 #ifdef HAVE_TAGCACHE
332 case WPS_TOKEN_DATABASE_PLAYCOUNT:
333 case WPS_TOKEN_DATABASE_RATING:
334 case WPS_TOKEN_DATABASE_AUTOSCORE:
335 #endif
336 if (intval)
337 *intval = 0;
338 return "0";
339 default:
340 return NULL;
343 return buf;
346 #if CONFIG_TUNER
348 /* Formats the frequency (specified in Hz) in MHz, */
349 /* with two digits after the decimal point */
350 static void format_freq_MHz(int freq, char *buf, int buf_size)
352 freq = freq / 10000;
353 snprintf(buf, buf_size, "%d.%02d", freq/100, freq%100);
357 /* Tokens which are really only used by the radio screen go in here */
358 const char *get_radio_token(struct wps_token *token, int preset_offset,
359 char *buf, int buf_size, int limit, int *intval)
361 (void)limit;
362 switch (token->type)
364 /* Radio/tuner tokens */
365 case WPS_TOKEN_TUNER_TUNED:
366 if (tuner_get(RADIO_TUNED))
367 return "t";
368 return NULL;
369 case WPS_TOKEN_TUNER_SCANMODE:
370 if (radio_scan_mode())
371 return "s";
372 return NULL;
373 case WPS_TOKEN_TUNER_STEREO:
374 if (radio_is_stereo())
375 return "s";
376 return NULL;
377 case WPS_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
379 format_freq_MHz(fm_region_data[global_settings.fm_region].freq_min,
380 buf, buf_size);
381 return buf;
383 case WPS_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
385 format_freq_MHz(fm_region_data[global_settings.fm_region].freq_max,
386 buf, buf_size);
387 return buf;
389 case WPS_TOKEN_TUNER_CURFREQ:
391 format_freq_MHz(radio_current_frequency(),
392 buf, buf_size);
393 return buf;
395 case WPS_TOKEN_PRESET_ID:
396 snprintf(buf, buf_size, "%d", radio_current_preset() + 1 + preset_offset);
397 return buf;
398 case WPS_TOKEN_PRESET_NAME:
399 case WPS_TOKEN_PRESET_FREQ:
401 int preset_count = radio_preset_count();
402 int cur_preset = radio_current_preset();
403 if (preset_count == 0 || cur_preset < 0)
404 return NULL;
405 int preset = cur_preset + preset_offset;
406 /* make sure it's in the valid range */
407 while (preset < 0)
408 preset += preset_count;
409 preset %= preset_count;
410 if (token->type == WPS_TOKEN_PRESET_NAME)
412 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
414 else
416 format_freq_MHz(radio_get_preset(preset)->frequency,
417 buf, buf_size);
419 return buf;
421 case WPS_TOKEN_PRESET_COUNT:
422 snprintf(buf, buf_size, "%d", radio_preset_count());
423 if (intval)
424 *intval = radio_preset_count();
425 return buf;
426 case WPS_TOKEN_HAVE_RDS:
427 #ifdef HAVE_RDS_CAP
428 return "rds";
429 case WPS_TOKEN_RDS_NAME:
430 return tuner_get_rds_info(RADIO_RDS_NAME);
431 case WPS_TOKEN_RDS_TEXT:
432 return tuner_get_rds_info(RADIO_RDS_TEXT);
433 #else
434 return NULL; /* end of the WPS_TOKEN_HAVE_RDS case */
435 #endif /* HAVE_RDS_CAP */
437 return NULL;
439 #endif
441 /* Return the tags value as text. buf should be used as temp storage if needed.
443 intval is used with conditionals/enums: when this function is called,
444 intval should contain the number of options in the conditional/enum.
445 When this function returns, intval is -1 if the tag is non numeric or,
446 if the tag is numeric, *intval is the enum case we want to go to (between 1
447 and the original value of *intval, inclusive).
448 When not treating a conditional/enum, intval should be NULL.
450 const char *get_token_value(struct gui_wps *gwps,
451 struct wps_token *token,
452 char *buf, int buf_size,
453 int *intval)
455 if (!gwps)
456 return NULL;
458 struct wps_data *data = gwps->data;
459 struct wps_state *state = gwps->state;
460 struct mp3entry *id3; /* Think very carefully about using this.
461 maybe get_id3_token() is the better place? */
462 const char *out_text = NULL;
464 if (!data || !state)
465 return NULL;
468 if (token->next)
469 id3 = state->nid3;
470 else
471 id3 = state->id3;
473 #if CONFIG_RTC
474 struct tm* tm = NULL;
476 /* if the token is an RTC one, update the time
477 and do the necessary checks */
478 if (token->type >= WPS_TOKENS_RTC_BEGIN
479 && token->type <= WPS_TOKENS_RTC_END)
481 tm = get_time();
483 if (!valid_time(tm))
484 return NULL;
486 #endif
488 int limit = 1;
489 if (intval)
491 limit = *intval;
492 *intval = -1;
495 out_text = get_id3_token(token, id3, buf, buf_size, limit, intval);
496 if (out_text)
497 return out_text;
498 #if CONFIG_TUNER
499 out_text = get_radio_token(token, 0, buf, buf_size, limit, intval);
500 if (out_text)
501 return out_text;
502 #endif
504 switch (token->type)
506 case WPS_TOKEN_CHARACTER:
507 if (token->value.c == '\n')
508 return NULL;
509 return &(token->value.c);
511 case WPS_TOKEN_STRING:
512 return (char*)token->value.data;
514 case WPS_TOKEN_TRANSLATEDSTRING:
515 return (char*)P2STR(ID2P(token->value.i));
517 case WPS_TOKEN_PLAYLIST_ENTRIES:
518 snprintf(buf, buf_size, "%d", playlist_amount());
519 return buf;
521 case WPS_TOKEN_LIST_TITLE_TEXT:
522 return (char*)token->value.data;
523 case WPS_TOKEN_LIST_TITLE_ICON:
524 if (intval)
525 *intval = token->value.i;
526 snprintf(buf, buf_size, "%d", token->value.i);
527 return buf;
529 case WPS_TOKEN_PLAYLIST_NAME:
530 return playlist_name(NULL, buf, buf_size);
532 case WPS_TOKEN_PLAYLIST_POSITION:
533 snprintf(buf, buf_size, "%d", playlist_get_display_index());
534 return buf;
536 case WPS_TOKEN_PLAYLIST_SHUFFLE:
537 if ( global_settings.playlist_shuffle )
538 return "s";
539 else
540 return NULL;
541 break;
543 case WPS_TOKEN_VOLUME:
544 snprintf(buf, buf_size, "%d", global_settings.volume);
545 if (intval)
547 int minvol = sound_min(SOUND_VOLUME);
548 if (global_settings.volume == minvol)
550 *intval = 1;
552 else if (global_settings.volume == 0)
554 *intval = limit - 1;
556 else if (global_settings.volume > 0)
558 *intval = limit;
560 else
562 *intval = (limit-3) * (global_settings.volume - minvol - 1)
563 / (-1 - minvol) + 2;
566 return buf;
567 #ifdef HAVE_ALBUMART
568 case WPS_TOKEN_ALBUMART_FOUND:
569 if (data->albumart) {
570 if (playback_current_aa_hid(data->playback_aa_slot) >= 0)
571 return "C";
573 return NULL;
575 case WPS_TOKEN_ALBUMART_DISPLAY:
576 if (!data->albumart)
577 return NULL;
578 if (!data->albumart->draw)
579 data->albumart->draw = true;
580 return NULL;
581 #endif
583 case WPS_TOKEN_BATTERY_PERCENT:
585 int l = battery_level();
587 if (intval)
589 limit = MAX(limit, 2);
590 if (l > -1) {
591 /* First enum is used for "unknown level". */
592 *intval = (limit - 1) * l / 100 + 2;
593 } else {
594 *intval = 1;
598 if (l > -1) {
599 snprintf(buf, buf_size, "%d", l);
600 return buf;
601 } else {
602 return "?";
606 case WPS_TOKEN_BATTERY_VOLTS:
608 unsigned int v = battery_voltage();
609 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
610 return buf;
613 case WPS_TOKEN_BATTERY_TIME:
615 int t = battery_time();
616 if (t >= 0)
617 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
618 else
619 return "?h ?m";
620 return buf;
623 #if CONFIG_CHARGING
624 case WPS_TOKEN_BATTERY_CHARGER_CONNECTED:
626 if(charger_input_state==CHARGER)
627 return "p";
628 else
629 return NULL;
631 #endif
632 #if CONFIG_CHARGING >= CHARGING_MONITOR
633 case WPS_TOKEN_BATTERY_CHARGING:
635 if (charge_state == CHARGING || charge_state == TOPOFF) {
636 return "c";
637 } else {
638 return NULL;
641 #endif
642 #ifdef HAVE_USB_POWER
643 case WPS_TOKEN_USB_POWERED:
644 if (usb_powered())
645 return "u";
646 return NULL;
647 #endif
648 case WPS_TOKEN_BATTERY_SLEEPTIME:
650 if (get_sleep_timer() == 0)
651 return NULL;
652 else
654 format_time(buf, buf_size, get_sleep_timer() * 1000);
655 return buf;
659 case WPS_TOKEN_PLAYBACK_STATUS:
661 int status = current_playmode();
662 /* music */
663 int mode = 1; /* stop */
664 if (status == STATUS_PLAY)
665 mode = 2; /* play */
666 if (state->is_fading ||
667 (status == STATUS_PAUSE && !status_get_ffmode()))
668 mode = 3; /* pause */
669 else
670 { /* ff / rwd */
671 if (status_get_ffmode() == STATUS_FASTFORWARD)
672 mode = 4;
673 if (status_get_ffmode() == STATUS_FASTBACKWARD)
674 mode = 5;
676 #ifdef HAVE_RECORDING
677 /* recording */
678 if (status == STATUS_RECORD)
679 mode = 6;
680 else if (status == STATUS_RECORD_PAUSE)
681 mode = 7;
682 #endif
683 #if CONFIG_TUNER
684 /* radio */
685 if (status == STATUS_RADIO)
686 mode = 8;
687 else if (status == STATUS_RADIO_PAUSE)
688 mode = 9;
689 #endif
691 if (intval) {
692 *intval = mode;
695 snprintf(buf, buf_size, "%d", mode-1);
696 return buf;
699 case WPS_TOKEN_REPEAT_MODE:
700 if (intval)
701 *intval = global_settings.repeat_mode + 1;
702 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
703 return buf;
705 case WPS_TOKEN_RTC_PRESENT:
706 #if CONFIG_RTC
707 return "c";
708 #else
709 return NULL;
710 #endif
712 #if CONFIG_RTC
713 case WPS_TOKEN_RTC_12HOUR_CFG:
714 if (intval)
715 *intval = global_settings.timeformat + 1;
716 snprintf(buf, buf_size, "%d", global_settings.timeformat);
717 return buf;
719 case WPS_TOKEN_RTC_DAY_OF_MONTH:
720 /* d: day of month (01..31) */
721 snprintf(buf, buf_size, "%02d", tm->tm_mday);
722 if (intval)
723 *intval = tm->tm_mday - 1;
724 return buf;
726 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
727 /* e: day of month, blank padded ( 1..31) */
728 snprintf(buf, buf_size, "%2d", tm->tm_mday);
729 if (intval)
730 *intval = tm->tm_mday - 1;
731 return buf;
733 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
734 /* H: hour (00..23) */
735 snprintf(buf, buf_size, "%02d", tm->tm_hour);
736 if (intval)
737 *intval = tm->tm_hour;
738 return buf;
740 case WPS_TOKEN_RTC_HOUR_24:
741 /* k: hour ( 0..23) */
742 snprintf(buf, buf_size, "%2d", tm->tm_hour);
743 if (intval)
744 *intval = tm->tm_hour;
745 return buf;
747 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
748 /* I: hour (01..12) */
749 snprintf(buf, buf_size, "%02d",
750 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
751 if (intval)
752 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
753 return buf;
755 case WPS_TOKEN_RTC_HOUR_12:
756 /* l: hour ( 1..12) */
757 snprintf(buf, buf_size, "%2d",
758 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
759 if (intval)
760 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
761 return buf;
763 case WPS_TOKEN_RTC_MONTH:
764 /* m: month (01..12) */
765 if (intval)
766 *intval = tm->tm_mon + 1;
767 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
768 return buf;
770 case WPS_TOKEN_RTC_MINUTE:
771 /* M: minute (00..59) */
772 snprintf(buf, buf_size, "%02d", tm->tm_min);
773 if (intval)
774 *intval = tm->tm_min;
775 return buf;
777 case WPS_TOKEN_RTC_SECOND:
778 /* S: second (00..59) */
779 snprintf(buf, buf_size, "%02d", tm->tm_sec);
780 if (intval)
781 *intval = tm->tm_sec;
782 return buf;
784 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
785 /* y: last two digits of year (00..99) */
786 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
787 if (intval)
788 *intval = tm->tm_year % 100;
789 return buf;
791 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
792 /* Y: year (1970...) */
793 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
794 if (intval)
795 *intval = tm->tm_year + 1900;
796 return buf;
798 case WPS_TOKEN_RTC_AM_PM_UPPER:
799 /* p: upper case AM or PM indicator */
800 if (intval)
801 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
802 return tm->tm_hour/12 == 0 ? "AM" : "PM";
804 case WPS_TOKEN_RTC_AM_PM_LOWER:
805 /* P: lower case am or pm indicator */
806 if (intval)
807 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
808 return tm->tm_hour/12 == 0 ? "am" : "pm";
810 case WPS_TOKEN_RTC_WEEKDAY_NAME:
811 /* a: abbreviated weekday name (Sun..Sat) */
812 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
814 case WPS_TOKEN_RTC_MONTH_NAME:
815 /* b: abbreviated month name (Jan..Dec) */
816 return str(LANG_MONTH_JANUARY + tm->tm_mon);
818 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
819 /* u: day of week (1..7); 1 is Monday */
820 if (intval)
821 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
822 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
823 return buf;
825 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
826 /* w: day of week (0..6); 0 is Sunday */
827 if (intval)
828 *intval = tm->tm_wday + 1;
829 snprintf(buf, buf_size, "%1d", tm->tm_wday);
830 return buf;
831 #else
832 case WPS_TOKEN_RTC_DAY_OF_MONTH:
833 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
834 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
835 case WPS_TOKEN_RTC_HOUR_24:
836 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
837 case WPS_TOKEN_RTC_HOUR_12:
838 case WPS_TOKEN_RTC_MONTH:
839 case WPS_TOKEN_RTC_MINUTE:
840 case WPS_TOKEN_RTC_SECOND:
841 case WPS_TOKEN_RTC_AM_PM_UPPER:
842 case WPS_TOKEN_RTC_AM_PM_LOWER:
843 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
844 return "--";
845 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
846 return "----";
847 case WPS_TOKEN_RTC_WEEKDAY_NAME:
848 case WPS_TOKEN_RTC_MONTH_NAME:
849 return "---";
850 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
851 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
852 return "-";
853 #endif
855 #ifdef HAVE_LCD_CHARCELLS
856 case WPS_TOKEN_PROGRESSBAR:
858 char *end = utf8encode(data->wps_progress_pat[0], buf);
859 *end = '\0';
860 return buf;
863 case WPS_TOKEN_PLAYER_PROGRESSBAR:
864 if(is_new_player())
866 /* we need 11 characters (full line) for
867 progress-bar */
868 strlcpy(buf, " ", buf_size);
870 else
872 /* Tell the user if we have an OldPlayer */
873 strlcpy(buf, " <Old LCD> ", buf_size);
875 return buf;
876 #endif
880 #if (CONFIG_CODEC == SWCODEC)
881 case WPS_TOKEN_CROSSFADE:
882 #ifdef HAVE_CROSSFADE
883 if (intval)
884 *intval = global_settings.crossfade + 1;
885 snprintf(buf, buf_size, "%d", global_settings.crossfade);
886 #else
887 snprintf(buf, buf_size, "%d", 0);
888 #endif
889 return buf;
891 case WPS_TOKEN_REPLAYGAIN:
893 int val;
895 if (global_settings.replaygain_type == REPLAYGAIN_OFF)
896 val = 1; /* off */
897 else
899 int type;
900 if (LIKELY(id3))
901 type = get_replaygain_mode(id3->track_gain_string != NULL,
902 id3->album_gain_string != NULL);
903 else
904 type = -1;
906 if (type < 0)
907 val = 6; /* no tag */
908 else
909 val = type + 2;
911 if (global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
912 val += 2;
915 if (intval)
916 *intval = val;
918 switch (val)
920 case 1:
921 case 6:
922 return "+0.00 dB";
923 break;
924 /* due to above, coming here with !id3 shouldn't be possible */
925 case 2:
926 case 4:
927 strlcpy(buf, id3->track_gain_string, buf_size);
928 break;
929 case 3:
930 case 5:
931 strlcpy(buf, id3->album_gain_string, buf_size);
932 break;
934 return buf;
936 #endif /* (CONFIG_CODEC == SWCODEC) */
938 #if (CONFIG_CODEC != MAS3507D)
939 case WPS_TOKEN_SOUND_PITCH:
941 int32_t pitch = sound_get_pitch();
942 snprintf(buf, buf_size, "%ld.%ld",
943 pitch / PITCH_SPEED_PRECISION,
944 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
946 if (intval)
947 *intval = pitch_speed_enum(limit, pitch,
948 PITCH_SPEED_PRECISION * 100);
949 return buf;
951 #endif
953 #if CONFIG_CODEC == SWCODEC
954 case WPS_TOKEN_SOUND_SPEED:
956 int32_t pitch = sound_get_pitch();
957 int32_t speed;
958 if (dsp_timestretch_available())
959 speed = GET_SPEED(pitch, dsp_get_timestretch());
960 else
961 speed = pitch;
962 snprintf(buf, buf_size, "%ld.%ld",
963 speed / PITCH_SPEED_PRECISION,
964 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
965 if (intval)
966 *intval = pitch_speed_enum(limit, speed,
967 PITCH_SPEED_PRECISION * 100);
968 return buf;
970 #endif
972 case WPS_TOKEN_MAIN_HOLD:
973 #ifdef HAS_BUTTON_HOLD
974 if (button_hold())
975 #else
976 if (is_keys_locked())
977 #endif /*hold switch or softlock*/
978 return "h";
979 else
980 return NULL;
982 #ifdef HAS_REMOTE_BUTTON_HOLD
983 case WPS_TOKEN_REMOTE_HOLD:
984 if (remote_button_hold())
985 return "r";
986 else
987 return NULL;
988 #endif
990 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
991 case WPS_TOKEN_VLED_HDD:
992 if(led_read(HZ/2))
993 return "h";
994 else
995 return NULL;
996 #endif
997 case WPS_TOKEN_BUTTON_VOLUME:
998 if (global_status.last_volume_change &&
999 TIME_BEFORE(current_tick, global_status.last_volume_change +
1000 token->value.i * TIMEOUT_UNIT))
1001 return "v";
1002 return NULL;
1004 case WPS_TOKEN_TRACK_STARTING:
1005 if (id3)
1007 int elapsed = id3->elapsed + state->ff_rewind_count;
1008 if (elapsed < token->value.i * 1000)
1009 return "starting";
1011 return NULL;
1012 case WPS_TOKEN_TRACK_ENDING:
1013 if (id3)
1015 unsigned long elapsed = id3->elapsed + state->ff_rewind_count;
1016 unsigned time = token->value.i * 1000;
1017 if (id3->length - elapsed < time)
1018 return "ending";
1020 return NULL;
1021 case WPS_TOKEN_LASTTOUCH:
1022 #ifdef HAVE_TOUCHSCREEN
1023 if (TIME_BEFORE(current_tick, token->value.i * TIMEOUT_UNIT +
1024 touchscreen_last_touch()))
1025 return "t";
1026 #endif
1027 return NULL;
1029 case WPS_TOKEN_SETTING:
1031 const struct settings_list *s = settings+token->value.i;
1032 if (intval)
1034 /* Handle contionals */
1035 switch (s->flags&F_T_MASK)
1037 case F_T_INT:
1038 case F_T_UINT:
1039 if (s->flags&F_T_SOUND)
1041 /* %?St|name|<min|min+1|...|max-1|max> */
1042 int sound_setting = s->sound_setting->setting;
1043 /* settings with decimals can't be used in conditionals */
1044 if (sound_numdecimals(sound_setting) == 0)
1046 *intval = (*(int*)s->setting-sound_min(sound_setting))
1047 /sound_steps(sound_setting) + 1;
1049 else
1050 *intval = -1;
1052 else if (s->flags&F_RGB)
1053 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1054 /* shouldn't overflow since colors are stored
1055 * on 16 bits ...
1056 * but this is pretty useless anyway */
1057 *intval = *(int*)s->setting + 1;
1058 else if (s->cfg_vals == NULL)
1059 /* %?St|name|<1st choice|2nd choice|...> */
1060 *intval = (*(int*)s->setting-s->int_setting->min)
1061 /s->int_setting->step + 1;
1062 else
1063 /* %?St|name|<1st choice|2nd choice|...> */
1064 /* Not sure about this one. cfg_name/vals are
1065 * indexed from 0 right? */
1066 *intval = *(int*)s->setting + 1;
1067 break;
1068 case F_T_BOOL:
1069 /* %?St|name|<if true|if false> */
1070 *intval = *(bool*)s->setting?1:2;
1071 break;
1072 case F_T_CHARPTR:
1073 case F_T_UCHARPTR:
1074 /* %?St|name|<if non empty string|if empty>
1075 * The string's emptyness discards the setting's
1076 * prefix and suffix */
1077 *intval = ((char*)s->setting)[0]?1:2;
1078 /* if there is a prefix we should ignore it here */
1079 if (s->filename_setting->prefix)
1080 return (char*)s->setting;
1081 break;
1082 default:
1083 /* This shouldn't happen ... but you never know */
1084 *intval = -1;
1085 break;
1088 /* Special handlng for filenames because we dont want to show the prefix */
1089 if ((s->flags&F_T_MASK) == F_T_UCHARPTR ||
1090 (s->flags&F_T_MASK) == F_T_UCHARPTR)
1092 if (s->filename_setting->prefix)
1093 return (char*)s->setting;
1095 cfg_to_string(token->value.i,buf,buf_size);
1096 return buf;
1098 case WPS_TOKEN_HAVE_TUNER:
1099 #if CONFIG_TUNER
1100 if (radio_hardware_present())
1101 return "r";
1102 #endif
1103 return NULL;
1104 /* Recording tokens */
1105 case WPS_TOKEN_HAVE_RECORDING:
1106 #ifdef HAVE_RECORDING
1107 return "r";
1108 #else
1109 return NULL;
1110 #endif
1112 #ifdef HAVE_RECORDING
1113 case WPS_TOKEN_IS_RECORDING:
1114 if (audio_status() == AUDIO_STATUS_RECORD)
1115 return "r";
1116 return NULL;
1117 case WPS_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1119 #if CONFIG_CODEC == SWCODEC
1120 unsigned long samprk;
1121 int rec_freq = global_settings.rec_frequency;
1123 #ifdef SIMULATOR
1124 samprk = 44100;
1125 #else
1126 #if defined(HAVE_SPDIF_REC)
1127 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1129 /* Use rate in use, not current measured rate if it changed */
1130 samprk = pcm_rec_sample_rate();
1131 rec_freq = 0;
1132 while (rec_freq < SAMPR_NUM_FREQ &&
1133 audio_master_sampr_list[rec_freq] != samprk)
1135 rec_freq++;
1138 else
1139 #endif
1140 samprk = rec_freq_sampr[rec_freq];
1141 #endif /* SIMULATOR */
1142 if (intval)
1144 switch (rec_freq)
1146 REC_HAVE_96_(case REC_FREQ_96:
1147 *intval = 1;
1148 break;)
1149 REC_HAVE_88_(case REC_FREQ_88:
1150 *intval = 2;
1151 break;)
1152 REC_HAVE_64_(case REC_FREQ_64:
1153 *intval = 3;
1154 break;)
1155 REC_HAVE_48_(case REC_FREQ_48:
1156 *intval = 4;
1157 break;)
1158 REC_HAVE_44_(case REC_FREQ_44:
1159 *intval = 5;
1160 break;)
1161 REC_HAVE_32_(case REC_FREQ_32:
1162 *intval = 6;
1163 break;)
1164 REC_HAVE_24_(case REC_FREQ_24:
1165 *intval = 7;
1166 break;)
1167 REC_HAVE_22_(case REC_FREQ_22:
1168 *intval = 8;
1169 break;)
1170 REC_HAVE_16_(case REC_FREQ_16:
1171 *intval = 9;
1172 break;)
1173 REC_HAVE_12_(case REC_FREQ_12:
1174 *intval = 10;
1175 break;)
1176 REC_HAVE_11_(case REC_FREQ_11:
1177 *intval = 11;
1178 break;)
1179 REC_HAVE_8_(case REC_FREQ_8:
1180 *intval = 12;
1181 break;)
1184 snprintf(buf, buf_size, "%lu.%1lu", samprk/1000,samprk%1000);
1185 #else /* HWCODEC */
1187 static const char * const freq_strings[] =
1188 {"--", "44", "48", "32", "22", "24", "16"};
1189 int freq = 1 + global_settings.rec_frequency;
1190 #ifdef HAVE_SPDIF_REC
1191 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1193 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1194 freq = 0;
1196 #endif /* HAVE_SPDIF_IN */
1197 if (intval)
1198 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1199 snprintf(buf, buf_size, "%s\n",
1200 freq_strings[global_settings.rec_frequency]);
1201 #endif
1202 return buf;
1204 #if CONFIG_CODEC == SWCODEC
1205 case WPS_TOKEN_REC_ENCODER:
1207 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1208 if (intval)
1209 *intval = rec_format;
1210 switch (rec_format)
1212 case REC_FORMAT_PCM_WAV:
1213 return "wav";
1214 case REC_FORMAT_AIFF:
1215 return "aiff";
1216 case REC_FORMAT_WAVPACK:
1217 return "wv";
1218 case REC_FORMAT_MPA_L3:
1219 return "MP3";
1220 default:
1221 return NULL;
1223 break;
1225 #endif
1226 case WPS_TOKEN_REC_BITRATE:
1227 #if CONFIG_CODEC == SWCODEC
1228 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1230 if (intval)
1232 #if 0 /* FIXME: I dont know if this is needed? */
1233 switch (1<<global_settings.mp3_enc_config.bitrate)
1235 case MP3_BITR_CAP_8:
1236 *intval = 1;
1237 break;
1238 case MP3_BITR_CAP_16:
1239 *intval = 2;
1240 break;
1241 case MP3_BITR_CAP_24:
1242 *intval = 3;
1243 break;
1244 case MP3_BITR_CAP_32:
1245 *intval = 4;
1246 break;
1247 case MP3_BITR_CAP_40:
1248 *intval = 5;
1249 break;
1250 case MP3_BITR_CAP_48:
1251 *intval = 6;
1252 break;
1253 case MP3_BITR_CAP_56:
1254 *intval = 7;
1255 break;
1256 case MP3_BITR_CAP_64:
1257 *intval = 8;
1258 break;
1259 case MP3_BITR_CAP_80:
1260 *intval = 9;
1261 break;
1262 case MP3_BITR_CAP_96:
1263 *intval = 10;
1264 break;
1265 case MP3_BITR_CAP_112:
1266 *intval = 11;
1267 break;
1268 case MP3_BITR_CAP_128:
1269 *intval = 12;
1270 break;
1271 case MP3_BITR_CAP_144:
1272 *intval = 13;
1273 break;
1274 case MP3_BITR_CAP_160:
1275 *intval = 14;
1276 break;
1277 case MP3_BITR_CAP_192:
1278 *intval = 15;
1279 break;
1281 #endif
1282 *intval = global_settings.mp3_enc_config.bitrate+1;
1284 snprintf(buf, buf_size, "%lu", global_settings.mp3_enc_config.bitrate+1);
1285 return buf;
1287 else
1288 return NULL; /* Fixme later */
1289 #else /* CONFIG_CODEC == HWCODEC */
1290 if (intval)
1291 *intval = global_settings.rec_quality+1;
1292 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1293 return buf;
1294 #endif
1295 case WPS_TOKEN_REC_MONO:
1296 if (!global_settings.rec_channels)
1297 return "m";
1298 return NULL;
1300 case WPS_TOKEN_REC_SECONDS:
1302 int time = (audio_recorded_time() / HZ) % 60;
1303 if (intval)
1304 *intval = time;
1305 snprintf(buf, buf_size, "%02d", time);
1306 return buf;
1308 case WPS_TOKEN_REC_MINUTES:
1310 int time = (audio_recorded_time() / HZ) / 60;
1311 if (intval)
1312 *intval = time;
1313 snprintf(buf, buf_size, "%02d", time);
1314 return buf;
1316 case WPS_TOKEN_REC_HOURS:
1318 int time = (audio_recorded_time() / HZ) / 3600;
1319 if (intval)
1320 *intval = time;
1321 snprintf(buf, buf_size, "%02d", time);
1322 return buf;
1325 #endif /* HAVE_RECORDING */
1327 case WPS_TOKEN_CURRENT_SCREEN:
1329 int curr_screen = current_screen();
1331 #ifdef HAVE_RECORDING
1332 /* override current_screen() for recording screen since it may
1333 * be entered from the radio screen */
1334 if (in_recording_screen())
1335 curr_screen = GO_TO_RECSCREEN;
1336 #endif
1338 switch (curr_screen)
1340 case GO_TO_WPS:
1341 curr_screen = 2;
1342 break;
1343 #ifdef HAVE_RECORDING
1344 case GO_TO_RECSCREEN:
1345 curr_screen = 3;
1346 break;
1347 #endif
1348 #if CONFIG_TUNER
1349 case GO_TO_FM:
1350 curr_screen = 4;
1351 break;
1352 #endif
1353 case GO_TO_PLAYLIST_VIEWER:
1354 curr_screen = 5;
1355 break;
1356 default: /* lists */
1357 curr_screen = 1;
1358 break;
1360 if (intval)
1362 *intval = curr_screen;
1364 snprintf(buf, buf_size, "%d", curr_screen);
1365 return buf;
1368 case WPS_TOKEN_LANG_IS_RTL:
1369 return lang_is_rtl() ? "r" : NULL;
1371 default:
1372 return NULL;