/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: oscilloscope.c 20680 2009-04-10 17:28:26Z kugel $ * * XYScope, hacked from Oscilloscope. * * Copyright (C) 2004-2006 Jens Arnold (Oscilloscope) * Copyright (C) 2009 Tony Huynh * * 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. * ****************************************************************************/ #include "plugin.h" #include "lib/helper.h" #ifdef HAVE_LCD_BITMAP #include "lib/xlcd.h" #include "lib/configfile.h" PLUGIN_HEADER /* variable button definitions */ #if CONFIG_KEYPAD == RECORDER_PAD #define XYSCOPE_QUIT BUTTON_OFF #define XYSCOPE_PAUSE BUTTON_PLAY #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_UP #define XYSCOPE_VOL_DOWN BUTTON_DOWN #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD #define XYSCOPE_QUIT BUTTON_OFF #define XYSCOPE_PAUSE BUTTON_SELECT #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_UP #define XYSCOPE_VOL_DOWN BUTTON_DOWN #elif CONFIG_KEYPAD == ONDIO_PAD #define XYSCOPE_QUIT BUTTON_OFF #define XYSCOPE_PAUSE (BUTTON_MENU | BUTTON_OFF) #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_UP #define XYSCOPE_VOL_DOWN BUTTON_DOWN #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) #define XYSCOPE_QUIT BUTTON_OFF #define XYSCOPE_PAUSE BUTTON_ON #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_UP #define XYSCOPE_VOL_DOWN BUTTON_DOWN #define XYSCOPE_RC_QUIT BUTTON_RC_STOP #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ (CONFIG_KEYPAD == IPOD_1G2G_PAD) #define XYSCOPE_QUIT (BUTTON_SELECT | BUTTON_MENU) #define XYSCOPE_PAUSE BUTTON_PLAY #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_SCROLL_FWD #define XYSCOPE_VOL_DOWN BUTTON_SCROLL_BACK #elif (CONFIG_KEYPAD == GIGABEAT_PAD) #define XYSCOPE_QUIT BUTTON_POWER #define XYSCOPE_PAUSE BUTTON_A #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_VOL_UP #define XYSCOPE_VOL_DOWN BUTTON_VOL_DOWN #elif (CONFIG_KEYPAD == SANSA_E200_PAD) #define XYSCOPE_QUIT BUTTON_POWER #define XYSCOPE_PAUSE BUTTON_REC #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_SCROLL_FWD #define XYSCOPE_VOL_DOWN BUTTON_SCROLL_BACK #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD) #define XYSCOPE_QUIT (BUTTON_HOME|BUTTON_REPEAT) #define XYSCOPE_PAUSE BUTTON_UP #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_SCROLL_FWD #define XYSCOPE_VOL_DOWN BUTTON_SCROLL_BACK #elif (CONFIG_KEYPAD == SANSA_C200_PAD) #define XYSCOPE_QUIT BUTTON_POWER #define XYSCOPE_PAUSE BUTTON_REC #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_VOL_UP #define XYSCOPE_VOL_DOWN BUTTON_VOL_DOWN #elif (CONFIG_KEYPAD == SANSA_CLIP_PAD) #define XYSCOPE_QUIT BUTTON_POWER #define XYSCOPE_PAUSE BUTTON_HOME #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_VOL_UP #define XYSCOPE_VOL_DOWN BUTTON_VOL_DOWN #elif (CONFIG_KEYPAD == SANSA_M200_PAD) #define XYSCOPE_QUIT BUTTON_POWER #define XYSCOPE_PAUSE (BUTTON_SELECT | BUTTON_UP) #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_VOL_UP #define XYSCOPE_VOL_DOWN BUTTON_VOL_DOWN #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD #define XYSCOPE_QUIT BUTTON_POWER #define XYSCOPE_PAUSE BUTTON_PLAY #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_UP #define XYSCOPE_VOL_DOWN BUTTON_DOWN #elif CONFIG_KEYPAD == IRIVER_H10_PAD #define XYSCOPE_QUIT BUTTON_POWER #define XYSCOPE_PAUSE BUTTON_PLAY #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_SCROLL_UP #define XYSCOPE_VOL_DOWN BUTTON_SCROLL_DOWN #elif CONFIG_KEYPAD == GIGABEAT_S_PAD #define XYSCOPE_QUIT BUTTON_BACK #define XYSCOPE_PAUSE BUTTON_PLAY #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_VOL_UP #define XYSCOPE_VOL_DOWN BUTTON_VOL_DOWN #elif (CONFIG_KEYPAD == MROBE100_PAD) #define XYSCOPE_QUIT BUTTON_POWER #define XYSCOPE_PAUSE BUTTON_DISPLAY #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_UP #define XYSCOPE_VOL_DOWN BUTTON_DOWN #elif CONFIG_KEYPAD == IAUDIO_M3_PAD #define XYSCOPE_QUIT BUTTON_RC_REC #define XYSCOPE_PAUSE BUTTON_RC_PLAY #define XYSCOPE_SPEED_UP BUTTON_RC_FF #define XYSCOPE_SPEED_DOWN BUTTON_RC_REW #define XYSCOPE_VOL_UP BUTTON_RC_VOL_UP #define XYSCOPE_VOL_DOWN BUTTON_RC_VOL_DOWN #elif CONFIG_KEYPAD == COWOND2_PAD #define XYSCOPE_QUIT BUTTON_POWER #define XYSCOPE_VOL_UP BUTTON_PLUS #define XYSCOPE_VOL_DOWN BUTTON_MINUS #elif CONFIG_KEYPAD == CREATIVEZVM_PAD #define XYSCOPE_QUIT BUTTON_BACK #define XYSCOPE_PAUSE BUTTON_PLAY #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_UP #define XYSCOPE_VOL_DOWN BUTTON_DOWN #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD #define XYSCOPE_QUIT BUTTON_POWER #define XYSCOPE_PAUSE BUTTON_SELECT #define XYSCOPE_SPEED_UP BUTTON_RIGHT #define XYSCOPE_SPEED_DOWN BUTTON_LEFT #define XYSCOPE_VOL_UP BUTTON_VOL_UP #define XYSCOPE_VOL_DOWN BUTTON_VOL_DOWN #elif CONFIG_KEYPAD == ONDAVX747_PAD #define XYSCOPE_QUIT BUTTON_POWER #define XYSCOPE_VOL_UP BUTTON_VOL_UP #define XYSCOPE_VOL_DOWN BUTTON_VOL_DOWN #else #error No keymap defined! #endif #ifdef HAVE_TOUCHSCREEN #ifndef XYSCOPE_QUIT #define XYSCOPE_QUIT BUTTON_TOPLEFT #endif #ifndef XYSCOPE_PAUSE #define XYSCOPE_PAUSE BUTTON_CENTER #endif #ifndef XYSCOPE_SPEED_UP #define XYSCOPE_SPEED_UP BUTTON_MIDRIGHT #endif #ifndef XYSCOPE_SPEED_DOWN #define XYSCOPE_SPEED_DOWN BUTTON_MIDLEFT #endif #ifndef XYSCOPE_VOL_UP #define XYSCOPE_VOL_UP BUTTON_TOPRIGHT #endif #ifndef XYSCOPE_VOL_DOWN #define XYSCOPE_VOL_DOWN BUTTON_BOTTOMRIGHT #endif #endif /* colours */ #if LCD_DEPTH > 1 #ifdef HAVE_LCD_COLOR #define BACKG_COLOR LCD_BLACK #define GRAPH_COLOR LCD_RGBPACK(128, 255, 0) #define CURSOR_COLOR LCD_RGBPACK(255, 0, 0) #else #define BACKG_COLOR LCD_WHITE #define GRAPH_COLOR LCD_BLACK #define CURSOR_COLOR LCD_DARKGRAY #endif #endif #define CFGFILE_VERSION 0 /* Current config file version */ #define CFGFILE_MINVERSION 0 /* Minimum config file version to accept */ #define MAX_PEAK 0x8000 #if defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC) #define mas_codec_readreg(x) mas_readreg(x) #endif #define X_ORIGIN (LCD_WIDTH/2) #define Y_ORIGIN (LCD_HEIGHT/2) #define MAX_POINTS 512 /* global variables */ /* settings */ struct xyosc_config { int delay; /* in ticks */ }; struct xyosc_config xyosc_disk = { 2 }; struct xyosc_config xyosc; /* running config */ static const char cfg_filename[] = "xyoscope.cfg"; struct configdata disk_config[] = { { TYPE_INT, 1, 99, { .int_p = &xyosc_disk.delay }, "delay", NULL }, }; long last_tick = 0; /* time of last drawing */ unsigned char message[16]; /* message to display */ bool displaymsg = false; int font_height = 8; /* a single point */ struct point{ short x; short y; long life_tick; /* how many ticks to display for */ }; static struct point point_buffer[MAX_POINTS]; /* Points are written into the above buffer in (FIFO) a cyclic manner */ /* oldest point is overwriten by newest */ /* the next slot to write in */ static int point_next_write = 0; /* implementation */ void draw_current_pixel(int x, int y) { long cur_tick = *rb->current_tick; long d = (cur_tick - last_tick) / xyosc.delay; #if LCD_DEPTH == 1 int i; #endif if (d == 0) /* too early, bail out */ return; last_tick = cur_tick; #if LCD_DEPTH > 1 /* erase what was in this place */ rb->lcd_set_foreground(BACKG_COLOR); rb->lcd_drawpixel( point_buffer[point_next_write].x, point_buffer[point_next_write].y ); #else rb->lcd_clear_display(); #endif point_buffer[point_next_write].x = x; point_buffer[point_next_write].y = y; #if LCD_DEPTH > 1 /* draw new point */ rb->lcd_set_foreground(GRAPH_COLOR); rb->lcd_drawpixel( point_buffer[point_next_write].x, point_buffer[point_next_write].y ); #else /* redraw all points */ for( i = 0; i < MAX_POINTS; i++ ) rb->lcd_drawpixel( point_buffer[i].x, point_buffer[i].y ); #endif point_next_write = (point_next_write + 1) % MAX_POINTS; #if defined(DEBUG) || defined(SIMULATOR) rb->snprintf(message, 16, "x: %d, y: %d", x, y); displaymsg = true; #endif if (displaymsg) { int width; rb->lcd_getstringsize(message, &width, NULL); rb->lcd_putsxy(0, 0, message); displaymsg = false; } rb->lcd_update(); } void cleanup(void *parameter) { (void)parameter; #if LCD_DEPTH > 1 rb->lcd_set_foreground(LCD_DEFAULT_FG); rb->lcd_set_background(LCD_DEFAULT_BG); #endif /* Turn on backlight timeout (revert to settings) */ backlight_use_settings(); /* backlight control in lib/helper.c */ } enum plugin_status plugin_start(const void* parameter) { int button, vol; int lastbutton = BUTTON_NONE; bool exit = false; bool paused = false; bool tell_speed; (void)parameter; configfile_load(cfg_filename, disk_config, sizeof(disk_config) / sizeof(disk_config[0]), CFGFILE_MINVERSION); rb->memcpy(&xyosc, &xyosc_disk, sizeof(xyosc)); /* copy to running config */ #if LCD_DEPTH > 1 rb->lcd_set_foreground(GRAPH_COLOR); rb->lcd_set_background(BACKG_COLOR); rb->lcd_set_backdrop(NULL); rb->lcd_clear_display(); rb->lcd_update(); #endif rb->lcd_set_drawmode(DRMODE_SOLID); /* Turn off backlight timeout */ backlight_force_on(); /* backlight control in lib/helper.c */ rb->lcd_getstringsize("A", NULL, &font_height); /* init points */ int i; for( i = 0; i < MAX_POINTS; i++ ){ point_buffer[i].x = 0; point_buffer[i].y = 0; point_buffer[i].life_tick = 0; } while ((!exit) && (!paused)) { #if (CONFIG_CODEC == SWCODEC) int16_t *buffer; int count; #endif rb->sleep( MAX(last_tick + xyosc.delay - *rb->current_tick - 1, 0) ); #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) #ifdef SIMULATOR /* HWCODEC sim doesn't play audio */ draw_current_pixel(0, 0); #else draw_current_pixel((LCD_WIDTH * rb->mas_codec_readreg(0xC)) >> 15, (LCD_HEIGHT * rb->mas_codec_readreg(0xD)) >> 15); #endif #elif (CONFIG_CODEC == SWCODEC) buffer = (int16_t *) rb->pcm_get_peak_buffer(&count); if (&buffer == 0 || count == 0) { if (rb->audio_status() & AUDIO_STATUS_PLAY) continue; } else { draw_current_pixel(X_ORIGIN + ((LCD_WIDTH * buffer[1]) >> 16), Y_ORIGIN + ((LCD_HEIGHT * buffer[0]) >> 16)); } #endif tell_speed = false; button = rb->button_get(paused); switch (button) { #ifdef XYSCOPE_RC_QUIT case XYSCOPE_RC_QUIT: #endif case XYSCOPE_QUIT: exit = true; break; case XYSCOPE_PAUSE: paused = !paused; last_tick = 0; break; case XYSCOPE_SPEED_UP: case XYSCOPE_SPEED_UP | BUTTON_REPEAT: if (xyosc.delay > 1) { xyosc.delay--; tell_speed = true; } break; case XYSCOPE_SPEED_DOWN: case XYSCOPE_SPEED_DOWN | BUTTON_REPEAT: xyosc.delay++; tell_speed = true; break; case XYSCOPE_VOL_UP: case XYSCOPE_VOL_UP | BUTTON_REPEAT: vol = rb->global_settings->volume; if (vol < rb->sound_max(SOUND_VOLUME)) { vol++; rb->sound_set(SOUND_VOLUME, vol); rb->global_settings->volume = vol; } break; case XYSCOPE_VOL_DOWN: case XYSCOPE_VOL_DOWN | BUTTON_REPEAT: vol = rb->global_settings->volume; if (vol > rb->sound_min(SOUND_VOLUME)) { vol--; rb->sound_set(SOUND_VOLUME, vol); rb->global_settings->volume = vol; } break; default: if (rb->default_event_handler_ex(button, cleanup, NULL) == SYS_USB_CONNECTED) return PLUGIN_USB_CONNECTED; break; } if (button != BUTTON_NONE) lastbutton = button; if (tell_speed) { rb->snprintf(message, sizeof(message), "%s%d ", "Speed: ", 100 / xyosc.delay); displaymsg = true; } } cleanup(NULL); if (rb->memcmp(&xyosc, &xyosc_disk, sizeof(xyosc))) /* save settings if changed */ { rb->memcpy(&xyosc_disk, &xyosc, sizeof(xyosc)); configfile_save(cfg_filename, disk_config, sizeof(disk_config) / sizeof(disk_config[0]), CFGFILE_VERSION); } return PLUGIN_OK; } #endif /* HAVE_LCD_BITMAP */