lcd-m6sp.c: remove \r
[kugel-rb.git] / apps / gui / skin_engine / skin_tokens.c
blobb0a55ca13caec638e8e1b03d6e4d6b2250762a16
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 #include "cuesheet.h"
38 #ifdef HAVE_LCD_CHARCELLS
39 #include "hwcompat.h"
40 #endif
41 #include "abrepeat.h"
42 #include "lang.h"
43 #include "misc.h"
44 #include "led.h"
45 #ifdef HAVE_LCD_BITMAP
46 /* Image stuff */
47 #include "albumart.h"
48 #endif
49 #include "dsp.h"
50 #include "playlist.h"
51 #if CONFIG_CODEC == SWCODEC
52 #include "playback.h"
53 #include "tdspeed.h"
54 #endif
55 #include "viewport.h"
57 #include "wps_internals.h"
58 #include "root_menu.h"
59 #ifdef HAVE_RECORDING
60 #include "recording.h"
61 #include "pcm_record.h"
62 #endif
63 #include "language.h"
64 #include "usb.h"
65 #if CONFIG_TUNER
66 #include "radio.h"
67 #include "tuner.h"
68 #endif
70 extern struct wps_state wps_state;
72 static const char* get_codectype(const struct mp3entry* id3)
74 if (id3 && id3->codectype < AFMT_NUM_CODECS) {
75 return audio_formats[id3->codectype].label;
76 } else {
77 return NULL;
81 /* Extract a part from a path.
83 * buf - buffer extract part to.
84 * buf_size - size of buffer.
85 * path - path to extract from.
86 * level - what to extract. 0 is file name, 1 is parent of file, 2 is
87 * parent of parent, etc.
89 * Returns buf if the desired level was found, NULL otherwise.
91 char* get_dir(char* buf, int buf_size, const char* path, int level)
93 const char* sep;
94 const char* last_sep;
95 int len;
97 sep = path + strlen(path);
98 last_sep = sep;
100 while (sep > path)
102 if ('/' == *(--sep))
104 if (!level)
105 break;
107 level--;
108 last_sep = sep - 1;
112 if (level || (last_sep <= sep))
113 return NULL;
115 len = MIN(last_sep - sep, buf_size - 1);
116 strlcpy(buf, sep + 1, len + 1);
117 return buf;
120 #if (CONFIG_CODEC != MAS3507D)
121 /* A helper to determine the enum value for pitch/speed.
123 When there are two choices (i.e. boolean), return 1 if the value is
124 different from normal value and 2 if the value is the same as the
125 normal value. E.g. "%?Sp<%Sp>" would show the pitch only when
126 playing at a modified pitch.
128 When there are more than two choices (i.e. enum), the left half of
129 the choices are to show 0..normal range, and the right half of the
130 choices are to show values over that. The last entry is used when
131 it is set to the normal setting, following the rockbox convention
132 to use the last entry for special values.
134 E.g.
136 2 items: %?Sp<0..99 or 101..infinity|100>
137 3 items: %?Sp<0..99|101..infinity|100>
138 4 items: %?Sp<0..49|50..99|101..infinity|100>
139 5 items: %?Sp<0..49|50..99|101..149|150..infinity|100>
140 6 items: %?Sp<0..33|34..66|67..99|101..133|134..infinity|100>
141 7 items: %?Sp<0..33|34..66|67..99|101..133|134..167|167..infinity|100>
143 static int pitch_speed_enum(int range, int32_t val, int32_t normval)
145 int center;
146 int n;
148 if (range < 3)
149 return (val == normval) + 1;
150 if (val == normval)
151 return range;
152 center = range / 2;
153 n = (center * val) / normval + 1;
154 return (range <= n) ? (range - 1) : n;
156 #endif
159 /* All tokens which only need the info to return a value go in here */
160 const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
161 char *buf, int buf_size, int limit, int *intval)
163 struct wps_state *state = &wps_state;
164 if (id3)
166 unsigned long length = id3->length;
167 unsigned long elapsed = id3->elapsed + state->ff_rewind_count;
168 switch (token->type)
170 case WPS_TOKEN_METADATA_ARTIST:
171 return id3->artist;
172 case WPS_TOKEN_METADATA_COMPOSER:
173 return id3->composer;
174 case WPS_TOKEN_METADATA_ALBUM:
175 return id3->album;
176 case WPS_TOKEN_METADATA_ALBUM_ARTIST:
177 return id3->albumartist;
178 case WPS_TOKEN_METADATA_GROUPING:
179 return id3->grouping;
180 case WPS_TOKEN_METADATA_GENRE:
181 return id3->genre_string;
182 case WPS_TOKEN_METADATA_DISC_NUMBER:
183 if (id3->disc_string)
184 return id3->disc_string;
185 if (id3->discnum) {
186 snprintf(buf, buf_size, "%d", id3->discnum);
187 return buf;
189 return NULL;
190 case WPS_TOKEN_METADATA_TRACK_NUMBER:
191 if (id3->track_string)
192 return id3->track_string;
193 if (id3->tracknum) {
194 snprintf(buf, buf_size, "%d", id3->tracknum);
195 return buf;
197 return NULL;
198 case WPS_TOKEN_METADATA_TRACK_TITLE:
199 return id3->title;
200 case WPS_TOKEN_METADATA_VERSION:
201 switch (id3->id3version)
203 case ID3_VER_1_0:
204 return "1";
205 case ID3_VER_1_1:
206 return "1.1";
207 case ID3_VER_2_2:
208 return "2.2";
209 case ID3_VER_2_3:
210 return "2.3";
211 case ID3_VER_2_4:
212 return "2.4";
213 default:
214 break;
216 return NULL;
217 case WPS_TOKEN_METADATA_YEAR:
218 if( id3->year_string )
219 return id3->year_string;
220 if (id3->year) {
221 snprintf(buf, buf_size, "%d", id3->year);
222 return buf;
224 return NULL;
225 case WPS_TOKEN_METADATA_COMMENT:
226 return id3->comment;
227 case WPS_TOKEN_FILE_PATH:
228 return id3->path;
229 case WPS_TOKEN_FILE_BITRATE:
230 if(id3->bitrate)
231 snprintf(buf, buf_size, "%d", id3->bitrate);
232 else
233 return "?";
234 return buf;
235 case WPS_TOKEN_TRACK_TIME_ELAPSED:
236 format_time(buf, buf_size, elapsed);
237 return buf;
239 case WPS_TOKEN_TRACK_TIME_REMAINING:
240 format_time(buf, buf_size, length - elapsed);
241 return buf;
243 case WPS_TOKEN_TRACK_LENGTH:
244 format_time(buf, buf_size, length);
245 return buf;
247 case WPS_TOKEN_TRACK_ELAPSED_PERCENT:
248 if (length <= 0)
249 return NULL;
251 if (intval)
253 *intval = limit * elapsed / length + 1;
255 snprintf(buf, buf_size, "%lu", 100 * elapsed / length);
256 return buf;
258 case WPS_TOKEN_TRACK_STARTING:
260 unsigned long time = token->value.i * 1000;
261 if (elapsed < time)
262 return "starting";
264 return NULL;
265 case WPS_TOKEN_TRACK_ENDING:
267 unsigned long time = token->value.i * 1000;
268 if (length - elapsed < time)
269 return "ending";
271 return NULL;
273 case WPS_TOKEN_FILE_CODEC:
274 if (intval)
276 if(id3->codectype == AFMT_UNKNOWN)
277 *intval = AFMT_NUM_CODECS;
278 else
279 *intval = id3->codectype;
281 return get_codectype(id3);
283 case WPS_TOKEN_FILE_FREQUENCY:
284 snprintf(buf, buf_size, "%ld", id3->frequency);
285 return buf;
286 case WPS_TOKEN_FILE_FREQUENCY_KHZ:
287 /* ignore remainders < 100, so 22050 Hz becomes just 22k */
288 if ((id3->frequency % 1000) < 100)
289 snprintf(buf, buf_size, "%ld", id3->frequency / 1000);
290 else
291 snprintf(buf, buf_size, "%ld.%lu",
292 id3->frequency / 1000,
293 (id3->frequency % 1000) / 100);
294 return buf;
295 case WPS_TOKEN_FILE_NAME:
296 if (get_dir(buf, buf_size, id3->path, 0)) {
297 /* Remove extension */
298 char* sep = strrchr(buf, '.');
299 if (NULL != sep) {
300 *sep = 0;
302 return buf;
304 return NULL;
305 case WPS_TOKEN_FILE_NAME_WITH_EXTENSION:
306 return get_dir(buf, buf_size, id3->path, 0);
307 case WPS_TOKEN_FILE_SIZE:
308 snprintf(buf, buf_size, "%ld", id3->filesize / 1024);
309 return buf;
310 case WPS_TOKEN_FILE_VBR:
311 return (id3->vbr) ? "(avg)" : NULL;
312 case WPS_TOKEN_FILE_DIRECTORY:
313 return get_dir(buf, buf_size, id3->path, token->value.i);
315 #ifdef HAVE_TAGCACHE
316 case WPS_TOKEN_DATABASE_PLAYCOUNT:
317 if (intval)
318 *intval = id3->playcount + 1;
319 snprintf(buf, buf_size, "%ld", id3->playcount);
320 return buf;
321 case WPS_TOKEN_DATABASE_RATING:
322 if (intval)
323 *intval = id3->rating + 1;
324 snprintf(buf, buf_size, "%d", id3->rating);
325 return buf;
326 case WPS_TOKEN_DATABASE_AUTOSCORE:
327 if (intval)
328 *intval = id3->score + 1;
329 snprintf(buf, buf_size, "%d", id3->score);
330 return buf;
331 #endif
333 default:
334 return NULL;
337 else /* id3 == NULL, handle the error based on the expected return type */
339 switch (token->type)
341 /* Most tokens expect NULL on error so leave that for the default case,
342 * The ones that expect "0" need to be handled */
343 case WPS_TOKEN_FILE_FREQUENCY:
344 case WPS_TOKEN_FILE_FREQUENCY_KHZ:
345 case WPS_TOKEN_FILE_SIZE:
346 #ifdef HAVE_TAGCACHE
347 case WPS_TOKEN_DATABASE_PLAYCOUNT:
348 case WPS_TOKEN_DATABASE_RATING:
349 case WPS_TOKEN_DATABASE_AUTOSCORE:
350 #endif
351 if (intval)
352 *intval = 0;
353 return "0";
354 default:
355 return NULL;
358 return buf;
361 #if CONFIG_TUNER
363 /* Formats the frequency (specified in Hz) in MHz, */
364 /* with one or two digits after the decimal point -- */
365 /* depending on the frequency changing step. */
366 /* Returns buf */
367 static char *format_freq_MHz(int freq, int freq_step, char *buf, int buf_size)
369 int scale, div;
370 char *fmt;
371 if (freq_step < 100000)
373 /* Format with two digits after decimal point */
374 scale = 10000;
375 fmt = "%d.%02d";
377 else
379 /* Format with one digit after decimal point */
380 scale = 100000;
381 fmt = "%d.%d";
383 div = 1000000 / scale;
384 freq = freq / scale;
385 snprintf(buf, buf_size, fmt, freq/div, freq%div);
386 return buf;
390 /* Tokens which are really only used by the radio screen go in here */
391 const char *get_radio_token(struct wps_token *token, int preset_offset,
392 char *buf, int buf_size, int limit, int *intval)
394 const struct fm_region_data *region_data =
395 &(fm_region_data[global_settings.fm_region]);
396 (void)limit;
397 switch (token->type)
399 /* Radio/tuner tokens */
400 case WPS_TOKEN_TUNER_TUNED:
401 if (tuner_get(RADIO_TUNED))
402 return "t";
403 return NULL;
404 case WPS_TOKEN_TUNER_SCANMODE:
405 if (radio_scan_mode())
406 return "s";
407 return NULL;
408 case WPS_TOKEN_TUNER_STEREO:
409 if (radio_is_stereo())
410 return "s";
411 return NULL;
412 case WPS_TOKEN_TUNER_MINFREQ: /* changes based on "region" */
413 return format_freq_MHz(region_data->freq_min,
414 region_data->freq_step, buf, buf_size);
415 case WPS_TOKEN_TUNER_MAXFREQ: /* changes based on "region" */
416 return format_freq_MHz(region_data->freq_max,
417 region_data->freq_step, buf, buf_size);
418 case WPS_TOKEN_TUNER_CURFREQ:
419 return format_freq_MHz(radio_current_frequency(),
420 region_data->freq_step, buf, buf_size);
421 case WPS_TOKEN_PRESET_NAME:
422 case WPS_TOKEN_PRESET_FREQ:
423 case WPS_TOKEN_PRESET_ID:
425 int preset_count = radio_preset_count();
426 int cur_preset = radio_current_preset();
427 if (preset_count == 0 || cur_preset < 0)
428 return NULL;
429 int preset = cur_preset + preset_offset;
430 /* make sure it's in the valid range */
431 preset %= preset_count;
432 if (preset < 0)
433 preset += preset_count;
434 if (token->type == WPS_TOKEN_PRESET_NAME)
435 snprintf(buf, buf_size, "%s", radio_get_preset(preset)->name);
436 else if (token->type == WPS_TOKEN_PRESET_FREQ)
437 format_freq_MHz(radio_get_preset(preset)->frequency,
438 region_data->freq_step, buf, buf_size);
439 else
440 snprintf(buf, buf_size, "%d", preset + 1);
441 return buf;
443 case WPS_TOKEN_PRESET_COUNT:
444 snprintf(buf, buf_size, "%d", radio_preset_count());
445 if (intval)
446 *intval = radio_preset_count();
447 return buf;
448 case WPS_TOKEN_HAVE_RDS:
449 #ifdef HAVE_RDS_CAP
450 return "rds";
451 case WPS_TOKEN_RDS_NAME:
452 return tuner_get_rds_info(RADIO_RDS_NAME);
453 case WPS_TOKEN_RDS_TEXT:
454 return tuner_get_rds_info(RADIO_RDS_TEXT);
455 #else
456 return NULL; /* end of the WPS_TOKEN_HAVE_RDS case */
457 #endif /* HAVE_RDS_CAP */
459 return NULL;
461 #endif
463 /* Return the tags value as text. buf should be used as temp storage if needed.
465 intval is used with conditionals/enums: when this function is called,
466 intval should contain the number of options in the conditional/enum.
467 When this function returns, intval is -1 if the tag is non numeric or,
468 if the tag is numeric, *intval is the enum case we want to go to (between 1
469 and the original value of *intval, inclusive).
470 When not treating a conditional/enum, intval should be NULL.
472 const char *get_token_value(struct gui_wps *gwps,
473 struct wps_token *token,
474 char *buf, int buf_size,
475 int *intval)
477 if (!gwps)
478 return NULL;
480 struct wps_data *data = gwps->data;
481 struct wps_state *state = gwps->state;
482 struct mp3entry *id3; /* Think very carefully about using this.
483 maybe get_id3_token() is the better place? */
484 const char *out_text = NULL;
486 if (!data || !state)
487 return NULL;
490 if (token->next)
491 id3 = state->nid3;
492 else
493 id3 = state->id3;
495 #if CONFIG_RTC
496 struct tm* tm = NULL;
498 /* if the token is an RTC one, update the time
499 and do the necessary checks */
500 if (token->type >= WPS_TOKENS_RTC_BEGIN
501 && token->type <= WPS_TOKENS_RTC_END)
503 tm = get_time();
505 if (!valid_time(tm))
506 return NULL;
508 #endif
510 int limit = 1;
511 if (intval)
513 limit = *intval;
514 *intval = -1;
517 if (state->id3 && state->id3->cuesheet)
519 out_text = get_cuesheetid3_token(token, state->id3, token->next?1:0, buf, buf_size);
520 if (out_text)
521 return out_text;
523 out_text = get_id3_token(token, id3, buf, buf_size, limit, intval);
524 if (out_text)
525 return out_text;
526 #if CONFIG_TUNER
527 out_text = get_radio_token(token, 0, buf, buf_size, limit, intval);
528 if (out_text)
529 return out_text;
530 #endif
532 switch (token->type)
534 case WPS_TOKEN_CHARACTER:
535 if (token->value.c == '\n')
536 return NULL;
537 return &(token->value.c);
539 case WPS_TOKEN_STRING:
540 return (char*)token->value.data;
542 case WPS_TOKEN_TRANSLATEDSTRING:
543 return (char*)P2STR(ID2P(token->value.i));
545 case WPS_TOKEN_PLAYLIST_ENTRIES:
546 snprintf(buf, buf_size, "%d", playlist_amount());
547 return buf;
549 case WPS_TOKEN_LIST_TITLE_TEXT:
550 return (char*)token->value.data;
551 case WPS_TOKEN_LIST_TITLE_ICON:
552 if (intval)
553 *intval = token->value.i;
554 snprintf(buf, buf_size, "%d", token->value.i);
555 return buf;
557 case WPS_TOKEN_PLAYLIST_NAME:
558 return playlist_name(NULL, buf, buf_size);
560 case WPS_TOKEN_PLAYLIST_POSITION:
561 snprintf(buf, buf_size, "%d", playlist_get_display_index());
562 return buf;
564 case WPS_TOKEN_PLAYLIST_SHUFFLE:
565 if ( global_settings.playlist_shuffle )
566 return "s";
567 else
568 return NULL;
569 break;
571 case WPS_TOKEN_VOLUME:
572 snprintf(buf, buf_size, "%d", global_settings.volume);
573 if (intval)
575 int minvol = sound_min(SOUND_VOLUME);
576 if (global_settings.volume == minvol)
578 *intval = 1;
580 else if (global_settings.volume == 0)
582 *intval = limit - 1;
584 else if (global_settings.volume > 0)
586 *intval = limit;
588 else
590 *intval = (limit-3) * (global_settings.volume - minvol - 1)
591 / (-1 - minvol) + 2;
594 return buf;
595 #ifdef HAVE_ALBUMART
596 case WPS_TOKEN_ALBUMART_FOUND:
597 if (data->albumart)
599 int handle = -1;
600 handle = playback_current_aa_hid(data->playback_aa_slot);
601 #if CONFIG_TUNER
602 if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
604 struct dim dim = {data->albumart->width, data->albumart->height};
605 handle = radio_get_art_hid(&dim);
607 #endif
608 if (handle >= 0)
609 return "C";
611 return NULL;
613 case WPS_TOKEN_ALBUMART_DISPLAY:
614 if (!data->albumart)
615 return NULL;
616 if (!data->albumart->draw)
617 data->albumart->draw = true;
618 return NULL;
619 #endif
621 case WPS_TOKEN_BATTERY_PERCENT:
623 int l = battery_level();
625 if (intval)
627 limit = MAX(limit, 2);
628 if (l > -1) {
629 /* First enum is used for "unknown level". */
630 *intval = (limit - 1) * l / 100 + 2;
631 } else {
632 *intval = 1;
636 if (l > -1) {
637 snprintf(buf, buf_size, "%d", l);
638 return buf;
639 } else {
640 return "?";
644 case WPS_TOKEN_BATTERY_VOLTS:
646 unsigned int v = battery_voltage();
647 snprintf(buf, buf_size, "%d.%02d", v / 1000, (v % 1000) / 10);
648 return buf;
651 case WPS_TOKEN_BATTERY_TIME:
653 int t = battery_time();
654 if (t >= 0)
655 snprintf(buf, buf_size, "%dh %dm", t / 60, t % 60);
656 else
657 return "?h ?m";
658 return buf;
661 #if CONFIG_CHARGING
662 case WPS_TOKEN_BATTERY_CHARGER_CONNECTED:
664 if(charger_input_state==CHARGER)
665 return "p";
666 else
667 return NULL;
669 #endif
670 #if CONFIG_CHARGING >= CHARGING_MONITOR
671 case WPS_TOKEN_BATTERY_CHARGING:
673 if (charge_state == CHARGING || charge_state == TOPOFF) {
674 return "c";
675 } else {
676 return NULL;
679 #endif
680 #ifdef HAVE_USB_POWER
681 case WPS_TOKEN_USB_POWERED:
682 if (usb_powered())
683 return "u";
684 return NULL;
685 #endif
686 case WPS_TOKEN_BATTERY_SLEEPTIME:
688 if (get_sleep_timer() == 0)
689 return NULL;
690 else
692 format_time(buf, buf_size, get_sleep_timer() * 1000);
693 return buf;
697 case WPS_TOKEN_PLAYBACK_STATUS:
699 int status = current_playmode();
700 /* music */
701 int mode = 1; /* stop */
702 if (status == STATUS_PLAY)
703 mode = 2; /* play */
704 if (state->is_fading ||
705 (status == STATUS_PAUSE && !status_get_ffmode()))
706 mode = 3; /* pause */
707 else
708 { /* ff / rwd */
709 if (status_get_ffmode() == STATUS_FASTFORWARD)
710 mode = 4;
711 if (status_get_ffmode() == STATUS_FASTBACKWARD)
712 mode = 5;
714 #ifdef HAVE_RECORDING
715 /* recording */
716 if (status == STATUS_RECORD)
717 mode = 6;
718 else if (status == STATUS_RECORD_PAUSE)
719 mode = 7;
720 #endif
721 #if CONFIG_TUNER
722 /* radio */
723 if (status == STATUS_RADIO)
724 mode = 8;
725 else if (status == STATUS_RADIO_PAUSE)
726 mode = 9;
727 #endif
729 if (intval) {
730 *intval = mode;
733 snprintf(buf, buf_size, "%d", mode-1);
734 return buf;
737 case WPS_TOKEN_REPEAT_MODE:
738 if (intval)
739 *intval = global_settings.repeat_mode + 1;
740 snprintf(buf, buf_size, "%d", global_settings.repeat_mode);
741 return buf;
743 case WPS_TOKEN_RTC_PRESENT:
744 #if CONFIG_RTC
745 return "c";
746 #else
747 return NULL;
748 #endif
750 #if CONFIG_RTC
751 case WPS_TOKEN_RTC_12HOUR_CFG:
752 if (intval)
753 *intval = global_settings.timeformat + 1;
754 snprintf(buf, buf_size, "%d", global_settings.timeformat);
755 return buf;
757 case WPS_TOKEN_RTC_DAY_OF_MONTH:
758 /* d: day of month (01..31) */
759 snprintf(buf, buf_size, "%02d", tm->tm_mday);
760 if (intval)
761 *intval = tm->tm_mday - 1;
762 return buf;
764 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
765 /* e: day of month, blank padded ( 1..31) */
766 snprintf(buf, buf_size, "%2d", tm->tm_mday);
767 if (intval)
768 *intval = tm->tm_mday - 1;
769 return buf;
771 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
772 /* H: hour (00..23) */
773 snprintf(buf, buf_size, "%02d", tm->tm_hour);
774 if (intval)
775 *intval = tm->tm_hour;
776 return buf;
778 case WPS_TOKEN_RTC_HOUR_24:
779 /* k: hour ( 0..23) */
780 snprintf(buf, buf_size, "%2d", tm->tm_hour);
781 if (intval)
782 *intval = tm->tm_hour;
783 return buf;
785 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
786 /* I: hour (01..12) */
787 snprintf(buf, buf_size, "%02d",
788 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
789 if (intval)
790 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
791 return buf;
793 case WPS_TOKEN_RTC_HOUR_12:
794 /* l: hour ( 1..12) */
795 snprintf(buf, buf_size, "%2d",
796 (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12);
797 if (intval)
798 *intval = (tm->tm_hour % 12 == 0) ? 12 : tm->tm_hour % 12;
799 return buf;
801 case WPS_TOKEN_RTC_MONTH:
802 /* m: month (01..12) */
803 if (intval)
804 *intval = tm->tm_mon + 1;
805 snprintf(buf, buf_size, "%02d", tm->tm_mon + 1);
806 return buf;
808 case WPS_TOKEN_RTC_MINUTE:
809 /* M: minute (00..59) */
810 snprintf(buf, buf_size, "%02d", tm->tm_min);
811 if (intval)
812 *intval = tm->tm_min;
813 return buf;
815 case WPS_TOKEN_RTC_SECOND:
816 /* S: second (00..59) */
817 snprintf(buf, buf_size, "%02d", tm->tm_sec);
818 if (intval)
819 *intval = tm->tm_sec;
820 return buf;
822 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
823 /* y: last two digits of year (00..99) */
824 snprintf(buf, buf_size, "%02d", tm->tm_year % 100);
825 if (intval)
826 *intval = tm->tm_year % 100;
827 return buf;
829 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
830 /* Y: year (1970...) */
831 snprintf(buf, buf_size, "%04d", tm->tm_year + 1900);
832 if (intval)
833 *intval = tm->tm_year + 1900;
834 return buf;
836 case WPS_TOKEN_RTC_AM_PM_UPPER:
837 /* p: upper case AM or PM indicator */
838 if (intval)
839 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
840 return tm->tm_hour/12 == 0 ? "AM" : "PM";
842 case WPS_TOKEN_RTC_AM_PM_LOWER:
843 /* P: lower case am or pm indicator */
844 if (intval)
845 *intval = tm->tm_hour/12 == 0 ? 0 : 1;
846 return tm->tm_hour/12 == 0 ? "am" : "pm";
848 case WPS_TOKEN_RTC_WEEKDAY_NAME:
849 /* a: abbreviated weekday name (Sun..Sat) */
850 return str(LANG_WEEKDAY_SUNDAY + tm->tm_wday);
852 case WPS_TOKEN_RTC_MONTH_NAME:
853 /* b: abbreviated month name (Jan..Dec) */
854 return str(LANG_MONTH_JANUARY + tm->tm_mon);
856 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
857 /* u: day of week (1..7); 1 is Monday */
858 if (intval)
859 *intval = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
860 snprintf(buf, buf_size, "%1d", tm->tm_wday + 1);
861 return buf;
863 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
864 /* w: day of week (0..6); 0 is Sunday */
865 if (intval)
866 *intval = tm->tm_wday + 1;
867 snprintf(buf, buf_size, "%1d", tm->tm_wday);
868 return buf;
869 #else
870 case WPS_TOKEN_RTC_DAY_OF_MONTH:
871 case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED:
872 case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED:
873 case WPS_TOKEN_RTC_HOUR_24:
874 case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED:
875 case WPS_TOKEN_RTC_HOUR_12:
876 case WPS_TOKEN_RTC_MONTH:
877 case WPS_TOKEN_RTC_MINUTE:
878 case WPS_TOKEN_RTC_SECOND:
879 case WPS_TOKEN_RTC_AM_PM_UPPER:
880 case WPS_TOKEN_RTC_AM_PM_LOWER:
881 case WPS_TOKEN_RTC_YEAR_2_DIGITS:
882 return "--";
883 case WPS_TOKEN_RTC_YEAR_4_DIGITS:
884 return "----";
885 case WPS_TOKEN_RTC_WEEKDAY_NAME:
886 case WPS_TOKEN_RTC_MONTH_NAME:
887 return "---";
888 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON:
889 case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN:
890 return "-";
891 #endif
893 #ifdef HAVE_LCD_CHARCELLS
894 case WPS_TOKEN_PROGRESSBAR:
896 char *end = utf8encode(data->wps_progress_pat[0], buf);
897 *end = '\0';
898 return buf;
901 case WPS_TOKEN_PLAYER_PROGRESSBAR:
902 if(is_new_player())
904 /* we need 11 characters (full line) for
905 progress-bar */
906 strlcpy(buf, " ", buf_size);
908 else
910 /* Tell the user if we have an OldPlayer */
911 strlcpy(buf, " <Old LCD> ", buf_size);
913 return buf;
914 #endif
918 #if (CONFIG_CODEC == SWCODEC)
919 case WPS_TOKEN_CROSSFADE:
920 #ifdef HAVE_CROSSFADE
921 if (intval)
922 *intval = global_settings.crossfade + 1;
923 snprintf(buf, buf_size, "%d", global_settings.crossfade);
924 #else
925 snprintf(buf, buf_size, "%d", 0);
926 #endif
927 return buf;
929 case WPS_TOKEN_REPLAYGAIN:
931 int val;
933 if (global_settings.replaygain_type == REPLAYGAIN_OFF)
934 val = 1; /* off */
935 else
937 int type;
938 if (LIKELY(id3))
939 type = get_replaygain_mode(id3->track_gain_string != NULL,
940 id3->album_gain_string != NULL);
941 else
942 type = -1;
944 if (type < 0)
945 val = 6; /* no tag */
946 else
947 val = type + 2;
949 if (global_settings.replaygain_type == REPLAYGAIN_SHUFFLE)
950 val += 2;
953 if (intval)
954 *intval = val;
956 switch (val)
958 case 1:
959 case 6:
960 return "+0.00 dB";
961 break;
962 /* due to above, coming here with !id3 shouldn't be possible */
963 case 2:
964 case 4:
965 strlcpy(buf, id3->track_gain_string, buf_size);
966 break;
967 case 3:
968 case 5:
969 strlcpy(buf, id3->album_gain_string, buf_size);
970 break;
972 return buf;
974 #endif /* (CONFIG_CODEC == SWCODEC) */
976 #if (CONFIG_CODEC != MAS3507D)
977 case WPS_TOKEN_SOUND_PITCH:
979 int32_t pitch = sound_get_pitch();
980 snprintf(buf, buf_size, "%ld.%ld",
981 pitch / PITCH_SPEED_PRECISION,
982 (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
984 if (intval)
985 *intval = pitch_speed_enum(limit, pitch,
986 PITCH_SPEED_PRECISION * 100);
987 return buf;
989 #endif
991 #if CONFIG_CODEC == SWCODEC
992 case WPS_TOKEN_SOUND_SPEED:
994 int32_t pitch = sound_get_pitch();
995 int32_t speed;
996 if (dsp_timestretch_available())
997 speed = GET_SPEED(pitch, dsp_get_timestretch());
998 else
999 speed = pitch;
1000 snprintf(buf, buf_size, "%ld.%ld",
1001 speed / PITCH_SPEED_PRECISION,
1002 (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
1003 if (intval)
1004 *intval = pitch_speed_enum(limit, speed,
1005 PITCH_SPEED_PRECISION * 100);
1006 return buf;
1008 #endif
1010 case WPS_TOKEN_MAIN_HOLD:
1011 #ifdef HAS_BUTTON_HOLD
1012 if (button_hold())
1013 #else
1014 if (is_keys_locked())
1015 #endif /*hold switch or softlock*/
1016 return "h";
1017 else
1018 return NULL;
1020 #ifdef HAS_REMOTE_BUTTON_HOLD
1021 case WPS_TOKEN_REMOTE_HOLD:
1022 if (remote_button_hold())
1023 return "r";
1024 else
1025 return NULL;
1026 #endif
1028 #if (CONFIG_LED == LED_VIRTUAL) || defined(HAVE_REMOTE_LCD)
1029 case WPS_TOKEN_VLED_HDD:
1030 if(led_read(HZ/2))
1031 return "h";
1032 else
1033 return NULL;
1034 #endif
1035 case WPS_TOKEN_BUTTON_VOLUME:
1036 if (global_status.last_volume_change &&
1037 TIME_BEFORE(current_tick, global_status.last_volume_change +
1038 token->value.i * TIMEOUT_UNIT))
1039 return "v";
1040 return NULL;
1042 case WPS_TOKEN_LASTTOUCH:
1044 #ifdef HAVE_TOUCHSCREEN
1045 unsigned int last_touch = touchscreen_last_touch();
1046 if (last_touch != 0xffff &&
1047 TIME_BEFORE(current_tick, token->value.i * TIMEOUT_UNIT +
1048 last_touch))
1049 return "t";
1050 #endif
1052 return NULL;
1054 case WPS_TOKEN_SETTING:
1056 const struct settings_list *s = settings+token->value.i;
1057 if (intval)
1059 /* Handle contionals */
1060 switch (s->flags&F_T_MASK)
1062 case F_T_INT:
1063 case F_T_UINT:
1064 if (s->flags&F_T_SOUND)
1066 /* %?St|name|<min|min+1|...|max-1|max> */
1067 int sound_setting = s->sound_setting->setting;
1068 /* settings with decimals can't be used in conditionals */
1069 if (sound_numdecimals(sound_setting) == 0)
1071 *intval = (*(int*)s->setting-sound_min(sound_setting))
1072 /sound_steps(sound_setting) + 1;
1074 else
1075 *intval = -1;
1077 else if (s->flags&F_RGB)
1078 /* %?St|name|<#000000|#000001|...|#FFFFFF> */
1079 /* shouldn't overflow since colors are stored
1080 * on 16 bits ...
1081 * but this is pretty useless anyway */
1082 *intval = *(int*)s->setting + 1;
1083 else if (s->cfg_vals == NULL)
1084 /* %?St|name|<1st choice|2nd choice|...> */
1085 *intval = (*(int*)s->setting-s->int_setting->min)
1086 /s->int_setting->step + 1;
1087 else
1088 /* %?St|name|<1st choice|2nd choice|...> */
1089 /* Not sure about this one. cfg_name/vals are
1090 * indexed from 0 right? */
1091 *intval = *(int*)s->setting + 1;
1092 break;
1093 case F_T_BOOL:
1094 /* %?St|name|<if true|if false> */
1095 *intval = *(bool*)s->setting?1:2;
1096 break;
1097 case F_T_CHARPTR:
1098 case F_T_UCHARPTR:
1099 /* %?St|name|<if non empty string|if empty>
1100 * The string's emptyness discards the setting's
1101 * prefix and suffix */
1102 *intval = ((char*)s->setting)[0]?1:2;
1103 /* if there is a prefix we should ignore it here */
1104 if (s->filename_setting->prefix)
1105 return (char*)s->setting;
1106 break;
1107 default:
1108 /* This shouldn't happen ... but you never know */
1109 *intval = -1;
1110 break;
1113 /* Special handlng for filenames because we dont want to show the prefix */
1114 if ((s->flags&F_T_MASK) == F_T_UCHARPTR ||
1115 (s->flags&F_T_MASK) == F_T_UCHARPTR)
1117 if (s->filename_setting->prefix)
1118 return (char*)s->setting;
1120 cfg_to_string(token->value.i,buf,buf_size);
1121 return buf;
1123 case WPS_TOKEN_HAVE_TUNER:
1124 #if CONFIG_TUNER
1125 if (radio_hardware_present())
1126 return "r";
1127 #endif
1128 return NULL;
1129 /* Recording tokens */
1130 case WPS_TOKEN_HAVE_RECORDING:
1131 #ifdef HAVE_RECORDING
1132 return "r";
1133 #else
1134 return NULL;
1135 #endif
1137 #ifdef HAVE_RECORDING
1138 case WPS_TOKEN_IS_RECORDING:
1139 if (audio_status() == AUDIO_STATUS_RECORD)
1140 return "r";
1141 return NULL;
1142 case WPS_TOKEN_REC_FREQ: /* order from REC_FREQ_CFG_VAL_LIST */
1144 #if CONFIG_CODEC == SWCODEC
1145 unsigned long samprk;
1146 int rec_freq = global_settings.rec_frequency;
1148 #ifdef SIMULATOR
1149 samprk = 44100;
1150 #else
1151 #if defined(HAVE_SPDIF_REC)
1152 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1154 /* Use rate in use, not current measured rate if it changed */
1155 samprk = pcm_rec_sample_rate();
1156 rec_freq = 0;
1157 while (rec_freq < SAMPR_NUM_FREQ &&
1158 audio_master_sampr_list[rec_freq] != samprk)
1160 rec_freq++;
1163 else
1164 #endif
1165 samprk = rec_freq_sampr[rec_freq];
1166 #endif /* SIMULATOR */
1167 if (intval)
1169 switch (rec_freq)
1171 REC_HAVE_96_(case REC_FREQ_96:
1172 *intval = 1;
1173 break;)
1174 REC_HAVE_88_(case REC_FREQ_88:
1175 *intval = 2;
1176 break;)
1177 REC_HAVE_64_(case REC_FREQ_64:
1178 *intval = 3;
1179 break;)
1180 REC_HAVE_48_(case REC_FREQ_48:
1181 *intval = 4;
1182 break;)
1183 REC_HAVE_44_(case REC_FREQ_44:
1184 *intval = 5;
1185 break;)
1186 REC_HAVE_32_(case REC_FREQ_32:
1187 *intval = 6;
1188 break;)
1189 REC_HAVE_24_(case REC_FREQ_24:
1190 *intval = 7;
1191 break;)
1192 REC_HAVE_22_(case REC_FREQ_22:
1193 *intval = 8;
1194 break;)
1195 REC_HAVE_16_(case REC_FREQ_16:
1196 *intval = 9;
1197 break;)
1198 REC_HAVE_12_(case REC_FREQ_12:
1199 *intval = 10;
1200 break;)
1201 REC_HAVE_11_(case REC_FREQ_11:
1202 *intval = 11;
1203 break;)
1204 REC_HAVE_8_(case REC_FREQ_8:
1205 *intval = 12;
1206 break;)
1209 snprintf(buf, buf_size, "%lu.%1lu", samprk/1000,samprk%1000);
1210 #else /* HWCODEC */
1212 static const char * const freq_strings[] =
1213 {"--", "44", "48", "32", "22", "24", "16"};
1214 int freq = 1 + global_settings.rec_frequency;
1215 #ifdef HAVE_SPDIF_REC
1216 if (global_settings.rec_source == AUDIO_SRC_SPDIF)
1218 /* Can't measure S/PDIF sample rate on Archos/Sim yet */
1219 freq = 0;
1221 #endif /* HAVE_SPDIF_IN */
1222 if (intval)
1223 *intval = freq+1; /* so the token gets a value 1<=x<=7 */
1224 snprintf(buf, buf_size, "%s\n",
1225 freq_strings[global_settings.rec_frequency]);
1226 #endif
1227 return buf;
1229 #if CONFIG_CODEC == SWCODEC
1230 case WPS_TOKEN_REC_ENCODER:
1232 int rec_format = global_settings.rec_format+1; /* WAV, AIFF, WV, MPEG */
1233 if (intval)
1234 *intval = rec_format;
1235 switch (rec_format)
1237 case REC_FORMAT_PCM_WAV:
1238 return "wav";
1239 case REC_FORMAT_AIFF:
1240 return "aiff";
1241 case REC_FORMAT_WAVPACK:
1242 return "wv";
1243 case REC_FORMAT_MPA_L3:
1244 return "MP3";
1245 default:
1246 return NULL;
1248 break;
1250 #endif
1251 case WPS_TOKEN_REC_BITRATE:
1252 #if CONFIG_CODEC == SWCODEC
1253 if (global_settings.rec_format == REC_FORMAT_MPA_L3)
1255 if (intval)
1257 #if 0 /* FIXME: I dont know if this is needed? */
1258 switch (1<<global_settings.mp3_enc_config.bitrate)
1260 case MP3_BITR_CAP_8:
1261 *intval = 1;
1262 break;
1263 case MP3_BITR_CAP_16:
1264 *intval = 2;
1265 break;
1266 case MP3_BITR_CAP_24:
1267 *intval = 3;
1268 break;
1269 case MP3_BITR_CAP_32:
1270 *intval = 4;
1271 break;
1272 case MP3_BITR_CAP_40:
1273 *intval = 5;
1274 break;
1275 case MP3_BITR_CAP_48:
1276 *intval = 6;
1277 break;
1278 case MP3_BITR_CAP_56:
1279 *intval = 7;
1280 break;
1281 case MP3_BITR_CAP_64:
1282 *intval = 8;
1283 break;
1284 case MP3_BITR_CAP_80:
1285 *intval = 9;
1286 break;
1287 case MP3_BITR_CAP_96:
1288 *intval = 10;
1289 break;
1290 case MP3_BITR_CAP_112:
1291 *intval = 11;
1292 break;
1293 case MP3_BITR_CAP_128:
1294 *intval = 12;
1295 break;
1296 case MP3_BITR_CAP_144:
1297 *intval = 13;
1298 break;
1299 case MP3_BITR_CAP_160:
1300 *intval = 14;
1301 break;
1302 case MP3_BITR_CAP_192:
1303 *intval = 15;
1304 break;
1306 #endif
1307 *intval = global_settings.mp3_enc_config.bitrate+1;
1309 snprintf(buf, buf_size, "%lu", global_settings.mp3_enc_config.bitrate+1);
1310 return buf;
1312 else
1313 return NULL; /* Fixme later */
1314 #else /* CONFIG_CODEC == HWCODEC */
1315 if (intval)
1316 *intval = global_settings.rec_quality+1;
1317 snprintf(buf, buf_size, "%d", global_settings.rec_quality);
1318 return buf;
1319 #endif
1320 case WPS_TOKEN_REC_MONO:
1321 if (!global_settings.rec_channels)
1322 return "m";
1323 return NULL;
1325 case WPS_TOKEN_REC_SECONDS:
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_MINUTES:
1335 int time = (audio_recorded_time() / HZ) / 60;
1336 if (intval)
1337 *intval = time;
1338 snprintf(buf, buf_size, "%02d", time);
1339 return buf;
1341 case WPS_TOKEN_REC_HOURS:
1343 int time = (audio_recorded_time() / HZ) / 3600;
1344 if (intval)
1345 *intval = time;
1346 snprintf(buf, buf_size, "%02d", time);
1347 return buf;
1350 #endif /* HAVE_RECORDING */
1352 case WPS_TOKEN_CURRENT_SCREEN:
1354 int curr_screen = current_screen();
1356 #ifdef HAVE_RECORDING
1357 /* override current_screen() for recording screen since it may
1358 * be entered from the radio screen */
1359 if (in_recording_screen())
1360 curr_screen = GO_TO_RECSCREEN;
1361 #endif
1363 switch (curr_screen)
1365 case GO_TO_WPS:
1366 curr_screen = 2;
1367 break;
1368 #ifdef HAVE_RECORDING
1369 case GO_TO_RECSCREEN:
1370 curr_screen = 3;
1371 break;
1372 #endif
1373 #if CONFIG_TUNER
1374 case GO_TO_FM:
1375 curr_screen = 4;
1376 break;
1377 #endif
1378 case GO_TO_PLAYLIST_VIEWER:
1379 curr_screen = 5;
1380 break;
1381 default: /* lists */
1382 curr_screen = 1;
1383 break;
1385 if (intval)
1387 *intval = curr_screen;
1389 snprintf(buf, buf_size, "%d", curr_screen);
1390 return buf;
1393 case WPS_TOKEN_LANG_IS_RTL:
1394 return lang_is_rtl() ? "r" : NULL;
1396 default:
1397 return NULL;