Avoid duplicated code, create a formatting function for FM frequency
[kugel-rb.git] / apps / gui / skin_engine / skin_tokens.c
blob165c3b9b43ee3eac984d8fecc42c92ba247c5808
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 = radio_current_preset() + preset_offset;
402 if (radio_preset_count() == 0 || preset == -1)
403 return NULL;
404 /* make sure its in the valid range */
405 while (preset < 0)
406 preset += radio_preset_count();
407 preset %= radio_preset_count();
408 if (token->type == WPS_TOKEN_PRESET_NAME)
410 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
412 else
414 format_freq_MHz(radio_get_preset(preset)->frequency,
415 buf, buf_size);
417 return buf;
419 case WPS_TOKEN_PRESET_COUNT:
420 snprintf(buf, buf_size, "%d", radio_preset_count());
421 if (intval)
422 *intval = radio_preset_count();
423 return buf;
424 case WPS_TOKEN_HAVE_RDS:
425 #ifdef HAVE_RDS_CAP
426 return "rds";
427 case WPS_TOKEN_RDS_NAME:
428 return tuner_get_rds_info(RADIO_RDS_NAME);
429 case WPS_TOKEN_RDS_TEXT:
430 return tuner_get_rds_info(RADIO_RDS_TEXT);
431 #else
432 return NULL; /* end of the WPS_TOKEN_HAVE_RDS case */
433 #endif /* HAVE_RDS_CAP */
435 return NULL;
437 #endif
439 /* Return the tags value as text. buf should be used as temp storage if needed.
441 intval is used with conditionals/enums: when this function is called,
442 intval should contain the number of options in the conditional/enum.
443 When this function returns, intval is -1 if the tag is non numeric or,
444 if the tag is numeric, *intval is the enum case we want to go to (between 1
445 and the original value of *intval, inclusive).
446 When not treating a conditional/enum, intval should be NULL.
448 const char *get_token_value(struct gui_wps *gwps,
449 struct wps_token *token,
450 char *buf, int buf_size,
451 int *intval)
453 if (!gwps)
454 return NULL;
456 struct wps_data *data = gwps->data;
457 struct wps_state *state = gwps->state;
458 struct mp3entry *id3; /* Think very carefully about using this.
459 maybe get_id3_token() is the better place? */
460 const char *out_text = NULL;
462 if (!data || !state)
463 return NULL;
466 if (token->next)
467 id3 = state->nid3;
468 else
469 id3 = state->id3;
471 #if CONFIG_RTC
472 struct tm* tm = NULL;
474 /* if the token is an RTC one, update the time
475 and do the necessary checks */
476 if (token->type >= WPS_TOKENS_RTC_BEGIN
477 && token->type <= WPS_TOKENS_RTC_END)
479 tm = get_time();
481 if (!valid_time(tm))
482 return NULL;
484 #endif
486 int limit = 1;
487 if (intval)
489 limit = *intval;
490 *intval = -1;
493 out_text = get_id3_token(token, id3, buf, buf_size, limit, intval);
494 if (out_text)
495 return out_text;
496 #if CONFIG_TUNER
497 out_text = get_radio_token(token, 0, buf, buf_size, limit, intval);
498 if (out_text)
499 return out_text;
500 #endif
502 switch (token->type)
504 case WPS_TOKEN_CHARACTER:
505 if (token->value.c == '\n')
506 return NULL;
507 return &(token->value.c);
509 case WPS_TOKEN_STRING:
510 return (char*)token->value.data;
512 case WPS_TOKEN_TRANSLATEDSTRING:
513 return (char*)P2STR(ID2P(token->value.i));
515 case WPS_TOKEN_PLAYLIST_ENTRIES:
516 snprintf(buf, buf_size, "%d", playlist_amount());
517 return buf;
519 case WPS_TOKEN_LIST_TITLE_TEXT:
520 return (char*)token->value.data;
521 case WPS_TOKEN_LIST_TITLE_ICON:
522 if (intval)
523 *intval = token->value.i;
524 snprintf(buf, buf_size, "%d", token->value.i);
525 return buf;
527 case WPS_TOKEN_PLAYLIST_NAME:
528 return playlist_name(NULL, buf, buf_size);
530 case WPS_TOKEN_PLAYLIST_POSITION:
531 snprintf(buf, buf_size, "%d", playlist_get_display_index());
532 return buf;
534 case WPS_TOKEN_PLAYLIST_SHUFFLE:
535 if ( global_settings.playlist_shuffle )
536 return "s";
537 else
538 return NULL;
539 break;
541 case WPS_TOKEN_VOLUME:
542 snprintf(buf, buf_size, "%d", global_settings.volume);
543 if (intval)
545 int minvol = sound_min(SOUND_VOLUME);
546 if (global_settings.volume == minvol)
548 *intval = 1;
550 else if (global_settings.volume == 0)
552 *intval = limit - 1;
554 else if (global_settings.volume > 0)
556 *intval = limit;
558 else
560 *intval = (limit-3) * (global_settings.volume - minvol - 1)
561 / (-1 - minvol) + 2;
564 return buf;
565 #ifdef HAVE_ALBUMART
566 case WPS_TOKEN_ALBUMART_FOUND:
567 if (data->albumart) {
568 if (playback_current_aa_hid(data->playback_aa_slot) >= 0)
569 return "C";
571 return NULL;
573 case WPS_TOKEN_ALBUMART_DISPLAY:
574 if (!data->albumart)
575 return NULL;
576 if (!data->albumart->draw)
577 data->albumart->draw = true;
578 return NULL;
579 #endif
581 case WPS_TOKEN_BATTERY_PERCENT:
583 int l = battery_level();
585 if (intval)
587 limit = MAX(limit, 2);
588 if (l > -1) {
589 /* First enum is used for "unknown level". */
590 *intval = (limit - 1) * l / 100 + 2;
591 } else {
592 *intval = 1;
596 if (l > -1) {
597 snprintf(buf, buf_size, "%d", l);
598 return buf;
599 } else {
600 return "?";
604 case WPS_TOKEN_BATTERY_VOLTS:
606 unsigned int v = battery_voltage();
607 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
608 return buf;
611 case WPS_TOKEN_BATTERY_TIME:
613 int t = battery_time();
614 if (t >= 0)
615 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
616 else
617 return "?h ?m";
618 return buf;
621 #if CONFIG_CHARGING
622 case WPS_TOKEN_BATTERY_CHARGER_CONNECTED:
624 if(charger_input_state==CHARGER)
625 return "p";
626 else
627 return NULL;
629 #endif
630 #if CONFIG_CHARGING >= CHARGING_MONITOR
631 case WPS_TOKEN_BATTERY_CHARGING:
633 if (charge_state == CHARGING || charge_state == TOPOFF) {
634 return "c";
635 } else {
636 return NULL;
639 #endif
640 #ifdef HAVE_USB_POWER
641 case WPS_TOKEN_USB_POWERED:
642 if (usb_powered())
643 return "u";
644 return NULL;
645 #endif
646 case WPS_TOKEN_BATTERY_SLEEPTIME:
648 if (get_sleep_timer() == 0)
649 return NULL;
650 else
652 format_time(buf, buf_size, get_sleep_timer() * 1000);
653 return buf;
657 case WPS_TOKEN_PLAYBACK_STATUS:
659 int status = current_playmode();
660 /* music */
661 int mode = 1; /* stop */
662 if (status == STATUS_PLAY)
663 mode = 2; /* play */
664 if (state->is_fading ||
665 (status == STATUS_PAUSE && !status_get_ffmode()))
666 mode = 3; /* pause */
667 else
668 { /* ff / rwd */
669 if (status_get_ffmode() == STATUS_FASTFORWARD)
670 mode = 4;
671 if (status_get_ffmode() == STATUS_FASTBACKWARD)
672 mode = 5;
674 #ifdef HAVE_RECORDING
675 /* recording */
676 if (status == STATUS_RECORD)
677 mode = 6;
678 else if (status == STATUS_RECORD_PAUSE)
679 mode = 7;
680 #endif
681 #if CONFIG_TUNER
682 /* radio */
683 if (status == STATUS_RADIO)
684 mode = 8;
685 else if (status == STATUS_RADIO_PAUSE)
686 mode = 9;
687 #endif
689 if (intval) {
690 *intval = mode;
693 snprintf(buf, buf_size, "%d", mode-1);
694 return buf;
697 case WPS_TOKEN_REPEAT_MODE:
698 if (intval)
699 *intval = global_settings.repeat_mode + 1;
700 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
701 return buf;
703 case WPS_TOKEN_RTC_PRESENT:
704 #if CONFIG_RTC
705 return "c";
706 #else
707 return NULL;
708 #endif
710 #if CONFIG_RTC
711 case WPS_TOKEN_RTC_12HOUR_CFG:
712 if (intval)
713 *intval = global_settings.timeformat + 1;
714 snprintf(buf, buf_size, "%d", global_settings.timeformat);
715 return buf;
717 case WPS_TOKEN_RTC_DAY_OF_MONTH:
718 /* d: day of month (01..31) */
719 snprintf(buf, buf_size, "%02d", tm->tm_mday);
720 if (intval)
721 *intval = tm->tm_mday - 1;
722 return buf;
724 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
725 /* e: day of month, blank padded ( 1..31) */
726 snprintf(buf, buf_size, "%2d", tm->tm_mday);
727 if (intval)
728 *intval = tm->tm_mday - 1;
729 return buf;
731 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
732 /* H: hour (00..23) */
733 snprintf(buf, buf_size, "%02d", tm->tm_hour);
734 if (intval)
735 *intval = tm->tm_hour;
736 return buf;
738 case WPS_TOKEN_RTC_HOUR_24:
739 /* k: hour ( 0..23) */
740 snprintf(buf, buf_size, "%2d", tm->tm_hour);
741 if (intval)
742 *intval = tm->tm_hour;
743 return buf;
745 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
746 /* I: hour (01..12) */
747 snprintf(buf, buf_size, "%02d",
748 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
749 if (intval)
750 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
751 return buf;
753 case WPS_TOKEN_RTC_HOUR_12:
754 /* l: hour ( 1..12) */
755 snprintf(buf, buf_size, "%2d",
756 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
757 if (intval)
758 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
759 return buf;
761 case WPS_TOKEN_RTC_MONTH:
762 /* m: month (01..12) */
763 if (intval)
764 *intval = tm->tm_mon + 1;
765 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
766 return buf;
768 case WPS_TOKEN_RTC_MINUTE:
769 /* M: minute (00..59) */
770 snprintf(buf, buf_size, "%02d", tm->tm_min);
771 if (intval)
772 *intval = tm->tm_min;
773 return buf;
775 case WPS_TOKEN_RTC_SECOND:
776 /* S: second (00..59) */
777 snprintf(buf, buf_size, "%02d", tm->tm_sec);
778 if (intval)
779 *intval = tm->tm_sec;
780 return buf;
782 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
783 /* y: last two digits of year (00..99) */
784 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
785 if (intval)
786 *intval = tm->tm_year % 100;
787 return buf;
789 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
790 /* Y: year (1970...) */
791 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
792 if (intval)
793 *intval = tm->tm_year + 1900;
794 return buf;
796 case WPS_TOKEN_RTC_AM_PM_UPPER:
797 /* p: upper case AM or PM indicator */
798 if (intval)
799 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
800 return tm->tm_hour/12 == 0 ? "AM" : "PM";
802 case WPS_TOKEN_RTC_AM_PM_LOWER:
803 /* P: lower case am or pm indicator */
804 if (intval)
805 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
806 return tm->tm_hour/12 == 0 ? "am" : "pm";
808 case WPS_TOKEN_RTC_WEEKDAY_NAME:
809 /* a: abbreviated weekday name (Sun..Sat) */
810 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
812 case WPS_TOKEN_RTC_MONTH_NAME:
813 /* b: abbreviated month name (Jan..Dec) */
814 return str(LANG_MONTH_JANUARY + tm->tm_mon);
816 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
817 /* u: day of week (1..7); 1 is Monday */
818 if (intval)
819 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
820 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
821 return buf;
823 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
824 /* w: day of week (0..6); 0 is Sunday */
825 if (intval)
826 *intval = tm->tm_wday + 1;
827 snprintf(buf, buf_size, "%1d", tm->tm_wday);
828 return buf;
829 #else
830 case WPS_TOKEN_RTC_DAY_OF_MONTH:
831 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
832 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
833 case WPS_TOKEN_RTC_HOUR_24:
834 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
835 case WPS_TOKEN_RTC_HOUR_12:
836 case WPS_TOKEN_RTC_MONTH:
837 case WPS_TOKEN_RTC_MINUTE:
838 case WPS_TOKEN_RTC_SECOND:
839 case WPS_TOKEN_RTC_AM_PM_UPPER:
840 case WPS_TOKEN_RTC_AM_PM_LOWER:
841 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
842 return "--";
843 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
844 return "----";
845 case WPS_TOKEN_RTC_WEEKDAY_NAME:
846 case WPS_TOKEN_RTC_MONTH_NAME:
847 return "---";
848 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
849 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
850 return "-";
851 #endif
853 #ifdef HAVE_LCD_CHARCELLS
854 case WPS_TOKEN_PROGRESSBAR:
856 char *end = utf8encode(data->wps_progress_pat[0], buf);
857 *end = '\0';
858 return buf;
861 case WPS_TOKEN_PLAYER_PROGRESSBAR:
862 if(is_new_player())
864 /* we need 11 characters (full line) for
865 progress-bar */
866 strlcpy(buf, " ", buf_size);
868 else
870 /* Tell the user if we have an OldPlayer */
871 strlcpy(buf, " <Old LCD> ", buf_size);
873 return buf;
874 #endif
878 #if (CONFIG_CODEC == SWCODEC)
879 case WPS_TOKEN_CROSSFADE:
880 #ifdef HAVE_CROSSFADE
881 if (intval)
882 *intval = global_settings.crossfade + 1;
883 snprintf(buf, buf_size, "%d", global_settings.crossfade);
884 #else
885 snprintf(buf, buf_size, "%d", 0);
886 #endif
887 return buf;
889 case WPS_TOKEN_REPLAYGAIN:
891 int val;
893 if (global_settings.replaygain_type == REPLAYGAIN_OFF)
894 val = 1; /* off */
895 else
897 int type;
898 if (LIKELY(id3))
899 type = get_replaygain_mode(id3->track_gain_string != NULL,
900 id3->album_gain_string != NULL);
901 else
902 type = -1;
904 if (type < 0)
905 val = 6; /* no tag */
906 else
907 val = type + 2;
909 if (global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
910 val += 2;
913 if (intval)
914 *intval = val;
916 switch (val)
918 case 1:
919 case 6:
920 return "+0.00 dB";
921 break;
922 /* due to above, coming here with !id3 shouldn't be possible */
923 case 2:
924 case 4:
925 strlcpy(buf, id3->track_gain_string, buf_size);
926 break;
927 case 3:
928 case 5:
929 strlcpy(buf, id3->album_gain_string, buf_size);
930 break;
932 return buf;
934 #endif /* (CONFIG_CODEC == SWCODEC) */
936 #if (CONFIG_CODEC != MAS3507D)
937 case WPS_TOKEN_SOUND_PITCH:
939 int32_t pitch = sound_get_pitch();
940 snprintf(buf, buf_size, "%ld.%ld",
941 pitch / PITCH_SPEED_PRECISION,
942 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
944 if (intval)
945 *intval = pitch_speed_enum(limit, pitch,
946 PITCH_SPEED_PRECISION * 100);
947 return buf;
949 #endif
951 #if CONFIG_CODEC == SWCODEC
952 case WPS_TOKEN_SOUND_SPEED:
954 int32_t pitch = sound_get_pitch();
955 int32_t speed;
956 if (dsp_timestretch_available())
957 speed = GET_SPEED(pitch, dsp_get_timestretch());
958 else
959 speed = pitch;
960 snprintf(buf, buf_size, "%ld.%ld",
961 speed / PITCH_SPEED_PRECISION,
962 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
963 if (intval)
964 *intval = pitch_speed_enum(limit, speed,
965 PITCH_SPEED_PRECISION * 100);
966 return buf;
968 #endif
970 case WPS_TOKEN_MAIN_HOLD:
971 #ifdef HAS_BUTTON_HOLD
972 if (button_hold())
973 #else
974 if (is_keys_locked())
975 #endif /*hold switch or softlock*/
976 return "h";
977 else
978 return NULL;
980 #ifdef HAS_REMOTE_BUTTON_HOLD
981 case WPS_TOKEN_REMOTE_HOLD:
982 if (remote_button_hold())
983 return "r";
984 else
985 return NULL;
986 #endif
988 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
989 case WPS_TOKEN_VLED_HDD:
990 if(led_read(HZ/2))
991 return "h";
992 else
993 return NULL;
994 #endif
995 case WPS_TOKEN_BUTTON_VOLUME:
996 if (global_status.last_volume_change &&
997 TIME_BEFORE(current_tick, global_status.last_volume_change +
998 token->value.i * TIMEOUT_UNIT))
999 return "v";
1000 return NULL;
1002 case WPS_TOKEN_TRACK_STARTING:
1003 if (id3)
1005 int elapsed = id3->elapsed + state->ff_rewind_count;
1006 if (elapsed < token->value.i * 1000)
1007 return "starting";
1009 return NULL;
1010 case WPS_TOKEN_TRACK_ENDING:
1011 if (id3)
1013 unsigned long elapsed = id3->elapsed + state->ff_rewind_count;
1014 unsigned time = token->value.i * 1000;
1015 if (id3->length - elapsed < time)
1016 return "ending";
1018 return NULL;
1019 case WPS_TOKEN_LASTTOUCH:
1020 #ifdef HAVE_TOUCHSCREEN
1021 if (TIME_BEFORE(current_tick, token->value.i * TIMEOUT_UNIT +
1022 touchscreen_last_touch()))
1023 return "t";
1024 #endif
1025 return NULL;
1027 case WPS_TOKEN_SETTING:
1029 const struct settings_list *s = settings+token->value.i;
1030 if (intval)
1032 /* Handle contionals */
1033 switch (s->flags&F_T_MASK)
1035 case F_T_INT:
1036 case F_T_UINT:
1037 if (s->flags&F_T_SOUND)
1039 /* %?St|name|<min|min+1|...|max-1|max> */
1040 int sound_setting = s->sound_setting->setting;
1041 /* settings with decimals can't be used in conditionals */
1042 if (sound_numdecimals(sound_setting) == 0)
1044 *intval = (*(int*)s->setting-sound_min(sound_setting))
1045 /sound_steps(sound_setting) + 1;
1047 else
1048 *intval = -1;
1050 else if (s->flags&F_RGB)
1051 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1052 /* shouldn't overflow since colors are stored
1053 * on 16 bits ...
1054 * but this is pretty useless anyway */
1055 *intval = *(int*)s->setting + 1;
1056 else if (s->cfg_vals == NULL)
1057 /* %?St|name|<1st choice|2nd choice|...> */
1058 *intval = (*(int*)s->setting-s->int_setting->min)
1059 /s->int_setting->step + 1;
1060 else
1061 /* %?St|name|<1st choice|2nd choice|...> */
1062 /* Not sure about this one. cfg_name/vals are
1063 * indexed from 0 right? */
1064 *intval = *(int*)s->setting + 1;
1065 break;
1066 case F_T_BOOL:
1067 /* %?St|name|<if true|if false> */
1068 *intval = *(bool*)s->setting?1:2;
1069 break;
1070 case F_T_CHARPTR:
1071 case F_T_UCHARPTR:
1072 /* %?St|name|<if non empty string|if empty>
1073 * The string's emptyness discards the setting's
1074 * prefix and suffix */
1075 *intval = ((char*)s->setting)[0]?1:2;
1076 /* if there is a prefix we should ignore it here */
1077 if (s->filename_setting->prefix)
1078 return (char*)s->setting;
1079 break;
1080 default:
1081 /* This shouldn't happen ... but you never know */
1082 *intval = -1;
1083 break;
1086 /* Special handlng for filenames because we dont want to show the prefix */
1087 if ((s->flags&F_T_MASK) == F_T_UCHARPTR ||
1088 (s->flags&F_T_MASK) == F_T_UCHARPTR)
1090 if (s->filename_setting->prefix)
1091 return (char*)s->setting;
1093 cfg_to_string(token->value.i,buf,buf_size);
1094 return buf;
1096 case WPS_TOKEN_HAVE_TUNER:
1097 #if CONFIG_TUNER
1098 if (radio_hardware_present())
1099 return "r";
1100 #endif
1101 return NULL;
1102 /* Recording tokens */
1103 case WPS_TOKEN_HAVE_RECORDING:
1104 #ifdef HAVE_RECORDING
1105 return "r";
1106 #else
1107 return NULL;
1108 #endif
1110 #ifdef HAVE_RECORDING
1111 case WPS_TOKEN_IS_RECORDING:
1112 if (audio_status() == AUDIO_STATUS_RECORD)
1113 return "r";
1114 return NULL;
1115 case WPS_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1117 #if CONFIG_CODEC == SWCODEC
1118 unsigned long samprk;
1119 int rec_freq = global_settings.rec_frequency;
1121 #ifdef SIMULATOR
1122 samprk = 44100;
1123 #else
1124 #if defined(HAVE_SPDIF_REC)
1125 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1127 /* Use rate in use, not current measured rate if it changed */
1128 samprk = pcm_rec_sample_rate();
1129 rec_freq = 0;
1130 while (rec_freq < SAMPR_NUM_FREQ &&
1131 audio_master_sampr_list[rec_freq] != samprk)
1133 rec_freq++;
1136 else
1137 #endif
1138 samprk = rec_freq_sampr[rec_freq];
1139 #endif /* SIMULATOR */
1140 if (intval)
1142 switch (rec_freq)
1144 REC_HAVE_96_(case REC_FREQ_96:
1145 *intval = 1;
1146 break;)
1147 REC_HAVE_88_(case REC_FREQ_88:
1148 *intval = 2;
1149 break;)
1150 REC_HAVE_64_(case REC_FREQ_64:
1151 *intval = 3;
1152 break;)
1153 REC_HAVE_48_(case REC_FREQ_48:
1154 *intval = 4;
1155 break;)
1156 REC_HAVE_44_(case REC_FREQ_44:
1157 *intval = 5;
1158 break;)
1159 REC_HAVE_32_(case REC_FREQ_32:
1160 *intval = 6;
1161 break;)
1162 REC_HAVE_24_(case REC_FREQ_24:
1163 *intval = 7;
1164 break;)
1165 REC_HAVE_22_(case REC_FREQ_22:
1166 *intval = 8;
1167 break;)
1168 REC_HAVE_16_(case REC_FREQ_16:
1169 *intval = 9;
1170 break;)
1171 REC_HAVE_12_(case REC_FREQ_12:
1172 *intval = 10;
1173 break;)
1174 REC_HAVE_11_(case REC_FREQ_11:
1175 *intval = 11;
1176 break;)
1177 REC_HAVE_8_(case REC_FREQ_8:
1178 *intval = 12;
1179 break;)
1182 snprintf(buf, buf_size, "%lu.%1lu", samprk/1000,samprk%1000);
1183 #else /* HWCODEC */
1185 static const char * const freq_strings[] =
1186 {"--", "44", "48", "32", "22", "24", "16"};
1187 int freq = 1 + global_settings.rec_frequency;
1188 #ifdef HAVE_SPDIF_REC
1189 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1191 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1192 freq = 0;
1194 #endif /* HAVE_SPDIF_IN */
1195 if (intval)
1196 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1197 snprintf(buf, buf_size, "%s\n",
1198 freq_strings[global_settings.rec_frequency]);
1199 #endif
1200 return buf;
1202 #if CONFIG_CODEC == SWCODEC
1203 case WPS_TOKEN_REC_ENCODER:
1205 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1206 if (intval)
1207 *intval = rec_format;
1208 switch (rec_format)
1210 case REC_FORMAT_PCM_WAV:
1211 return "wav";
1212 case REC_FORMAT_AIFF:
1213 return "aiff";
1214 case REC_FORMAT_WAVPACK:
1215 return "wv";
1216 case REC_FORMAT_MPA_L3:
1217 return "MP3";
1218 default:
1219 return NULL;
1221 break;
1223 #endif
1224 case WPS_TOKEN_REC_BITRATE:
1225 #if CONFIG_CODEC == SWCODEC
1226 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1228 if (intval)
1230 #if 0 /* FIXME: I dont know if this is needed? */
1231 switch (1<<global_settings.mp3_enc_config.bitrate)
1233 case MP3_BITR_CAP_8:
1234 *intval = 1;
1235 break;
1236 case MP3_BITR_CAP_16:
1237 *intval = 2;
1238 break;
1239 case MP3_BITR_CAP_24:
1240 *intval = 3;
1241 break;
1242 case MP3_BITR_CAP_32:
1243 *intval = 4;
1244 break;
1245 case MP3_BITR_CAP_40:
1246 *intval = 5;
1247 break;
1248 case MP3_BITR_CAP_48:
1249 *intval = 6;
1250 break;
1251 case MP3_BITR_CAP_56:
1252 *intval = 7;
1253 break;
1254 case MP3_BITR_CAP_64:
1255 *intval = 8;
1256 break;
1257 case MP3_BITR_CAP_80:
1258 *intval = 9;
1259 break;
1260 case MP3_BITR_CAP_96:
1261 *intval = 10;
1262 break;
1263 case MP3_BITR_CAP_112:
1264 *intval = 11;
1265 break;
1266 case MP3_BITR_CAP_128:
1267 *intval = 12;
1268 break;
1269 case MP3_BITR_CAP_144:
1270 *intval = 13;
1271 break;
1272 case MP3_BITR_CAP_160:
1273 *intval = 14;
1274 break;
1275 case MP3_BITR_CAP_192:
1276 *intval = 15;
1277 break;
1279 #endif
1280 *intval = global_settings.mp3_enc_config.bitrate+1;
1282 snprintf(buf, buf_size, "%lu", global_settings.mp3_enc_config.bitrate+1);
1283 return buf;
1285 else
1286 return NULL; /* Fixme later */
1287 #else /* CONFIG_CODEC == HWCODEC */
1288 if (intval)
1289 *intval = global_settings.rec_quality+1;
1290 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1291 return buf;
1292 #endif
1293 case WPS_TOKEN_REC_MONO:
1294 if (!global_settings.rec_channels)
1295 return "m";
1296 return NULL;
1298 case WPS_TOKEN_REC_SECONDS:
1300 int time = (audio_recorded_time() / HZ) % 60;
1301 if (intval)
1302 *intval = time;
1303 snprintf(buf, buf_size, "%02d", time);
1304 return buf;
1306 case WPS_TOKEN_REC_MINUTES:
1308 int time = (audio_recorded_time() / HZ) / 60;
1309 if (intval)
1310 *intval = time;
1311 snprintf(buf, buf_size, "%02d", time);
1312 return buf;
1314 case WPS_TOKEN_REC_HOURS:
1316 int time = (audio_recorded_time() / HZ) / 3600;
1317 if (intval)
1318 *intval = time;
1319 snprintf(buf, buf_size, "%02d", time);
1320 return buf;
1323 #endif /* HAVE_RECORDING */
1325 case WPS_TOKEN_CURRENT_SCREEN:
1327 int curr_screen = current_screen();
1329 #ifdef HAVE_RECORDING
1330 /* override current_screen() for recording screen since it may
1331 * be entered from the radio screen */
1332 if (in_recording_screen())
1333 curr_screen = GO_TO_RECSCREEN;
1334 #endif
1336 switch (curr_screen)
1338 case GO_TO_WPS:
1339 curr_screen = 2;
1340 break;
1341 #ifdef HAVE_RECORDING
1342 case GO_TO_RECSCREEN:
1343 curr_screen = 3;
1344 break;
1345 #endif
1346 #if CONFIG_TUNER
1347 case GO_TO_FM:
1348 curr_screen = 4;
1349 break;
1350 #endif
1351 case GO_TO_PLAYLIST_VIEWER:
1352 curr_screen = 5;
1353 break;
1354 default: /* lists */
1355 curr_screen = 1;
1356 break;
1358 if (intval)
1360 *intval = curr_screen;
1362 snprintf(buf, buf_size, "%d", curr_screen);
1363 return buf;
1366 case WPS_TOKEN_LANG_IS_RTL:
1367 return lang_is_rtl() ? "r" : NULL;
1369 default:
1370 return NULL;