| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * Copyright (C) 2007 Nicolas Pennequin, Dan Everton, Matthias Mohr |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| |
| #ifdef DEBUG |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include "gwps.h" |
| #ifdef __PCTOOL__ |
| #define DEBUGF printf |
| #else |
| #include "debug.h" |
| #endif |
| |
| #define PARSE_FAIL_UNCLOSED_COND 1 |
| #define PARSE_FAIL_INVALID_CHAR 2 |
| #define PARSE_FAIL_COND_SYNTAX_ERROR 3 |
| #define PARSE_FAIL_COND_INVALID_PARAM 4 |
| |
| #if defined(SIMULATOR) || defined(__PCTOOL__) |
| extern bool debug_wps; |
| extern int wps_verbose_level; |
| #endif |
| |
| static char *next_str(bool next) { |
| return next ? "next " : ""; |
| } |
| |
| static char *get_token_desc(struct wps_token *token, struct wps_data *data, |
| char *buf, int bufsize) |
| { |
| bool next = token->next; |
| |
| switch(token->type) |
| { |
| case WPS_NO_TOKEN: |
| snprintf(buf, bufsize, "No token"); |
| break; |
| |
| case WPS_TOKEN_UNKNOWN: |
| snprintf(buf, bufsize, "Unknown token"); |
| break; |
| |
| case WPS_TOKEN_CHARACTER: |
| snprintf(buf, bufsize, "Character '%c'", |
| token->value.c); |
| break; |
| |
| case WPS_TOKEN_STRING: |
| snprintf(buf, bufsize, "String '%s'", |
| data->strings[token->value.i]); |
| break; |
| |
| #ifdef HAVE_LCD_BITMAP |
| case WPS_TOKEN_ALIGN_LEFT: |
| snprintf(buf, bufsize, "align left"); |
| break; |
| |
| case WPS_TOKEN_ALIGN_CENTER: |
| snprintf(buf, bufsize, "align center"); |
| break; |
| |
| case WPS_TOKEN_ALIGN_RIGHT: |
| snprintf(buf, bufsize, "align right"); |
| break; |
| #endif |
| |
| case WPS_TOKEN_SUBLINE_TIMEOUT: |
| snprintf(buf, bufsize, "subline timeout value: %d", |
| token->value.i); |
| break; |
| |
| case WPS_TOKEN_CONDITIONAL: |
| snprintf(buf, bufsize, "conditional, %d options", |
| token->value.i); |
| break; |
| |
| case WPS_TOKEN_CONDITIONAL_START: |
| snprintf(buf, bufsize, "conditional start, next cond: %d", |
| token->value.i); |
| break; |
| |
| case WPS_TOKEN_CONDITIONAL_OPTION: |
| snprintf(buf, bufsize, "conditional option, next cond: %d", |
| token->value.i); |
| break; |
| |
| case WPS_TOKEN_CONDITIONAL_END: |
| snprintf(buf, bufsize, "conditional end"); |
| break; |
| |
| #ifdef HAVE_LCD_BITMAP |
| case WPS_TOKEN_IMAGE_PRELOAD: |
| snprintf(buf, bufsize, "preload image"); |
| break; |
| |
| case WPS_TOKEN_IMAGE_PRELOAD_DISPLAY: |
| snprintf(buf, bufsize, "display preloaded image %d", |
| token->value.i); |
| break; |
| |
| case WPS_TOKEN_IMAGE_DISPLAY: |
| snprintf(buf, bufsize, "display image"); |
| break; |
| #endif |
| |
| #ifdef HAS_BUTTON_HOLD |
| case WPS_TOKEN_MAIN_HOLD: |
| snprintf(buf, bufsize, "mode hold"); |
| break; |
| #endif |
| |
| #ifdef HAS_REMOTE_BUTTON_HOLD |
| case WPS_TOKEN_REMOTE_HOLD: |
| snprintf(buf, bufsize, "mode remote hold"); |
| break; |
| #endif |
| |
| case WPS_TOKEN_REPEAT_MODE: |
| snprintf(buf, bufsize, "mode repeat"); |
| break; |
| |
| case WPS_TOKEN_PLAYBACK_STATUS: |
| snprintf(buf, bufsize, "mode playback"); |
| break; |
| |
| case WPS_TOKEN_RTC_DAY_OF_MONTH: |
| snprintf(buf, bufsize, "rtc: day of month (01..31)"); |
| break; |
| case WPS_TOKEN_RTC_DAY_OF_MONTH_BLANK_PADDED: |
| snprintf(buf, bufsize, |
| "rtc: day of month, blank padded ( 1..31)"); |
| break; |
| case WPS_TOKEN_RTC_HOUR_24_ZERO_PADDED: |
| snprintf(buf, bufsize, "rtc: hour (00..23)"); |
| break; |
| case WPS_TOKEN_RTC_HOUR_24: |
| snprintf(buf, bufsize, "rtc: hour ( 0..23)"); |
| break; |
| case WPS_TOKEN_RTC_HOUR_12_ZERO_PADDED: |
| snprintf(buf, bufsize, "rtc: hour (01..12)"); |
| break; |
| case WPS_TOKEN_RTC_HOUR_12: |
| snprintf(buf, bufsize, "rtc: hour ( 1..12)"); |
| break; |
| case WPS_TOKEN_RTC_MONTH: |
| snprintf(buf, bufsize, "rtc: month (01..12)"); |
| break; |
| case WPS_TOKEN_RTC_MINUTE: |
| snprintf(buf, bufsize, "rtc: minute (00..59)"); |
| break; |
| case WPS_TOKEN_RTC_SECOND: |
| snprintf(buf, bufsize, "rtc: second (00..59)"); |
| break; |
| case WPS_TOKEN_RTC_YEAR_2_DIGITS: |
| snprintf(buf, bufsize, |
| "rtc: last two digits of year (00..99)"); |
| break; |
| case WPS_TOKEN_RTC_YEAR_4_DIGITS: |
| snprintf(buf, bufsize, "rtc: year (1970...)"); |
| break; |
| case WPS_TOKEN_RTC_AM_PM_UPPER: |
| snprintf(buf, bufsize, |
| "rtc: upper case AM or PM indicator"); |
| break; |
| case WPS_TOKEN_RTC_AM_PM_LOWER: |
| snprintf(buf, bufsize, |
| "rtc: lower case am or pm indicator"); |
| break; |
| case WPS_TOKEN_RTC_WEEKDAY_NAME: |
| snprintf(buf, bufsize, |
| "rtc: abbreviated weekday name (Sun..Sat)"); |
| break; |
| case WPS_TOKEN_RTC_MONTH_NAME: |
| snprintf(buf, bufsize, |
| "rtc: abbreviated month name (Jan..Dec)"); |
| break; |
| case WPS_TOKEN_RTC_DAY_OF_WEEK_START_MON: |
| snprintf(buf, bufsize, |
| "rtc: day of week (1..7); 1 is Monday"); |
| break; |
| case WPS_TOKEN_RTC_DAY_OF_WEEK_START_SUN: |
| snprintf(buf, bufsize, |
| "rtc: day of week (0..6); 0 is Sunday"); |
| break; |
| |
| #if (CONFIG_CODEC == SWCODEC) |
| case WPS_TOKEN_CROSSFADE: |
| snprintf(buf, bufsize, "crossfade"); |
| break; |
| |
| case WPS_TOKEN_REPLAYGAIN: |
| snprintf(buf, bufsize, "replaygain"); |
| break; |
| #endif |
| |
| #ifdef HAVE_ALBUMART |
| case WPS_TOKEN_ALBUMART_DISPLAY: |
| snprintf(buf, bufsize, "album art display"); |
| break; |
| |
| case WPS_TOKEN_ALBUMART_FOUND: |
| snprintf(buf, bufsize, "%strack album art conditional", |
| next_str(next)); |
| break; |
| #endif |
| |
| #ifdef HAVE_LCD_BITMAP |
| case WPS_TOKEN_IMAGE_BACKDROP: |
| snprintf(buf, bufsize, "backdrop image"); |
| break; |
| |
| case WPS_TOKEN_IMAGE_PROGRESS_BAR: |
| snprintf(buf, bufsize, "progressbar bitmap"); |
| break; |
| |
| case WPS_TOKEN_PEAKMETER: |
| snprintf(buf, bufsize, "peakmeter"); |
| break; |
| #endif |
| |
| case WPS_TOKEN_PROGRESSBAR: |
| snprintf(buf, bufsize, "progressbar"); |
| break; |
| |
| #ifdef HAVE_LCD_CHARCELLS |
| case WPS_TOKEN_PLAYER_PROGRESSBAR: |
| snprintf(buf, bufsize, "full line progressbar"); |
| break; |
| #endif |
| |
| case WPS_TOKEN_TRACK_TIME_ELAPSED: |
| snprintf(buf, bufsize, "time elapsed in track"); |
| break; |
| |
| case WPS_TOKEN_TRACK_ELAPSED_PERCENT: |
| snprintf(buf, bufsize, "played percentage of track"); |
| break; |
| |
| case WPS_TOKEN_PLAYLIST_ENTRIES: |
| snprintf(buf, bufsize, "number of entries in playlist"); |
| break; |
| |
| case WPS_TOKEN_PLAYLIST_NAME: |
| snprintf(buf, bufsize, "playlist name"); |
| break; |
| |
| case WPS_TOKEN_PLAYLIST_POSITION: |
| snprintf(buf, bufsize, "position in playlist"); |
| break; |
| |
| case WPS_TOKEN_TRACK_TIME_REMAINING: |
| snprintf(buf, bufsize, "time remaining in track"); |
| break; |
| |
| case WPS_TOKEN_PLAYLIST_SHUFFLE: |
| snprintf(buf, bufsize, "playlist shuffle mode"); |
| break; |
| |
| case WPS_TOKEN_TRACK_LENGTH: |
| snprintf(buf, bufsize, "track length"); |
| break; |
| |
| case WPS_TOKEN_VOLUME: |
| snprintf(buf, bufsize, "volume"); |
| break; |
| |
| case WPS_TOKEN_METADATA_ARTIST: |
| snprintf(buf, bufsize, "%strack artist", |
| next_str(next)); |
| break; |
| |
| case WPS_TOKEN_METADATA_COMPOSER: |
| snprintf(buf, bufsize, "%strack composer", |
| next_str(next)); |
| break; |
| |
| case WPS_TOKEN_METADATA_ALBUM: |
| snprintf(buf, bufsize, "%strack album", |
| next_str(next)); |
| break; |
| |
| case WPS_TOKEN_METADATA_GROUPING: |
| snprintf(buf, bufsize, "%strack grouping", |
| next_str(next)); |
| break; |
| |
| case WPS_TOKEN_METADATA_GENRE: |
| snprintf(buf, bufsize, "%strack genre", |
| next_str(next)); |
| break; |
| |
| case WPS_TOKEN_METADATA_DISC_NUMBER: |
| snprintf(buf, bufsize, "%strack disc", next_str(next)); |
| break; |
| |
| case WPS_TOKEN_METADATA_TRACK_NUMBER: |
| snprintf(buf, bufsize, "%strack number", |
| next_str(next)); |
| break; |
| |
| case WPS_TOKEN_METADATA_TRACK_TITLE: |
| snprintf(buf, bufsize, "%strack title", |
| next_str(next)); |
| break; |
| |
| case WPS_TOKEN_METADATA_VERSION: |
| snprintf(buf, bufsize, "%strack ID3 version", |
| next_str(next)); |
| break; |
| |
| case WPS_TOKEN_METADATA_ALBUM_ARTIST: |
| snprintf(buf, bufsize, "%strack album artist", |
| next_str(next)); |
| break; |
| |
| case WPS_TOKEN_METADATA_COMMENT: |
| snprintf(buf, bufsize, "%strack comment", |
| next_str(next)); |
| break; |
| |
| case WPS_TOKEN_METADATA_YEAR: |
| snprintf(buf, bufsize, "%strack year", next_str(next)); |
| break; |
| |
| #ifdef HAVE_TAGCACHE |
| case WPS_TOKEN_DATABASE_PLAYCOUNT: |
| snprintf(buf, bufsize, "track playcount (database)"); |
| break; |
| |
| case WPS_TOKEN_DATABASE_RATING: |
| snprintf(buf, bufsize, "track rating (database)"); |
| break; |
| |
| case WPS_TOKEN_DATABASE_AUTOSCORE: |
| snprintf(buf, bufsize, "track autoscore (database)"); |
| break; |
| #endif |
| |
| case WPS_TOKEN_BATTERY_PERCENT: |
| snprintf(buf, bufsize, "battery percentage"); |
| break; |
| |
| case WPS_TOKEN_BATTERY_VOLTS: |
| snprintf(buf, bufsize, "battery voltage"); |
| break; |
| |
| case WPS_TOKEN_BATTERY_TIME: |
| snprintf(buf, bufsize, "battery time left"); |
| break; |
| |
| case WPS_TOKEN_BATTERY_CHARGER_CONNECTED: |
| snprintf(buf, bufsize, "battery charger connected"); |
| break; |
| |
| case WPS_TOKEN_BATTERY_CHARGING: |
| snprintf(buf, bufsize, "battery charging"); |
| break; |
| |
| case WPS_TOKEN_BATTERY_SLEEPTIME: |
| snprintf(buf, bufsize, "sleep timer"); |
| break; |
| |
| case WPS_TOKEN_FILE_BITRATE: |
| snprintf(buf, bufsize, "%sfile bitrate", next_str(next)); |
| break; |
| |
| case WPS_TOKEN_FILE_CODEC: |
| snprintf(buf, bufsize, "%sfile codec", next_str(next)); |
| break; |
| |
| case WPS_TOKEN_FILE_FREQUENCY: |
| snprintf(buf, bufsize, "%sfile audio frequency in Hz", |
| next_str(next)); |
| break; |
| |
| case WPS_TOKEN_FILE_FREQUENCY_KHZ: |
| snprintf(buf, bufsize, "%sfile audio frequency in KHz", |
| next_str(next)); |
| break; |
| |
| case WPS_TOKEN_FILE_NAME: |
| snprintf(buf, bufsize, "%sfile name", next_str(next)); |
| break; |
| |
| case WPS_TOKEN_FILE_NAME_WITH_EXTENSION: |
| snprintf(buf, bufsize, "%sfile name with extension", |
| next_str(next)); |
| break; |
| |
| case WPS_TOKEN_FILE_PATH: |
| snprintf(buf, bufsize, "%sfile path", next_str(next)); |
| break; |
| |
| case WPS_TOKEN_FILE_SIZE: |
| snprintf(buf, bufsize, "%sfile size", next_str(next)); |
| break; |
| |
| case WPS_TOKEN_FILE_VBR: |
| snprintf(buf, bufsize, "%sfile is vbr", next_str(next)); |
| break; |
| |
| case WPS_TOKEN_FILE_DIRECTORY: |
| snprintf(buf, bufsize, "%sfile directory, level: %d", |
| next_str(next), token->value.i); |
| break; |
| |
| #if (CONFIG_CODEC != MAS3507D) |
| case WPS_TOKEN_SOUND_PITCH: |
| snprintf(buf, bufsize, "pitch value"); |
| break; |
| #endif |
| case WPS_VIEWPORT_ENABLE: |
| snprintf(buf, bufsize, "enable VP:%d", |
| token->value.i); |
| break; |
| |
| default: |
| snprintf(buf, bufsize, "FIXME (code: %d)", |
| token->type); |
| break; |
| } |
| |
| return buf; |
| } |
| |
| #if defined(SIMULATOR) || defined(__PCTOOL__) |
| static void dump_wps_tokens(struct wps_data *data) |
| { |
| struct wps_token *token; |
| int i, j; |
| int indent = 0; |
| char buf[64]; |
| int num_string_tokens = 0; |
| |
| /* Dump parsed WPS */ |
| for (i = 0, token = data->tokens; i < data->num_tokens; i++, token++) |
| { |
| get_token_desc(token, data, buf, sizeof(buf)); |
| |
| switch(token->type) |
| { |
| case WPS_TOKEN_STRING: |
| num_string_tokens++; |
| break; |
| |
| case WPS_TOKEN_CONDITIONAL_START: |
| indent++; |
| break; |
| |
| case WPS_TOKEN_CONDITIONAL_END: |
| indent--; |
| break; |
| |
| default: |
| break; |
| } |
| |
| if (wps_verbose_level > 2) |
| { |
| for(j = 0; j < indent; j++) { |
| DEBUGF("\t"); |
| } |
| |
| DEBUGF("[%3d] = (%2d) %s\n", i, token->type, buf); |
| } |
| } |
| |
| if (wps_verbose_level > 0) |
| { |
| DEBUGF("\n"); |
| DEBUGF("Number of string tokens: %d\n", num_string_tokens); |
| DEBUGF("\n"); |
| } |
| } |
| |
| static void print_line_info(struct wps_data *data) |
| { |
| int i, j, v; |
| struct wps_line *line; |
| struct wps_subline *subline; |
| |
| if (wps_verbose_level > 0) |
| { |
| DEBUGF("Number of viewports : %d\n", data->num_viewports); |
| for (v = 0; v < data->num_viewports; v++) |
| { |
| DEBUGF("vp %d: First line: %d\n", v, data->viewports[v].first_line); |
| DEBUGF("vp %d: Last line: %d\n", v, data->viewports[v].last_line); |
| } |
| DEBUGF("Number of sublines : %d\n", data->num_sublines); |
| DEBUGF("Number of tokens : %d\n", data->num_tokens); |
| DEBUGF("\n"); |
| } |
| |
| if (wps_verbose_level > 1) |
| { |
| for (v = 0; v < data->num_viewports; v++) |
| { |
| DEBUGF("Viewport %d - +%d+%d (%dx%d)\n",v,data->viewports[v].vp.x, |
| data->viewports[v].vp.y, |
| data->viewports[v].vp.width, |
| data->viewports[v].vp.height); |
| for (i = data->viewports[v].first_line, line = &data->lines[data->viewports[v].first_line]; i <= data->viewports[v].last_line; i++,line++) |
| { |
| DEBUGF("Line %2d (num_sublines=%d, first_subline=%d)\n", |
| i, line->num_sublines, line->first_subline_idx); |
| |
| for (j = 0, subline = data->sublines + line->first_subline_idx; |
| j < line->num_sublines; j++, subline++) |
| { |
| DEBUGF(" Subline %d: first_token=%3d, last_token=%3d", |
| j, subline->first_token_idx, |
| wps_last_token_index(data, i, j)); |
| |
| if (subline->line_type & WPS_REFRESH_SCROLL) |
| DEBUGF(", scrolled"); |
| else if (subline->line_type & WPS_REFRESH_PLAYER_PROGRESS) |
| DEBUGF(", progressbar"); |
| else if (subline->line_type & WPS_REFRESH_PEAK_METER) |
| DEBUGF(", peakmeter"); |
| |
| DEBUGF("\n"); |
| } |
| } |
| } |
| |
| DEBUGF("\n"); |
| } |
| } |
| |
| static void print_wps_strings(struct wps_data *data) |
| { |
| int i, len, total_len = 0, buf_used = 0; |
| |
| if (wps_verbose_level > 1) DEBUGF("Strings:\n"); |
| for (i = 0; i < data->num_strings; i++) |
| { |
| len = strlen(data->strings[i]); |
| total_len += len; |
| buf_used += len + 1; |
| if (wps_verbose_level > 1) |
| DEBUGF("%2d: (%2d) '%s'\n", i, len, data->strings[i]); |
| } |
| if (wps_verbose_level > 1) DEBUGF("\n"); |
| |
| if (wps_verbose_level > 0) |
| { |
| DEBUGF("Number of unique strings: %d (max: %d)\n", |
| data->num_strings, WPS_MAX_STRINGS); |
| DEBUGF("Total string length: %d\n", total_len); |
| DEBUGF("String buffer used: %d out of %d bytes\n", |
| buf_used, STRING_BUFFER_SIZE); |
| DEBUGF("\n"); |
| } |
| } |
| #endif |
| |
| void print_debug_info(struct wps_data *data, int fail, int line) |
| { |
| #if defined(SIMULATOR) || defined(__PCTOOL__) |
| if (debug_wps && wps_verbose_level) |
| { |
| dump_wps_tokens(data); |
| print_wps_strings(data); |
| print_line_info(data); |
| } |
| #endif /* SIMULATOR */ |
| |
| if (data->num_tokens >= WPS_MAX_TOKENS - 1) { |
| DEBUGF("Warning: Max number of tokens was reached (%d)\n", |
| WPS_MAX_TOKENS - 1); |
| } |
| |
| if (fail) |
| { |
| char buf[64]; |
| |
| DEBUGF("Failed parsing on line %d : ", line); |
| switch (fail) |
| { |
| case PARSE_FAIL_UNCLOSED_COND: |
| DEBUGF("Unclosed conditional"); |
| break; |
| |
| case PARSE_FAIL_INVALID_CHAR: |
| DEBUGF("unexpected conditional char after token %d: \"%s\"", |
| data->num_tokens-1, |
| get_token_desc(&data->tokens[data->num_tokens-1], data, |
| buf, sizeof(buf)) |
| ); |
| break; |
| |
| case PARSE_FAIL_COND_SYNTAX_ERROR: |
| DEBUGF("Conditional syntax error after token %d: \"%s\"", |
| data->num_tokens-1, |
| get_token_desc(&data->tokens[data->num_tokens-1], data, |
| buf, sizeof(buf)) |
| ); |
| break; |
| |
| case PARSE_FAIL_COND_INVALID_PARAM: |
| DEBUGF("Invalid parameter list for token %d: \"%s\"", |
| data->num_tokens, |
| get_token_desc(&data->tokens[data->num_tokens], data, |
| buf, sizeof(buf)) |
| ); |
| break; |
| } |
| DEBUGF("\n"); |
| } |
| } |
| |
| #endif /* DEBUG */ |