e5a34c43183773536362c2f30c5c33034e6df435
[kugel-rb.git] / apps / gui / skin_engine / skin_tokens.c
blobe5a34c43183773536362c2f30c5c33034e6df435
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
347 /* Tokens which are really only used by the radio screen go in here */
348 const char *get_radio_token(struct wps_token *token, int preset_offset,
349 char *buf, int buf_size, int limit, int *intval)
351 (void)limit;
352 switch (token->type)
354 /* Radio/tuner tokens */
355 case WPS_TOKEN_TUNER_TUNED:
356 if (tuner_get(RADIO_TUNED))
357 return "t";
358 return NULL;
359 case WPS_TOKEN_TUNER_SCANMODE:
360 if (radio_scan_mode())
361 return "s";
362 return NULL;
363 case WPS_TOKEN_TUNER_STEREO:
364 if (radio_is_stereo())
365 return "s";
366 return NULL;
367 case WPS_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
369 int freq = fm_region_data[global_settings.fm_region].freq_min / 10000;
370 snprintf(buf, buf_size, "%d.%02d", freq/100, freq%100);
371 return buf;
373 case WPS_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
375 int freq = fm_region_data[global_settings.fm_region].freq_max / 10000;
376 snprintf(buf, buf_size, "%d.%02d", freq/100, freq%100);
377 return buf;
379 case WPS_TOKEN_TUNER_CURFREQ:
381 int freq = radio_current_frequency() / 10000;
382 snprintf(buf, buf_size, "%d.%02d", freq/100, freq%100);
383 return buf;
385 case WPS_TOKEN_PRESET_ID:
386 snprintf(buf, buf_size, "%d", radio_current_preset() + 1 + preset_offset);
387 return buf;
388 case WPS_TOKEN_PRESET_NAME:
389 case WPS_TOKEN_PRESET_FREQ:
391 int preset = radio_current_preset() + preset_offset;
392 if (radio_preset_count() == 0 || preset == -1)
393 return NULL;
394 /* make sure its in the valid range */
395 while (preset < 0)
396 preset += radio_preset_count();
397 preset %= radio_preset_count();
398 if (token->type == WPS_TOKEN_PRESET_NAME)
400 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
402 else
404 int freq = radio_get_preset(preset)->frequency / 10000;
405 snprintf(buf, buf_size, "%d.%02d", freq/100, freq%100);
407 return buf;
409 case WPS_TOKEN_PRESET_COUNT:
410 snprintf(buf, buf_size, "%d", radio_preset_count());
411 if (intval)
412 *intval = radio_preset_count();
413 return buf;
414 case WPS_TOKEN_HAVE_RDS:
415 #ifdef HAVE_RDS_CAP
416 return "rds";
417 case WPS_TOKEN_RDS_NAME:
418 return tuner_get_rds_info(RADIO_RDS_NAME);
419 case WPS_TOKEN_RDS_TEXT:
420 return tuner_get_rds_info(RADIO_RDS_TEXT);
421 #else
422 return NULL; /* end of the WPS_TOKEN_HAVE_RDS case */
423 #endif /* HAVE_RDS_CAP */
425 return NULL;
427 #endif
429 /* Return the tags value as text. buf should be used as temp storage if needed.
431 intval is used with conditionals/enums: when this function is called,
432 intval should contain the number of options in the conditional/enum.
433 When this function returns, intval is -1 if the tag is non numeric or,
434 if the tag is numeric, *intval is the enum case we want to go to (between 1
435 and the original value of *intval, inclusive).
436 When not treating a conditional/enum, intval should be NULL.
438 const char *get_token_value(struct gui_wps *gwps,
439 struct wps_token *token,
440 char *buf, int buf_size,
441 int *intval)
443 if (!gwps)
444 return NULL;
446 struct wps_data *data = gwps->data;
447 struct wps_state *state = gwps->state;
448 struct mp3entry *id3; /* Think very carefully about using this.
449 maybe get_id3_token() is the better place? */
450 const char *out_text = NULL;
452 if (!data || !state)
453 return NULL;
456 if (token->next)
457 id3 = state->nid3;
458 else
459 id3 = state->id3;
461 #if CONFIG_RTC
462 struct tm* tm = NULL;
464 /* if the token is an RTC one, update the time
465 and do the necessary checks */
466 if (token->type >= WPS_TOKENS_RTC_BEGIN
467 && token->type <= WPS_TOKENS_RTC_END)
469 tm = get_time();
471 if (!valid_time(tm))
472 return NULL;
474 #endif
476 int limit = 1;
477 if (intval)
479 limit = *intval;
480 *intval = -1;
483 out_text = get_id3_token(token, id3, buf, buf_size, limit, intval);
484 if (out_text)
485 return out_text;
486 #if CONFIG_TUNER
487 out_text = get_radio_token(token, 0, buf, buf_size, limit, intval);
488 if (out_text)
489 return out_text;
490 #endif
492 switch (token->type)
494 case WPS_TOKEN_CHARACTER:
495 if (token->value.c == '\n')
496 return NULL;
497 return &(token->value.c);
499 case WPS_TOKEN_STRING:
500 return (char*)token->value.data;
502 case WPS_TOKEN_TRANSLATEDSTRING:
503 return (char*)P2STR(ID2P(token->value.i));
505 case WPS_TOKEN_PLAYLIST_ENTRIES:
506 snprintf(buf, buf_size, "%d", playlist_amount());
507 return buf;
509 case WPS_TOKEN_LIST_TITLE_TEXT:
510 return (char*)token->value.data;
511 case WPS_TOKEN_LIST_TITLE_ICON:
512 if (intval)
513 *intval = token->value.i;
514 snprintf(buf, buf_size, "%d", token->value.i);
515 return buf;
517 case WPS_TOKEN_PLAYLIST_NAME:
518 return playlist_name(NULL, buf, buf_size);
520 case WPS_TOKEN_PLAYLIST_POSITION:
521 snprintf(buf, buf_size, "%d", playlist_get_display_index());
522 return buf;
524 case WPS_TOKEN_PLAYLIST_SHUFFLE:
525 if ( global_settings.playlist_shuffle )
526 return "s";
527 else
528 return NULL;
529 break;
531 case WPS_TOKEN_VOLUME:
532 snprintf(buf, buf_size, "%d", global_settings.volume);
533 if (intval)
535 int minvol = sound_min(SOUND_VOLUME);
536 if (global_settings.volume == minvol)
538 *intval = 1;
540 else if (global_settings.volume == 0)
542 *intval = limit - 1;
544 else if (global_settings.volume > 0)
546 *intval = limit;
548 else
550 *intval = (limit-3) * (global_settings.volume - minvol - 1)
551 / (-1 - minvol) + 2;
554 return buf;
555 #ifdef HAVE_ALBUMART
556 case WPS_TOKEN_ALBUMART_FOUND:
557 if (data->albumart) {
558 if (playback_current_aa_hid(data->playback_aa_slot) >= 0)
559 return "C";
561 return NULL;
563 case WPS_TOKEN_ALBUMART_DISPLAY:
564 if (!data->albumart)
565 return NULL;
566 if (!data->albumart->draw)
567 data->albumart->draw = true;
568 return NULL;
569 #endif
571 case WPS_TOKEN_BATTERY_PERCENT:
573 int l = battery_level();
575 if (intval)
577 limit = MAX(limit, 2);
578 if (l > -1) {
579 /* First enum is used for "unknown level". */
580 *intval = (limit - 1) * l / 100 + 2;
581 } else {
582 *intval = 1;
586 if (l > -1) {
587 snprintf(buf, buf_size, "%d", l);
588 return buf;
589 } else {
590 return "?";
594 case WPS_TOKEN_BATTERY_VOLTS:
596 unsigned int v = battery_voltage();
597 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
598 return buf;
601 case WPS_TOKEN_BATTERY_TIME:
603 int t = battery_time();
604 if (t >= 0)
605 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
606 else
607 return "?h ?m";
608 return buf;
611 #if CONFIG_CHARGING
612 case WPS_TOKEN_BATTERY_CHARGER_CONNECTED:
614 if(charger_input_state==CHARGER)
615 return "p";
616 else
617 return NULL;
619 #endif
620 #if CONFIG_CHARGING >= CHARGING_MONITOR
621 case WPS_TOKEN_BATTERY_CHARGING:
623 if (charge_state == CHARGING || charge_state == TOPOFF) {
624 return "c";
625 } else {
626 return NULL;
629 #endif
630 #ifdef HAVE_USB_POWER
631 case WPS_TOKEN_USB_POWERED:
632 if (usb_powered())
633 return "u";
634 return NULL;
635 #endif
636 case WPS_TOKEN_BATTERY_SLEEPTIME:
638 if (get_sleep_timer() == 0)
639 return NULL;
640 else
642 format_time(buf, buf_size, get_sleep_timer() * 1000);
643 return buf;
647 case WPS_TOKEN_PLAYBACK_STATUS:
649 int status = current_playmode();
650 /* music */
651 int mode = 1; /* stop */
652 if (status == STATUS_PLAY)
653 mode = 2; /* play */
654 if (state->is_fading ||
655 (status == STATUS_PAUSE && !status_get_ffmode()))
656 mode = 3; /* pause */
657 else
658 { /* ff / rwd */
659 if (status_get_ffmode() == STATUS_FASTFORWARD)
660 mode = 4;
661 if (status_get_ffmode() == STATUS_FASTBACKWARD)
662 mode = 5;
664 #ifdef HAVE_RECORDING
665 /* recording */
666 if (status == STATUS_RECORD)
667 mode = 6;
668 else if (status == STATUS_RECORD_PAUSE)
669 mode = 7;
670 #endif
671 #if CONFIG_TUNER
672 /* radio */
673 if (status == STATUS_RADIO)
674 mode = 8;
675 else if (status == STATUS_RADIO_PAUSE)
676 mode = 9;
677 #endif
679 if (intval) {
680 *intval = mode;
683 snprintf(buf, buf_size, "%d", mode-1);
684 return buf;
687 case WPS_TOKEN_REPEAT_MODE:
688 if (intval)
689 *intval = global_settings.repeat_mode + 1;
690 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
691 return buf;
693 case WPS_TOKEN_RTC_PRESENT:
694 #if CONFIG_RTC
695 return "c";
696 #else
697 return NULL;
698 #endif
700 #if CONFIG_RTC
701 case WPS_TOKEN_RTC_12HOUR_CFG:
702 if (intval)
703 *intval = global_settings.timeformat + 1;
704 snprintf(buf, buf_size, "%d", global_settings.timeformat);
705 return buf;
707 case WPS_TOKEN_RTC_DAY_OF_MONTH:
708 /* d: day of month (01..31) */
709 snprintf(buf, buf_size, "%02d", tm->tm_mday);
710 if (intval)
711 *intval = tm->tm_mday - 1;
712 return buf;
714 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
715 /* e: day of month, blank padded ( 1..31) */
716 snprintf(buf, buf_size, "%2d", tm->tm_mday);
717 if (intval)
718 *intval = tm->tm_mday - 1;
719 return buf;
721 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
722 /* H: hour (00..23) */
723 snprintf(buf, buf_size, "%02d", tm->tm_hour);
724 if (intval)
725 *intval = tm->tm_hour;
726 return buf;
728 case WPS_TOKEN_RTC_HOUR_24:
729 /* k: hour ( 0..23) */
730 snprintf(buf, buf_size, "%2d", tm->tm_hour);
731 if (intval)
732 *intval = tm->tm_hour;
733 return buf;
735 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
736 /* I: hour (01..12) */
737 snprintf(buf, buf_size, "%02d",
738 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
739 if (intval)
740 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
741 return buf;
743 case WPS_TOKEN_RTC_HOUR_12:
744 /* l: hour ( 1..12) */
745 snprintf(buf, buf_size, "%2d",
746 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
747 if (intval)
748 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
749 return buf;
751 case WPS_TOKEN_RTC_MONTH:
752 /* m: month (01..12) */
753 if (intval)
754 *intval = tm->tm_mon + 1;
755 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
756 return buf;
758 case WPS_TOKEN_RTC_MINUTE:
759 /* M: minute (00..59) */
760 snprintf(buf, buf_size, "%02d", tm->tm_min);
761 if (intval)
762 *intval = tm->tm_min;
763 return buf;
765 case WPS_TOKEN_RTC_SECOND:
766 /* S: second (00..59) */
767 snprintf(buf, buf_size, "%02d", tm->tm_sec);
768 if (intval)
769 *intval = tm->tm_sec;
770 return buf;
772 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
773 /* y: last two digits of year (00..99) */
774 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
775 if (intval)
776 *intval = tm->tm_year % 100;
777 return buf;
779 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
780 /* Y: year (1970...) */
781 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
782 if (intval)
783 *intval = tm->tm_year + 1900;
784 return buf;
786 case WPS_TOKEN_RTC_AM_PM_UPPER:
787 /* p: upper case AM or PM indicator */
788 if (intval)
789 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
790 return tm->tm_hour/12 == 0 ? "AM" : "PM";
792 case WPS_TOKEN_RTC_AM_PM_LOWER:
793 /* P: lower case am or pm indicator */
794 if (intval)
795 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
796 return tm->tm_hour/12 == 0 ? "am" : "pm";
798 case WPS_TOKEN_RTC_WEEKDAY_NAME:
799 /* a: abbreviated weekday name (Sun..Sat) */
800 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
802 case WPS_TOKEN_RTC_MONTH_NAME:
803 /* b: abbreviated month name (Jan..Dec) */
804 return str(LANG_MONTH_JANUARY + tm->tm_mon);
806 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
807 /* u: day of week (1..7); 1 is Monday */
808 if (intval)
809 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
810 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
811 return buf;
813 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
814 /* w: day of week (0..6); 0 is Sunday */
815 if (intval)
816 *intval = tm->tm_wday + 1;
817 snprintf(buf, buf_size, "%1d", tm->tm_wday);
818 return buf;
819 #else
820 case WPS_TOKEN_RTC_DAY_OF_MONTH:
821 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
822 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
823 case WPS_TOKEN_RTC_HOUR_24:
824 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
825 case WPS_TOKEN_RTC_HOUR_12:
826 case WPS_TOKEN_RTC_MONTH:
827 case WPS_TOKEN_RTC_MINUTE:
828 case WPS_TOKEN_RTC_SECOND:
829 case WPS_TOKEN_RTC_AM_PM_UPPER:
830 case WPS_TOKEN_RTC_AM_PM_LOWER:
831 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
832 return "--";
833 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
834 return "----";
835 case WPS_TOKEN_RTC_WEEKDAY_NAME:
836 case WPS_TOKEN_RTC_MONTH_NAME:
837 return "---";
838 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
839 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
840 return "-";
841 #endif
843 #ifdef HAVE_LCD_CHARCELLS
844 case WPS_TOKEN_PROGRESSBAR:
846 char *end = utf8encode(data->wps_progress_pat[0], buf);
847 *end = '\0';
848 return buf;
851 case WPS_TOKEN_PLAYER_PROGRESSBAR:
852 if(is_new_player())
854 /* we need 11 characters (full line) for
855 progress-bar */
856 strlcpy(buf, " ", buf_size);
858 else
860 /* Tell the user if we have an OldPlayer */
861 strlcpy(buf, " <Old LCD> ", buf_size);
863 return buf;
864 #endif
868 #if (CONFIG_CODEC == SWCODEC)
869 case WPS_TOKEN_CROSSFADE:
870 #ifdef HAVE_CROSSFADE
871 if (intval)
872 *intval = global_settings.crossfade + 1;
873 snprintf(buf, buf_size, "%d", global_settings.crossfade);
874 #else
875 snprintf(buf, buf_size, "%d", 0);
876 #endif
877 return buf;
879 case WPS_TOKEN_REPLAYGAIN:
881 int val;
883 if (global_settings.replaygain_type == REPLAYGAIN_OFF)
884 val = 1; /* off */
885 else
887 int type;
888 if (LIKELY(id3))
889 type = get_replaygain_mode(id3->track_gain_string != NULL,
890 id3->album_gain_string != NULL);
891 else
892 type = -1;
894 if (type < 0)
895 val = 6; /* no tag */
896 else
897 val = type + 2;
899 if (global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
900 val += 2;
903 if (intval)
904 *intval = val;
906 switch (val)
908 case 1:
909 case 6:
910 return "+0.00 dB";
911 break;
912 /* due to above, coming here with !id3 shouldn't be possible */
913 case 2:
914 case 4:
915 strlcpy(buf, id3->track_gain_string, buf_size);
916 break;
917 case 3:
918 case 5:
919 strlcpy(buf, id3->album_gain_string, buf_size);
920 break;
922 return buf;
924 #endif /* (CONFIG_CODEC == SWCODEC) */
926 #if (CONFIG_CODEC != MAS3507D)
927 case WPS_TOKEN_SOUND_PITCH:
929 int32_t pitch = sound_get_pitch();
930 snprintf(buf, buf_size, "%ld.%ld",
931 pitch / PITCH_SPEED_PRECISION,
932 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
934 if (intval)
935 *intval = pitch_speed_enum(limit, pitch,
936 PITCH_SPEED_PRECISION * 100);
937 return buf;
939 #endif
941 #if CONFIG_CODEC == SWCODEC
942 case WPS_TOKEN_SOUND_SPEED:
944 int32_t pitch = sound_get_pitch();
945 int32_t speed;
946 if (dsp_timestretch_available())
947 speed = GET_SPEED(pitch, dsp_get_timestretch());
948 else
949 speed = pitch;
950 snprintf(buf, buf_size, "%ld.%ld",
951 speed / PITCH_SPEED_PRECISION,
952 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
953 if (intval)
954 *intval = pitch_speed_enum(limit, speed,
955 PITCH_SPEED_PRECISION * 100);
956 return buf;
958 #endif
960 case WPS_TOKEN_MAIN_HOLD:
961 #ifdef HAS_BUTTON_HOLD
962 if (button_hold())
963 #else
964 if (is_keys_locked())
965 #endif /*hold switch or softlock*/
966 return "h";
967 else
968 return NULL;
970 #ifdef HAS_REMOTE_BUTTON_HOLD
971 case WPS_TOKEN_REMOTE_HOLD:
972 if (remote_button_hold())
973 return "r";
974 else
975 return NULL;
976 #endif
978 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
979 case WPS_TOKEN_VLED_HDD:
980 if(led_read(HZ/2))
981 return "h";
982 else
983 return NULL;
984 #endif
985 case WPS_TOKEN_BUTTON_VOLUME:
986 if (global_status.last_volume_change &&
987 TIME_BEFORE(current_tick, global_status.last_volume_change +
988 token->value.i * TIMEOUT_UNIT))
989 return "v";
990 return NULL;
992 case WPS_TOKEN_TRACK_STARTING:
993 if (id3)
995 int elapsed = id3->elapsed + state->ff_rewind_count;
996 if (elapsed < token->value.i * 1000)
997 return "starting";
999 return NULL;
1000 case WPS_TOKEN_TRACK_ENDING:
1001 if (id3)
1003 unsigned long elapsed = id3->elapsed + state->ff_rewind_count;
1004 unsigned time = token->value.i * 1000;
1005 if (id3->length - elapsed < time)
1006 return "ending";
1008 return NULL;
1009 case WPS_TOKEN_LASTTOUCH:
1010 #ifdef HAVE_TOUCHSCREEN
1011 if (TIME_BEFORE(current_tick, token->value.i * TIMEOUT_UNIT +
1012 touchscreen_last_touch()))
1013 return "t";
1014 #endif
1015 return NULL;
1017 case WPS_TOKEN_SETTING:
1019 const struct settings_list *s = settings+token->value.i;
1020 if (intval)
1022 /* Handle contionals */
1023 switch (s->flags&F_T_MASK)
1025 case F_T_INT:
1026 case F_T_UINT:
1027 if (s->flags&F_T_SOUND)
1029 /* %?St|name|<min|min+1|...|max-1|max> */
1030 int sound_setting = s->sound_setting->setting;
1031 /* settings with decimals can't be used in conditionals */
1032 if (sound_numdecimals(sound_setting) == 0)
1034 *intval = (*(int*)s->setting-sound_min(sound_setting))
1035 /sound_steps(sound_setting) + 1;
1037 else
1038 *intval = -1;
1040 else if (s->flags&F_RGB)
1041 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1042 /* shouldn't overflow since colors are stored
1043 * on 16 bits ...
1044 * but this is pretty useless anyway */
1045 *intval = *(int*)s->setting + 1;
1046 else if (s->cfg_vals == NULL)
1047 /* %?St|name|<1st choice|2nd choice|...> */
1048 *intval = (*(int*)s->setting-s->int_setting->min)
1049 /s->int_setting->step + 1;
1050 else
1051 /* %?St|name|<1st choice|2nd choice|...> */
1052 /* Not sure about this one. cfg_name/vals are
1053 * indexed from 0 right? */
1054 *intval = *(int*)s->setting + 1;
1055 break;
1056 case F_T_BOOL:
1057 /* %?St|name|<if true|if false> */
1058 *intval = *(bool*)s->setting?1:2;
1059 break;
1060 case F_T_CHARPTR:
1061 case F_T_UCHARPTR:
1062 /* %?St|name|<if non empty string|if empty>
1063 * The string's emptyness discards the setting's
1064 * prefix and suffix */
1065 *intval = ((char*)s->setting)[0]?1:2;
1066 /* if there is a prefix we should ignore it here */
1067 if (s->filename_setting->prefix)
1068 return (char*)s->setting;
1069 break;
1070 default:
1071 /* This shouldn't happen ... but you never know */
1072 *intval = -1;
1073 break;
1076 /* Special handlng for filenames because we dont want to show the prefix */
1077 if ((s->flags&F_T_MASK) == F_T_UCHARPTR ||
1078 (s->flags&F_T_MASK) == F_T_UCHARPTR)
1080 if (s->filename_setting->prefix)
1081 return (char*)s->setting;
1083 cfg_to_string(token->value.i,buf,buf_size);
1084 return buf;
1086 case WPS_TOKEN_HAVE_TUNER:
1087 #if CONFIG_TUNER
1088 if (radio_hardware_present())
1089 return "r";
1090 #endif
1091 return NULL;
1092 /* Recording tokens */
1093 case WPS_TOKEN_HAVE_RECORDING:
1094 #ifdef HAVE_RECORDING
1095 return "r";
1096 #else
1097 return NULL;
1098 #endif
1100 #ifdef HAVE_RECORDING
1101 case WPS_TOKEN_IS_RECORDING:
1102 if (audio_status() == AUDIO_STATUS_RECORD)
1103 return "r";
1104 return NULL;
1105 case WPS_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1107 #if CONFIG_CODEC == SWCODEC
1108 unsigned long samprk;
1109 int rec_freq = global_settings.rec_frequency;
1111 #ifdef SIMULATOR
1112 samprk = 44100;
1113 #else
1114 #if defined(HAVE_SPDIF_REC)
1115 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1117 /* Use rate in use, not current measured rate if it changed */
1118 samprk = pcm_rec_sample_rate();
1119 rec_freq = 0;
1120 while (rec_freq < SAMPR_NUM_FREQ &&
1121 audio_master_sampr_list[rec_freq] != samprk)
1123 rec_freq++;
1126 else
1127 #endif
1128 samprk = rec_freq_sampr[rec_freq];
1129 #endif /* SIMULATOR */
1130 if (intval)
1132 switch (rec_freq)
1134 REC_HAVE_96_(case REC_FREQ_96:
1135 *intval = 1;
1136 break;)
1137 REC_HAVE_88_(case REC_FREQ_88:
1138 *intval = 2;
1139 break;)
1140 REC_HAVE_64_(case REC_FREQ_64:
1141 *intval = 3;
1142 break;)
1143 REC_HAVE_48_(case REC_FREQ_48:
1144 *intval = 4;
1145 break;)
1146 REC_HAVE_44_(case REC_FREQ_44:
1147 *intval = 5;
1148 break;)
1149 REC_HAVE_32_(case REC_FREQ_32:
1150 *intval = 6;
1151 break;)
1152 REC_HAVE_24_(case REC_FREQ_24:
1153 *intval = 7;
1154 break;)
1155 REC_HAVE_22_(case REC_FREQ_22:
1156 *intval = 8;
1157 break;)
1158 REC_HAVE_16_(case REC_FREQ_16:
1159 *intval = 9;
1160 break;)
1161 REC_HAVE_12_(case REC_FREQ_12:
1162 *intval = 10;
1163 break;)
1164 REC_HAVE_11_(case REC_FREQ_11:
1165 *intval = 11;
1166 break;)
1167 REC_HAVE_8_(case REC_FREQ_8:
1168 *intval = 12;
1169 break;)
1172 snprintf(buf, buf_size, "%lu.%1lu", samprk/1000,samprk%1000);
1173 #else /* HWCODEC */
1175 static const char * const freq_strings[] =
1176 {"--", "44", "48", "32", "22", "24", "16"};
1177 int freq = 1 + global_settings.rec_frequency;
1178 #ifdef HAVE_SPDIF_REC
1179 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1181 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1182 freq = 0;
1184 #endif /* HAVE_SPDIF_IN */
1185 if (intval)
1186 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1187 snprintf(buf, buf_size, "%s\n",
1188 freq_strings[global_settings.rec_frequency]);
1189 #endif
1190 return buf;
1192 #if CONFIG_CODEC == SWCODEC
1193 case WPS_TOKEN_REC_ENCODER:
1195 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1196 if (intval)
1197 *intval = rec_format;
1198 switch (rec_format)
1200 case REC_FORMAT_PCM_WAV:
1201 return "wav";
1202 case REC_FORMAT_AIFF:
1203 return "aiff";
1204 case REC_FORMAT_WAVPACK:
1205 return "wv";
1206 case REC_FORMAT_MPA_L3:
1207 return "MP3";
1208 default:
1209 return NULL;
1211 break;
1213 #endif
1214 case WPS_TOKEN_REC_BITRATE:
1215 #if CONFIG_CODEC == SWCODEC
1216 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1218 if (intval)
1220 #if 0 /* FIXME: I dont know if this is needed? */
1221 switch (1<<global_settings.mp3_enc_config.bitrate)
1223 case MP3_BITR_CAP_8:
1224 *intval = 1;
1225 break;
1226 case MP3_BITR_CAP_16:
1227 *intval = 2;
1228 break;
1229 case MP3_BITR_CAP_24:
1230 *intval = 3;
1231 break;
1232 case MP3_BITR_CAP_32:
1233 *intval = 4;
1234 break;
1235 case MP3_BITR_CAP_40:
1236 *intval = 5;
1237 break;
1238 case MP3_BITR_CAP_48:
1239 *intval = 6;
1240 break;
1241 case MP3_BITR_CAP_56:
1242 *intval = 7;
1243 break;
1244 case MP3_BITR_CAP_64:
1245 *intval = 8;
1246 break;
1247 case MP3_BITR_CAP_80:
1248 *intval = 9;
1249 break;
1250 case MP3_BITR_CAP_96:
1251 *intval = 10;
1252 break;
1253 case MP3_BITR_CAP_112:
1254 *intval = 11;
1255 break;
1256 case MP3_BITR_CAP_128:
1257 *intval = 12;
1258 break;
1259 case MP3_BITR_CAP_144:
1260 *intval = 13;
1261 break;
1262 case MP3_BITR_CAP_160:
1263 *intval = 14;
1264 break;
1265 case MP3_BITR_CAP_192:
1266 *intval = 15;
1267 break;
1269 #endif
1270 *intval = global_settings.mp3_enc_config.bitrate+1;
1272 snprintf(buf, buf_size, "%lu", global_settings.mp3_enc_config.bitrate+1);
1273 return buf;
1275 else
1276 return NULL; /* Fixme later */
1277 #else /* CONFIG_CODEC == HWCODEC */
1278 if (intval)
1279 *intval = global_settings.rec_quality+1;
1280 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1281 return buf;
1282 #endif
1283 case WPS_TOKEN_REC_MONO:
1284 if (!global_settings.rec_channels)
1285 return "m";
1286 return NULL;
1288 case WPS_TOKEN_REC_SECONDS:
1290 int time = (audio_recorded_time() / HZ) % 60;
1291 if (intval)
1292 *intval = time;
1293 snprintf(buf, buf_size, "%02d", time);
1294 return buf;
1296 case WPS_TOKEN_REC_MINUTES:
1298 int time = (audio_recorded_time() / HZ) / 60;
1299 if (intval)
1300 *intval = time;
1301 snprintf(buf, buf_size, "%02d", time);
1302 return buf;
1304 case WPS_TOKEN_REC_HOURS:
1306 int time = (audio_recorded_time() / HZ) / 3600;
1307 if (intval)
1308 *intval = time;
1309 snprintf(buf, buf_size, "%02d", time);
1310 return buf;
1313 #endif /* HAVE_RECORDING */
1315 case WPS_TOKEN_CURRENT_SCREEN:
1317 int curr_screen = current_screen();
1319 #ifdef HAVE_RECORDING
1320 /* override current_screen() for recording screen since it may
1321 * be entered from the radio screen */
1322 if (in_recording_screen())
1323 curr_screen = GO_TO_RECSCREEN;
1324 #endif
1326 switch (curr_screen)
1328 case GO_TO_WPS:
1329 curr_screen = 2;
1330 break;
1331 #ifdef HAVE_RECORDING
1332 case GO_TO_RECSCREEN:
1333 curr_screen = 3;
1334 break;
1335 #endif
1336 #if CONFIG_TUNER
1337 case GO_TO_FM:
1338 curr_screen = 4;
1339 break;
1340 #endif
1341 case GO_TO_PLAYLIST_VIEWER:
1342 curr_screen = 5;
1343 break;
1344 default: /* lists */
1345 curr_screen = 1;
1346 break;
1348 if (intval)
1350 *intval = curr_screen;
1352 snprintf(buf, buf_size, "%d", curr_screen);
1353 return buf;
1356 case WPS_TOKEN_LANG_IS_RTL:
1357 return lang_is_rtl() ? "r" : NULL;
1359 default:
1360 return NULL;