Rearrange statements for a small binsize reduction; delete unneeded braces
[kugel-rb.git] / apps / gui / skin_engine / skin_tokens.c
bloba85fa171effd8717c8e6170d52114619f93dd0aa
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 one or two digits after the decimal point -- */
350 /* depending on the frequency changing step. */
351 /* Returns buf */
352 static char *format_freq_MHz(int freq, int freq_step, char *buf, int buf_size)
354 int scale, div;
355 char *fmt;
356 if (freq_step < 100000)
358 /* Format with two digits after decimal point */
359 scale = 10000;
360 fmt = "%d.%02d";
362 else
364 /* Format with one digit after decimal point */
365 scale = 100000;
366 fmt = "%d.%d";
368 div = 1000000 / scale;
369 freq = freq / scale;
370 snprintf(buf, buf_size, fmt, freq/div, freq%div);
371 return buf;
375 /* Tokens which are really only used by the radio screen go in here */
376 const char *get_radio_token(struct wps_token *token, int preset_offset,
377 char *buf, int buf_size, int limit, int *intval)
379 const struct fm_region_data *region_data =
380 &(fm_region_data[global_settings.fm_region]);
381 (void)limit;
382 switch (token->type)
384 /* Radio/tuner tokens */
385 case WPS_TOKEN_TUNER_TUNED:
386 if (tuner_get(RADIO_TUNED))
387 return "t";
388 return NULL;
389 case WPS_TOKEN_TUNER_SCANMODE:
390 if (radio_scan_mode())
391 return "s";
392 return NULL;
393 case WPS_TOKEN_TUNER_STEREO:
394 if (radio_is_stereo())
395 return "s";
396 return NULL;
397 case WPS_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
398 return format_freq_MHz(region_data->freq_min,
399 region_data->freq_step, buf, buf_size);
400 case WPS_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
401 return format_freq_MHz(region_data->freq_max,
402 region_data->freq_step, buf, buf_size);
403 case WPS_TOKEN_TUNER_CURFREQ:
404 return format_freq_MHz(radio_current_frequency(),
405 region_data->freq_step, buf, buf_size);
406 case WPS_TOKEN_PRESET_ID:
407 snprintf(buf, buf_size, "%d", radio_current_preset() + 1 + preset_offset);
408 return buf;
409 case WPS_TOKEN_PRESET_NAME:
410 case WPS_TOKEN_PRESET_FREQ:
412 int preset_count = radio_preset_count();
413 int cur_preset = radio_current_preset();
414 if (preset_count == 0 || cur_preset < 0)
415 return NULL;
416 int preset = cur_preset + preset_offset;
417 /* make sure it's in the valid range */
418 preset %= preset_count;
419 if (preset < 0)
420 preset += preset_count;
421 if (token->type == WPS_TOKEN_PRESET_NAME)
422 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
423 else
424 format_freq_MHz(radio_get_preset(preset)->frequency,
425 region_data->freq_step, buf, buf_size);
426 return buf;
428 case WPS_TOKEN_PRESET_COUNT:
429 snprintf(buf, buf_size, "%d", radio_preset_count());
430 if (intval)
431 *intval = radio_preset_count();
432 return buf;
433 case WPS_TOKEN_HAVE_RDS:
434 #ifdef HAVE_RDS_CAP
435 return "rds";
436 case WPS_TOKEN_RDS_NAME:
437 return tuner_get_rds_info(RADIO_RDS_NAME);
438 case WPS_TOKEN_RDS_TEXT:
439 return tuner_get_rds_info(RADIO_RDS_TEXT);
440 #else
441 return NULL; /* end of the WPS_TOKEN_HAVE_RDS case */
442 #endif /* HAVE_RDS_CAP */
444 return NULL;
446 #endif
448 /* Return the tags value as text. buf should be used as temp storage if needed.
450 intval is used with conditionals/enums: when this function is called,
451 intval should contain the number of options in the conditional/enum.
452 When this function returns, intval is -1 if the tag is non numeric or,
453 if the tag is numeric, *intval is the enum case we want to go to (between 1
454 and the original value of *intval, inclusive).
455 When not treating a conditional/enum, intval should be NULL.
457 const char *get_token_value(struct gui_wps *gwps,
458 struct wps_token *token,
459 char *buf, int buf_size,
460 int *intval)
462 if (!gwps)
463 return NULL;
465 struct wps_data *data = gwps->data;
466 struct wps_state *state = gwps->state;
467 struct mp3entry *id3; /* Think very carefully about using this.
468 maybe get_id3_token() is the better place? */
469 const char *out_text = NULL;
471 if (!data || !state)
472 return NULL;
475 if (token->next)
476 id3 = state->nid3;
477 else
478 id3 = state->id3;
480 #if CONFIG_RTC
481 struct tm* tm = NULL;
483 /* if the token is an RTC one, update the time
484 and do the necessary checks */
485 if (token->type >= WPS_TOKENS_RTC_BEGIN
486 && token->type <= WPS_TOKENS_RTC_END)
488 tm = get_time();
490 if (!valid_time(tm))
491 return NULL;
493 #endif
495 int limit = 1;
496 if (intval)
498 limit = *intval;
499 *intval = -1;
502 out_text = get_id3_token(token, id3, buf, buf_size, limit, intval);
503 if (out_text)
504 return out_text;
505 #if CONFIG_TUNER
506 out_text = get_radio_token(token, 0, buf, buf_size, limit, intval);
507 if (out_text)
508 return out_text;
509 #endif
511 switch (token->type)
513 case WPS_TOKEN_CHARACTER:
514 if (token->value.c == '\n')
515 return NULL;
516 return &(token->value.c);
518 case WPS_TOKEN_STRING:
519 return (char*)token->value.data;
521 case WPS_TOKEN_TRANSLATEDSTRING:
522 return (char*)P2STR(ID2P(token->value.i));
524 case WPS_TOKEN_PLAYLIST_ENTRIES:
525 snprintf(buf, buf_size, "%d", playlist_amount());
526 return buf;
528 case WPS_TOKEN_LIST_TITLE_TEXT:
529 return (char*)token->value.data;
530 case WPS_TOKEN_LIST_TITLE_ICON:
531 if (intval)
532 *intval = token->value.i;
533 snprintf(buf, buf_size, "%d", token->value.i);
534 return buf;
536 case WPS_TOKEN_PLAYLIST_NAME:
537 return playlist_name(NULL, buf, buf_size);
539 case WPS_TOKEN_PLAYLIST_POSITION:
540 snprintf(buf, buf_size, "%d", playlist_get_display_index());
541 return buf;
543 case WPS_TOKEN_PLAYLIST_SHUFFLE:
544 if ( global_settings.playlist_shuffle )
545 return "s";
546 else
547 return NULL;
548 break;
550 case WPS_TOKEN_VOLUME:
551 snprintf(buf, buf_size, "%d", global_settings.volume);
552 if (intval)
554 int minvol = sound_min(SOUND_VOLUME);
555 if (global_settings.volume == minvol)
557 *intval = 1;
559 else if (global_settings.volume == 0)
561 *intval = limit - 1;
563 else if (global_settings.volume > 0)
565 *intval = limit;
567 else
569 *intval = (limit-3) * (global_settings.volume - minvol - 1)
570 / (-1 - minvol) + 2;
573 return buf;
574 #ifdef HAVE_ALBUMART
575 case WPS_TOKEN_ALBUMART_FOUND:
576 if (data->albumart)
578 int handle = -1;
579 handle = playback_current_aa_hid(data->playback_aa_slot);
580 #if CONFIG_TUNER
581 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
583 struct dim dim = {data->albumart->width, data->albumart->height};
584 handle = radio_get_art_hid(&dim);
586 #endif
587 if (handle >= 0)
588 return "C";
590 return NULL;
592 case WPS_TOKEN_ALBUMART_DISPLAY:
593 if (!data->albumart)
594 return NULL;
595 if (!data->albumart->draw)
596 data->albumart->draw = true;
597 return NULL;
598 #endif
600 case WPS_TOKEN_BATTERY_PERCENT:
602 int l = battery_level();
604 if (intval)
606 limit = MAX(limit, 2);
607 if (l > -1) {
608 /* First enum is used for "unknown level". */
609 *intval = (limit - 1) * l / 100 + 2;
610 } else {
611 *intval = 1;
615 if (l > -1) {
616 snprintf(buf, buf_size, "%d", l);
617 return buf;
618 } else {
619 return "?";
623 case WPS_TOKEN_BATTERY_VOLTS:
625 unsigned int v = battery_voltage();
626 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
627 return buf;
630 case WPS_TOKEN_BATTERY_TIME:
632 int t = battery_time();
633 if (t >= 0)
634 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
635 else
636 return "?h ?m";
637 return buf;
640 #if CONFIG_CHARGING
641 case WPS_TOKEN_BATTERY_CHARGER_CONNECTED:
643 if(charger_input_state==CHARGER)
644 return "p";
645 else
646 return NULL;
648 #endif
649 #if CONFIG_CHARGING >= CHARGING_MONITOR
650 case WPS_TOKEN_BATTERY_CHARGING:
652 if (charge_state == CHARGING || charge_state == TOPOFF) {
653 return "c";
654 } else {
655 return NULL;
658 #endif
659 #ifdef HAVE_USB_POWER
660 case WPS_TOKEN_USB_POWERED:
661 if (usb_powered())
662 return "u";
663 return NULL;
664 #endif
665 case WPS_TOKEN_BATTERY_SLEEPTIME:
667 if (get_sleep_timer() == 0)
668 return NULL;
669 else
671 format_time(buf, buf_size, get_sleep_timer() * 1000);
672 return buf;
676 case WPS_TOKEN_PLAYBACK_STATUS:
678 int status = current_playmode();
679 /* music */
680 int mode = 1; /* stop */
681 if (status == STATUS_PLAY)
682 mode = 2; /* play */
683 if (state->is_fading ||
684 (status == STATUS_PAUSE && !status_get_ffmode()))
685 mode = 3; /* pause */
686 else
687 { /* ff / rwd */
688 if (status_get_ffmode() == STATUS_FASTFORWARD)
689 mode = 4;
690 if (status_get_ffmode() == STATUS_FASTBACKWARD)
691 mode = 5;
693 #ifdef HAVE_RECORDING
694 /* recording */
695 if (status == STATUS_RECORD)
696 mode = 6;
697 else if (status == STATUS_RECORD_PAUSE)
698 mode = 7;
699 #endif
700 #if CONFIG_TUNER
701 /* radio */
702 if (status == STATUS_RADIO)
703 mode = 8;
704 else if (status == STATUS_RADIO_PAUSE)
705 mode = 9;
706 #endif
708 if (intval) {
709 *intval = mode;
712 snprintf(buf, buf_size, "%d", mode-1);
713 return buf;
716 case WPS_TOKEN_REPEAT_MODE:
717 if (intval)
718 *intval = global_settings.repeat_mode + 1;
719 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
720 return buf;
722 case WPS_TOKEN_RTC_PRESENT:
723 #if CONFIG_RTC
724 return "c";
725 #else
726 return NULL;
727 #endif
729 #if CONFIG_RTC
730 case WPS_TOKEN_RTC_12HOUR_CFG:
731 if (intval)
732 *intval = global_settings.timeformat + 1;
733 snprintf(buf, buf_size, "%d", global_settings.timeformat);
734 return buf;
736 case WPS_TOKEN_RTC_DAY_OF_MONTH:
737 /* d: day of month (01..31) */
738 snprintf(buf, buf_size, "%02d", tm->tm_mday);
739 if (intval)
740 *intval = tm->tm_mday - 1;
741 return buf;
743 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
744 /* e: day of month, blank padded ( 1..31) */
745 snprintf(buf, buf_size, "%2d", tm->tm_mday);
746 if (intval)
747 *intval = tm->tm_mday - 1;
748 return buf;
750 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
751 /* H: hour (00..23) */
752 snprintf(buf, buf_size, "%02d", tm->tm_hour);
753 if (intval)
754 *intval = tm->tm_hour;
755 return buf;
757 case WPS_TOKEN_RTC_HOUR_24:
758 /* k: hour ( 0..23) */
759 snprintf(buf, buf_size, "%2d", tm->tm_hour);
760 if (intval)
761 *intval = tm->tm_hour;
762 return buf;
764 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
765 /* I: hour (01..12) */
766 snprintf(buf, buf_size, "%02d",
767 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
768 if (intval)
769 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
770 return buf;
772 case WPS_TOKEN_RTC_HOUR_12:
773 /* l: hour ( 1..12) */
774 snprintf(buf, buf_size, "%2d",
775 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
776 if (intval)
777 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
778 return buf;
780 case WPS_TOKEN_RTC_MONTH:
781 /* m: month (01..12) */
782 if (intval)
783 *intval = tm->tm_mon + 1;
784 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
785 return buf;
787 case WPS_TOKEN_RTC_MINUTE:
788 /* M: minute (00..59) */
789 snprintf(buf, buf_size, "%02d", tm->tm_min);
790 if (intval)
791 *intval = tm->tm_min;
792 return buf;
794 case WPS_TOKEN_RTC_SECOND:
795 /* S: second (00..59) */
796 snprintf(buf, buf_size, "%02d", tm->tm_sec);
797 if (intval)
798 *intval = tm->tm_sec;
799 return buf;
801 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
802 /* y: last two digits of year (00..99) */
803 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
804 if (intval)
805 *intval = tm->tm_year % 100;
806 return buf;
808 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
809 /* Y: year (1970...) */
810 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
811 if (intval)
812 *intval = tm->tm_year + 1900;
813 return buf;
815 case WPS_TOKEN_RTC_AM_PM_UPPER:
816 /* p: upper case AM or PM indicator */
817 if (intval)
818 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
819 return tm->tm_hour/12 == 0 ? "AM" : "PM";
821 case WPS_TOKEN_RTC_AM_PM_LOWER:
822 /* P: lower case am or pm indicator */
823 if (intval)
824 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
825 return tm->tm_hour/12 == 0 ? "am" : "pm";
827 case WPS_TOKEN_RTC_WEEKDAY_NAME:
828 /* a: abbreviated weekday name (Sun..Sat) */
829 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
831 case WPS_TOKEN_RTC_MONTH_NAME:
832 /* b: abbreviated month name (Jan..Dec) */
833 return str(LANG_MONTH_JANUARY + tm->tm_mon);
835 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
836 /* u: day of week (1..7); 1 is Monday */
837 if (intval)
838 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
839 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
840 return buf;
842 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
843 /* w: day of week (0..6); 0 is Sunday */
844 if (intval)
845 *intval = tm->tm_wday + 1;
846 snprintf(buf, buf_size, "%1d", tm->tm_wday);
847 return buf;
848 #else
849 case WPS_TOKEN_RTC_DAY_OF_MONTH:
850 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
851 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
852 case WPS_TOKEN_RTC_HOUR_24:
853 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
854 case WPS_TOKEN_RTC_HOUR_12:
855 case WPS_TOKEN_RTC_MONTH:
856 case WPS_TOKEN_RTC_MINUTE:
857 case WPS_TOKEN_RTC_SECOND:
858 case WPS_TOKEN_RTC_AM_PM_UPPER:
859 case WPS_TOKEN_RTC_AM_PM_LOWER:
860 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
861 return "--";
862 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
863 return "----";
864 case WPS_TOKEN_RTC_WEEKDAY_NAME:
865 case WPS_TOKEN_RTC_MONTH_NAME:
866 return "---";
867 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
868 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
869 return "-";
870 #endif
872 #ifdef HAVE_LCD_CHARCELLS
873 case WPS_TOKEN_PROGRESSBAR:
875 char *end = utf8encode(data->wps_progress_pat[0], buf);
876 *end = '\0';
877 return buf;
880 case WPS_TOKEN_PLAYER_PROGRESSBAR:
881 if(is_new_player())
883 /* we need 11 characters (full line) for
884 progress-bar */
885 strlcpy(buf, " ", buf_size);
887 else
889 /* Tell the user if we have an OldPlayer */
890 strlcpy(buf, " <Old LCD> ", buf_size);
892 return buf;
893 #endif
897 #if (CONFIG_CODEC == SWCODEC)
898 case WPS_TOKEN_CROSSFADE:
899 #ifdef HAVE_CROSSFADE
900 if (intval)
901 *intval = global_settings.crossfade + 1;
902 snprintf(buf, buf_size, "%d", global_settings.crossfade);
903 #else
904 snprintf(buf, buf_size, "%d", 0);
905 #endif
906 return buf;
908 case WPS_TOKEN_REPLAYGAIN:
910 int val;
912 if (global_settings.replaygain_type == REPLAYGAIN_OFF)
913 val = 1; /* off */
914 else
916 int type;
917 if (LIKELY(id3))
918 type = get_replaygain_mode(id3->track_gain_string != NULL,
919 id3->album_gain_string != NULL);
920 else
921 type = -1;
923 if (type < 0)
924 val = 6; /* no tag */
925 else
926 val = type + 2;
928 if (global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
929 val += 2;
932 if (intval)
933 *intval = val;
935 switch (val)
937 case 1:
938 case 6:
939 return "+0.00 dB";
940 break;
941 /* due to above, coming here with !id3 shouldn't be possible */
942 case 2:
943 case 4:
944 strlcpy(buf, id3->track_gain_string, buf_size);
945 break;
946 case 3:
947 case 5:
948 strlcpy(buf, id3->album_gain_string, buf_size);
949 break;
951 return buf;
953 #endif /* (CONFIG_CODEC == SWCODEC) */
955 #if (CONFIG_CODEC != MAS3507D)
956 case WPS_TOKEN_SOUND_PITCH:
958 int32_t pitch = sound_get_pitch();
959 snprintf(buf, buf_size, "%ld.%ld",
960 pitch / PITCH_SPEED_PRECISION,
961 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
963 if (intval)
964 *intval = pitch_speed_enum(limit, pitch,
965 PITCH_SPEED_PRECISION * 100);
966 return buf;
968 #endif
970 #if CONFIG_CODEC == SWCODEC
971 case WPS_TOKEN_SOUND_SPEED:
973 int32_t pitch = sound_get_pitch();
974 int32_t speed;
975 if (dsp_timestretch_available())
976 speed = GET_SPEED(pitch, dsp_get_timestretch());
977 else
978 speed = pitch;
979 snprintf(buf, buf_size, "%ld.%ld",
980 speed / PITCH_SPEED_PRECISION,
981 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
982 if (intval)
983 *intval = pitch_speed_enum(limit, speed,
984 PITCH_SPEED_PRECISION * 100);
985 return buf;
987 #endif
989 case WPS_TOKEN_MAIN_HOLD:
990 #ifdef HAS_BUTTON_HOLD
991 if (button_hold())
992 #else
993 if (is_keys_locked())
994 #endif /*hold switch or softlock*/
995 return "h";
996 else
997 return NULL;
999 #ifdef HAS_REMOTE_BUTTON_HOLD
1000 case WPS_TOKEN_REMOTE_HOLD:
1001 if (remote_button_hold())
1002 return "r";
1003 else
1004 return NULL;
1005 #endif
1007 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
1008 case WPS_TOKEN_VLED_HDD:
1009 if(led_read(HZ/2))
1010 return "h";
1011 else
1012 return NULL;
1013 #endif
1014 case WPS_TOKEN_BUTTON_VOLUME:
1015 if (global_status.last_volume_change &&
1016 TIME_BEFORE(current_tick, global_status.last_volume_change +
1017 token->value.i * TIMEOUT_UNIT))
1018 return "v";
1019 return NULL;
1021 case WPS_TOKEN_TRACK_STARTING:
1022 if (id3)
1024 int elapsed = id3->elapsed + state->ff_rewind_count;
1025 if (elapsed < token->value.i * 1000)
1026 return "starting";
1028 return NULL;
1029 case WPS_TOKEN_TRACK_ENDING:
1030 if (id3)
1032 unsigned long elapsed = id3->elapsed + state->ff_rewind_count;
1033 unsigned time = token->value.i * 1000;
1034 if (id3->length - elapsed < time)
1035 return "ending";
1037 return NULL;
1038 case WPS_TOKEN_LASTTOUCH:
1039 #ifdef HAVE_TOUCHSCREEN
1040 if (TIME_BEFORE(current_tick, token->value.i * TIMEOUT_UNIT +
1041 touchscreen_last_touch()))
1042 return "t";
1043 #endif
1044 return NULL;
1046 case WPS_TOKEN_SETTING:
1048 const struct settings_list *s = settings+token->value.i;
1049 if (intval)
1051 /* Handle contionals */
1052 switch (s->flags&F_T_MASK)
1054 case F_T_INT:
1055 case F_T_UINT:
1056 if (s->flags&F_T_SOUND)
1058 /* %?St|name|<min|min+1|...|max-1|max> */
1059 int sound_setting = s->sound_setting->setting;
1060 /* settings with decimals can't be used in conditionals */
1061 if (sound_numdecimals(sound_setting) == 0)
1063 *intval = (*(int*)s->setting-sound_min(sound_setting))
1064 /sound_steps(sound_setting) + 1;
1066 else
1067 *intval = -1;
1069 else if (s->flags&F_RGB)
1070 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1071 /* shouldn't overflow since colors are stored
1072 * on 16 bits ...
1073 * but this is pretty useless anyway */
1074 *intval = *(int*)s->setting + 1;
1075 else if (s->cfg_vals == NULL)
1076 /* %?St|name|<1st choice|2nd choice|...> */
1077 *intval = (*(int*)s->setting-s->int_setting->min)
1078 /s->int_setting->step + 1;
1079 else
1080 /* %?St|name|<1st choice|2nd choice|...> */
1081 /* Not sure about this one. cfg_name/vals are
1082 * indexed from 0 right? */
1083 *intval = *(int*)s->setting + 1;
1084 break;
1085 case F_T_BOOL:
1086 /* %?St|name|<if true|if false> */
1087 *intval = *(bool*)s->setting?1:2;
1088 break;
1089 case F_T_CHARPTR:
1090 case F_T_UCHARPTR:
1091 /* %?St|name|<if non empty string|if empty>
1092 * The string's emptyness discards the setting's
1093 * prefix and suffix */
1094 *intval = ((char*)s->setting)[0]?1:2;
1095 /* if there is a prefix we should ignore it here */
1096 if (s->filename_setting->prefix)
1097 return (char*)s->setting;
1098 break;
1099 default:
1100 /* This shouldn't happen ... but you never know */
1101 *intval = -1;
1102 break;
1105 /* Special handlng for filenames because we dont want to show the prefix */
1106 if ((s->flags&F_T_MASK) == F_T_UCHARPTR ||
1107 (s->flags&F_T_MASK) == F_T_UCHARPTR)
1109 if (s->filename_setting->prefix)
1110 return (char*)s->setting;
1112 cfg_to_string(token->value.i,buf,buf_size);
1113 return buf;
1115 case WPS_TOKEN_HAVE_TUNER:
1116 #if CONFIG_TUNER
1117 if (radio_hardware_present())
1118 return "r";
1119 #endif
1120 return NULL;
1121 /* Recording tokens */
1122 case WPS_TOKEN_HAVE_RECORDING:
1123 #ifdef HAVE_RECORDING
1124 return "r";
1125 #else
1126 return NULL;
1127 #endif
1129 #ifdef HAVE_RECORDING
1130 case WPS_TOKEN_IS_RECORDING:
1131 if (audio_status() == AUDIO_STATUS_RECORD)
1132 return "r";
1133 return NULL;
1134 case WPS_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1136 #if CONFIG_CODEC == SWCODEC
1137 unsigned long samprk;
1138 int rec_freq = global_settings.rec_frequency;
1140 #ifdef SIMULATOR
1141 samprk = 44100;
1142 #else
1143 #if defined(HAVE_SPDIF_REC)
1144 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1146 /* Use rate in use, not current measured rate if it changed */
1147 samprk = pcm_rec_sample_rate();
1148 rec_freq = 0;
1149 while (rec_freq < SAMPR_NUM_FREQ &&
1150 audio_master_sampr_list[rec_freq] != samprk)
1152 rec_freq++;
1155 else
1156 #endif
1157 samprk = rec_freq_sampr[rec_freq];
1158 #endif /* SIMULATOR */
1159 if (intval)
1161 switch (rec_freq)
1163 REC_HAVE_96_(case REC_FREQ_96:
1164 *intval = 1;
1165 break;)
1166 REC_HAVE_88_(case REC_FREQ_88:
1167 *intval = 2;
1168 break;)
1169 REC_HAVE_64_(case REC_FREQ_64:
1170 *intval = 3;
1171 break;)
1172 REC_HAVE_48_(case REC_FREQ_48:
1173 *intval = 4;
1174 break;)
1175 REC_HAVE_44_(case REC_FREQ_44:
1176 *intval = 5;
1177 break;)
1178 REC_HAVE_32_(case REC_FREQ_32:
1179 *intval = 6;
1180 break;)
1181 REC_HAVE_24_(case REC_FREQ_24:
1182 *intval = 7;
1183 break;)
1184 REC_HAVE_22_(case REC_FREQ_22:
1185 *intval = 8;
1186 break;)
1187 REC_HAVE_16_(case REC_FREQ_16:
1188 *intval = 9;
1189 break;)
1190 REC_HAVE_12_(case REC_FREQ_12:
1191 *intval = 10;
1192 break;)
1193 REC_HAVE_11_(case REC_FREQ_11:
1194 *intval = 11;
1195 break;)
1196 REC_HAVE_8_(case REC_FREQ_8:
1197 *intval = 12;
1198 break;)
1201 snprintf(buf, buf_size, "%lu.%1lu", samprk/1000,samprk%1000);
1202 #else /* HWCODEC */
1204 static const char * const freq_strings[] =
1205 {"--", "44", "48", "32", "22", "24", "16"};
1206 int freq = 1 + global_settings.rec_frequency;
1207 #ifdef HAVE_SPDIF_REC
1208 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1210 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1211 freq = 0;
1213 #endif /* HAVE_SPDIF_IN */
1214 if (intval)
1215 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1216 snprintf(buf, buf_size, "%s\n",
1217 freq_strings[global_settings.rec_frequency]);
1218 #endif
1219 return buf;
1221 #if CONFIG_CODEC == SWCODEC
1222 case WPS_TOKEN_REC_ENCODER:
1224 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1225 if (intval)
1226 *intval = rec_format;
1227 switch (rec_format)
1229 case REC_FORMAT_PCM_WAV:
1230 return "wav";
1231 case REC_FORMAT_AIFF:
1232 return "aiff";
1233 case REC_FORMAT_WAVPACK:
1234 return "wv";
1235 case REC_FORMAT_MPA_L3:
1236 return "MP3";
1237 default:
1238 return NULL;
1240 break;
1242 #endif
1243 case WPS_TOKEN_REC_BITRATE:
1244 #if CONFIG_CODEC == SWCODEC
1245 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1247 if (intval)
1249 #if 0 /* FIXME: I dont know if this is needed? */
1250 switch (1<<global_settings.mp3_enc_config.bitrate)
1252 case MP3_BITR_CAP_8:
1253 *intval = 1;
1254 break;
1255 case MP3_BITR_CAP_16:
1256 *intval = 2;
1257 break;
1258 case MP3_BITR_CAP_24:
1259 *intval = 3;
1260 break;
1261 case MP3_BITR_CAP_32:
1262 *intval = 4;
1263 break;
1264 case MP3_BITR_CAP_40:
1265 *intval = 5;
1266 break;
1267 case MP3_BITR_CAP_48:
1268 *intval = 6;
1269 break;
1270 case MP3_BITR_CAP_56:
1271 *intval = 7;
1272 break;
1273 case MP3_BITR_CAP_64:
1274 *intval = 8;
1275 break;
1276 case MP3_BITR_CAP_80:
1277 *intval = 9;
1278 break;
1279 case MP3_BITR_CAP_96:
1280 *intval = 10;
1281 break;
1282 case MP3_BITR_CAP_112:
1283 *intval = 11;
1284 break;
1285 case MP3_BITR_CAP_128:
1286 *intval = 12;
1287 break;
1288 case MP3_BITR_CAP_144:
1289 *intval = 13;
1290 break;
1291 case MP3_BITR_CAP_160:
1292 *intval = 14;
1293 break;
1294 case MP3_BITR_CAP_192:
1295 *intval = 15;
1296 break;
1298 #endif
1299 *intval = global_settings.mp3_enc_config.bitrate+1;
1301 snprintf(buf, buf_size, "%lu", global_settings.mp3_enc_config.bitrate+1);
1302 return buf;
1304 else
1305 return NULL; /* Fixme later */
1306 #else /* CONFIG_CODEC == HWCODEC */
1307 if (intval)
1308 *intval = global_settings.rec_quality+1;
1309 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1310 return buf;
1311 #endif
1312 case WPS_TOKEN_REC_MONO:
1313 if (!global_settings.rec_channels)
1314 return "m";
1315 return NULL;
1317 case WPS_TOKEN_REC_SECONDS:
1319 int time = (audio_recorded_time() / HZ) % 60;
1320 if (intval)
1321 *intval = time;
1322 snprintf(buf, buf_size, "%02d", time);
1323 return buf;
1325 case WPS_TOKEN_REC_MINUTES:
1327 int time = (audio_recorded_time() / HZ) / 60;
1328 if (intval)
1329 *intval = time;
1330 snprintf(buf, buf_size, "%02d", time);
1331 return buf;
1333 case WPS_TOKEN_REC_HOURS:
1335 int time = (audio_recorded_time() / HZ) / 3600;
1336 if (intval)
1337 *intval = time;
1338 snprintf(buf, buf_size, "%02d", time);
1339 return buf;
1342 #endif /* HAVE_RECORDING */
1344 case WPS_TOKEN_CURRENT_SCREEN:
1346 int curr_screen = current_screen();
1348 #ifdef HAVE_RECORDING
1349 /* override current_screen() for recording screen since it may
1350 * be entered from the radio screen */
1351 if (in_recording_screen())
1352 curr_screen = GO_TO_RECSCREEN;
1353 #endif
1355 switch (curr_screen)
1357 case GO_TO_WPS:
1358 curr_screen = 2;
1359 break;
1360 #ifdef HAVE_RECORDING
1361 case GO_TO_RECSCREEN:
1362 curr_screen = 3;
1363 break;
1364 #endif
1365 #if CONFIG_TUNER
1366 case GO_TO_FM:
1367 curr_screen = 4;
1368 break;
1369 #endif
1370 case GO_TO_PLAYLIST_VIEWER:
1371 curr_screen = 5;
1372 break;
1373 default: /* lists */
1374 curr_screen = 1;
1375 break;
1377 if (intval)
1379 *intval = curr_screen;
1381 snprintf(buf, buf_size, "%d", curr_screen);
1382 return buf;
1385 case WPS_TOKEN_LANG_IS_RTL:
1386 return lang_is_rtl() ? "r" : NULL;
1388 default:
1389 return NULL;