| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * Oscilloscope, with many different modes of operation. |
| * |
| * Copyright (C) 2004-2006 Jens Arnold |
| * |
| * 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 "helper.h" |
| |
| #ifdef HAVE_LCD_BITMAP |
| #include "xlcd.h" |
| #include "configfile.h" |
| |
| PLUGIN_HEADER |
| |
| /* variable button definitions */ |
| #if CONFIG_KEYPAD == RECORDER_PAD |
| #define OSCILLOSCOPE_QUIT BUTTON_OFF |
| #define OSCILLOSCOPE_DRAWMODE BUTTON_F1 |
| #define OSCILLOSCOPE_ADVMODE BUTTON_F2 |
| #define OSCILLOSCOPE_ORIENTATION BUTTON_F3 |
| #define OSCILLOSCOPE_PAUSE BUTTON_PLAY |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT |
| #define OSCILLOSCOPE_VOL_UP BUTTON_UP |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN |
| |
| #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD |
| #define OSCILLOSCOPE_QUIT BUTTON_OFF |
| #define OSCILLOSCOPE_DRAWMODE BUTTON_F1 |
| #define OSCILLOSCOPE_ADVMODE BUTTON_F2 |
| #define OSCILLOSCOPE_ORIENTATION BUTTON_F3 |
| #define OSCILLOSCOPE_PAUSE BUTTON_SELECT |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT |
| #define OSCILLOSCOPE_VOL_UP BUTTON_UP |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN |
| |
| #elif CONFIG_KEYPAD == ONDIO_PAD |
| #define OSCILLOSCOPE_QUIT BUTTON_OFF |
| #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_MENU |
| #define OSCILLOSCOPE_DRAWMODE (BUTTON_MENU | BUTTON_REL) |
| #define OSCILLOSCOPE_ADVMODE (BUTTON_MENU | BUTTON_RIGHT) |
| #define OSCILLOSCOPE_ORIENTATION (BUTTON_MENU | BUTTON_LEFT) |
| #define OSCILLOSCOPE_PAUSE (BUTTON_MENU | BUTTON_OFF) |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT |
| #define OSCILLOSCOPE_VOL_UP BUTTON_UP |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN |
| |
| #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) |
| #define OSCILLOSCOPE_QUIT BUTTON_OFF |
| #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT |
| #define OSCILLOSCOPE_ADVMODE BUTTON_MODE |
| #define OSCILLOSCOPE_ORIENTATION BUTTON_REC |
| #define OSCILLOSCOPE_PAUSE BUTTON_ON |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT |
| #define OSCILLOSCOPE_VOL_UP BUTTON_UP |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN |
| #define OSCILLOSCOPE_RC_QUIT BUTTON_RC_STOP |
| |
| #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \ |
| (CONFIG_KEYPAD == IPOD_1G2G_PAD) |
| #define OSCILLOSCOPE_QUIT (BUTTON_SELECT | BUTTON_MENU) |
| #define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_PLAY) |
| #define OSCILLOSCOPE_ADVMODE (BUTTON_SELECT | BUTTON_RIGHT) |
| #define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_LEFT) |
| #define OSCILLOSCOPE_PAUSE BUTTON_PLAY |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT |
| #define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK |
| |
| #elif (CONFIG_KEYPAD == GIGABEAT_PAD) |
| #define OSCILLOSCOPE_QUIT BUTTON_POWER |
| #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT |
| #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN |
| #define OSCILLOSCOPE_ORIENTATION BUTTON_UP |
| #define OSCILLOSCOPE_PAUSE BUTTON_A |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT |
| #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN |
| |
| #elif (CONFIG_KEYPAD == SANSA_E200_PAD) |
| #define OSCILLOSCOPE_QUIT BUTTON_POWER |
| #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT |
| #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN |
| #define OSCILLOSCOPE_ORIENTATION BUTTON_UP |
| #define OSCILLOSCOPE_PAUSE BUTTON_REC |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT |
| #define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK |
| |
| #elif (CONFIG_KEYPAD == SANSA_C200_PAD) |
| #define OSCILLOSCOPE_QUIT BUTTON_POWER |
| #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT |
| #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN |
| #define OSCILLOSCOPE_ORIENTATION BUTTON_UP |
| #define OSCILLOSCOPE_PAUSE BUTTON_REC |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT |
| #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN |
| |
| #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD |
| #define OSCILLOSCOPE_QUIT BUTTON_POWER |
| #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT |
| #define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL) |
| #define OSCILLOSCOPE_ADVMODE BUTTON_REC |
| #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT |
| #define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT) |
| #define OSCILLOSCOPE_PAUSE BUTTON_PLAY |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT |
| #define OSCILLOSCOPE_VOL_UP BUTTON_UP |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN |
| |
| #elif CONFIG_KEYPAD == IRIVER_H10_PAD |
| #define OSCILLOSCOPE_QUIT BUTTON_POWER |
| #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_REW |
| #define OSCILLOSCOPE_DRAWMODE (BUTTON_REW | BUTTON_REL) |
| #define OSCILLOSCOPE_ADVMODE BUTTON_FF |
| #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_REW |
| #define OSCILLOSCOPE_ORIENTATION (BUTTON_REW | BUTTON_REPEAT) |
| #define OSCILLOSCOPE_PAUSE BUTTON_PLAY |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT |
| #define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_UP |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_DOWN |
| |
| #elif CONFIG_KEYPAD == GIGABEAT_S_PAD |
| #define OSCILLOSCOPE_QUIT BUTTON_BACK |
| #define OSCILLOSCOPE_DRAWMODE BUTTON_PREV |
| #define OSCILLOSCOPE_ADVMODE BUTTON_NEXT |
| #define OSCILLOSCOPE_ORIENTATION BUTTON_MENU |
| #define OSCILLOSCOPE_PAUSE BUTTON_PLAY |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT |
| #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN |
| |
| #elif (CONFIG_KEYPAD == MROBE100_PAD) |
| #define OSCILLOSCOPE_QUIT BUTTON_POWER |
| #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT |
| #define OSCILLOSCOPE_ADVMODE BUTTON_MENU |
| #define OSCILLOSCOPE_ORIENTATION BUTTON_PLAY |
| #define OSCILLOSCOPE_PAUSE BUTTON_DISPLAY |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT |
| #define OSCILLOSCOPE_VOL_UP BUTTON_UP |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN |
| |
| #elif CONFIG_KEYPAD == IAUDIO_M3_PAD |
| #define OSCILLOSCOPE_QUIT BUTTON_RC_REC |
| #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_RC_MODE |
| #define OSCILLOSCOPE_DRAWMODE (BUTTON_RC_MODE|BUTTON_REL) |
| #define OSCILLOSCOPE_ADVMODE BUTTON_RC_MENU |
| #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_RC_MODE |
| #define OSCILLOSCOPE_ORIENTATION (BUTTON_RC_MODE|BUTTON_REPEAT) |
| #define OSCILLOSCOPE_PAUSE BUTTON_RC_PLAY |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_RC_FF |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_RC_REW |
| #define OSCILLOSCOPE_VOL_UP BUTTON_RC_VOL_UP |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_RC_VOL_DOWN |
| |
| #elif CONFIG_KEYPAD == COWOND2_PAD |
| #define OSCILLOSCOPE_QUIT BUTTON_POWER |
| #define OSCILLOSCOPE_VOL_UP BUTTON_PLUS |
| #define OSCILLOSCOPE_VOL_DOWN BUTTON_MINUS |
| |
| #else |
| #error No keymap defined! |
| #endif |
| |
| #ifdef HAVE_TOUCHPAD |
| #ifndef OSCILLOSCOPE_QUIT |
| #define OSCILLOSCOPE_QUIT BUTTON_TOPLEFT |
| #endif |
| #ifndef OSCILLOSCOPE_DRAWMODE |
| #define OSCILLOSCOPE_DRAWMODE BUTTON_TOPMIDDLE |
| #endif |
| #ifndef OSCILLOSCOPE_ADVMODE |
| #define OSCILLOSCOPE_ADVMODE BUTTON_BOTTOMMIDDLE |
| #endif |
| #ifndef OSCILLOSCOPE_ORIENTATION |
| #define OSCILLOSCOPE_ORIENTATION BUTTON_BOTTOMLEFT |
| #endif |
| #ifndef OSCILLOSCOPE_PAUSE |
| #define OSCILLOSCOPE_PAUSE BUTTON_CENTER |
| #endif |
| #ifndef OSCILLOSCOPE_SPEED_UP |
| #define OSCILLOSCOPE_SPEED_UP BUTTON_MIDRIGHT |
| #endif |
| #ifndef OSCILLOSCOPE_SPEED_DOWN |
| #define OSCILLOSCOPE_SPEED_DOWN BUTTON_MIDLEFT |
| #endif |
| #ifndef OSCILLOSCOPE_VOL_UP |
| #define OSCILLOSCOPE_VOL_UP BUTTON_TOPRIGHT |
| #endif |
| #ifndef OSCILLOSCOPE_VOL_DOWN |
| #define OSCILLOSCOPE_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 |
| |
| enum { DRAW_FILLED, DRAW_LINE, DRAW_PIXEL, MAX_DRAW }; |
| enum { ADV_SCROLL, ADV_WRAP, MAX_ADV }; |
| enum { OSC_HORIZ, OSC_VERT, MAX_OSC }; |
| |
| #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) rand()%MAX_PEAK |
| #endif |
| |
| /* global variables */ |
| |
| const struct plugin_api* rb; /* global api struct pointer */ |
| |
| /* settings */ |
| struct osc_config { |
| int delay; /* in ticks */ |
| int draw; |
| int advance; |
| int orientation; |
| }; |
| |
| struct osc_config osc_disk = { 2, DRAW_FILLED, ADV_SCROLL, OSC_HORIZ }; |
| struct osc_config osc; /* running config */ |
| |
| static const char cfg_filename[] = "oscilloscope.cfg"; |
| static char *draw_str[3] = { "filled", "line", "pixel" }; |
| static char *advance_str[2] = { "scroll", "wrap" }; |
| static char *orientation_str[2] = { "horizontal", "vertical" }; |
| |
| struct configdata disk_config[] = { |
| { TYPE_INT, 1, 99, &osc_disk.delay, "delay", NULL, NULL }, |
| { TYPE_ENUM, 0, MAX_DRAW, &osc_disk.draw, "draw", draw_str, NULL }, |
| { TYPE_ENUM, 0, MAX_ADV, &osc_disk.advance, "advance", advance_str, NULL }, |
| { TYPE_ENUM, 0, MAX_OSC, &osc_disk.orientation, "orientation", orientation_str, NULL } |
| }; |
| |
| |
| long last_tick = 0; /* time of last drawing */ |
| int last_pos = 0; /* last x or y drawing position. Reset for aspect switch. */ |
| int last_left; /* last channel values */ |
| int last_right; |
| |
| unsigned char message[16]; /* message to display */ |
| bool displaymsg = false; |
| int font_height = 8; |
| |
| /* implementation */ |
| |
| void anim_horizontal(int cur_left, int cur_right) |
| { |
| int cur_x, x; |
| int left, right, dl, dr; |
| long cur_tick = *rb->current_tick; |
| long d = (cur_tick - last_tick) / osc.delay; |
| bool full_update = false; |
| |
| if (d == 0) /* too early, bail out */ |
| return; |
| |
| last_tick = cur_tick; |
| |
| if (d > HZ) /* first call or too much delay, (re)start */ |
| { |
| last_left = cur_left; |
| last_right = cur_right; |
| return; |
| } |
| cur_x = last_pos + d; |
| |
| if (cur_x >= LCD_WIDTH) |
| { |
| if (osc.advance == ADV_SCROLL) |
| { |
| int shift = cur_x - (LCD_WIDTH-1); |
| xlcd_scroll_left(shift); |
| full_update = true; |
| cur_x -= shift; |
| last_pos -= shift; |
| } |
| else |
| { |
| cur_x -= LCD_WIDTH; |
| } |
| } |
| rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); |
| |
| if (cur_x > last_pos) |
| { |
| rb->lcd_fillrect(last_pos + 1, 0, d, LCD_HEIGHT); |
| } |
| else |
| { |
| rb->lcd_fillrect(last_pos + 1, 0, LCD_WIDTH - last_pos, LCD_HEIGHT); |
| rb->lcd_fillrect(0, 0, cur_x + 1, LCD_HEIGHT); |
| } |
| rb->lcd_set_drawmode(DRMODE_SOLID); |
| |
| switch (osc.draw) |
| { |
| case DRAW_FILLED: |
| left = last_left; |
| right = last_right; |
| dl = (cur_left - left) / d; |
| dr = (cur_right - right) / d; |
| |
| for (x = last_pos + 1; d > 0; x++, d--) |
| { |
| if (x == LCD_WIDTH) |
| x = 0; |
| |
| left += dl; |
| right += dr; |
| |
| rb->lcd_vline(x, LCD_HEIGHT/2-1, |
| LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16)); |
| rb->lcd_vline(x, LCD_HEIGHT/2+1, |
| LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16)); |
| } |
| break; |
| |
| case DRAW_LINE: |
| if (cur_x > last_pos) |
| { |
| rb->lcd_drawline( |
| last_pos, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * last_left) >> 16), |
| cur_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * cur_left) >> 16) |
| ); |
| rb->lcd_drawline( |
| last_pos, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * last_right) >> 16), |
| cur_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * cur_right) >> 16) |
| ); |
| } |
| else |
| { |
| left = last_left |
| + (LCD_WIDTH - last_pos) * (last_left - cur_left) / d; |
| right = last_right |
| + (LCD_WIDTH - last_pos) * (last_right - cur_right) / d; |
| |
| rb->lcd_drawline( |
| last_pos, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * last_left) >> 16), |
| LCD_WIDTH, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16) |
| ); |
| rb->lcd_drawline( |
| last_pos, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * last_right) >> 16), |
| LCD_WIDTH, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16) |
| ); |
| if (cur_x > 0) |
| { |
| rb->lcd_drawline( |
| 0, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16), |
| cur_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * cur_left) >> 16) |
| ); |
| rb->lcd_drawline( |
| 0, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16), |
| cur_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * cur_right) >> 16) |
| ); |
| } |
| } |
| break; |
| |
| case DRAW_PIXEL: |
| left = last_left; |
| right = last_right; |
| dl = (cur_left - left) / d; |
| dr = (cur_right - right) / d; |
| |
| for (x = last_pos + 1; d > 0; x++, d--) |
| { |
| if (x == LCD_WIDTH) |
| x = 0; |
| |
| left += dl; |
| right += dr; |
| |
| rb->lcd_drawpixel(x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16)); |
| rb->lcd_drawpixel(x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16)); |
| } |
| break; |
| |
| } |
| last_left = cur_left; |
| last_right = cur_right; |
| |
| if (displaymsg) |
| { |
| int width; |
| |
| rb->lcd_getstringsize(message, &width, NULL); |
| last_pos -= width - 1; |
| rb->lcd_putsxy(last_pos, 0, message); |
| displaymsg = false; |
| |
| if (last_pos < 0) |
| last_pos = 0; |
| } |
| |
| if (full_update) |
| { |
| rb->lcd_update(); |
| } |
| else |
| { |
| #if LCD_DEPTH > 1 /* cursor bar */ |
| rb->lcd_set_foreground(CURSOR_COLOR); |
| rb->lcd_vline(cur_x + 1, 0, LCD_HEIGHT-1); |
| rb->lcd_set_foreground(GRAPH_COLOR); |
| #else |
| rb->lcd_set_drawmode(DRMODE_COMPLEMENT); |
| rb->lcd_vline(cur_x + 1, 0, LCD_HEIGHT-1); |
| rb->lcd_set_drawmode(DRMODE_SOLID); |
| #endif |
| |
| if (cur_x > last_pos) |
| { |
| rb->lcd_update_rect(last_pos, 0, cur_x - last_pos + 2, LCD_HEIGHT); |
| } |
| else |
| { |
| rb->lcd_update_rect(last_pos, 0, LCD_WIDTH - last_pos, LCD_HEIGHT); |
| rb->lcd_update_rect(0, 0, cur_x + 2, LCD_HEIGHT); |
| } |
| } |
| last_pos = cur_x; |
| } |
| |
| void anim_vertical(int cur_left, int cur_right) |
| { |
| int cur_y, y; |
| int left, right, dl, dr; |
| long cur_tick = *rb->current_tick; |
| long d = (cur_tick - last_tick) / osc.delay; |
| bool full_update = false; |
| |
| if (d == 0) /* too early, bail out */ |
| return; |
| |
| last_tick = cur_tick; |
| |
| if (d > HZ) /* first call or too much delay, (re)start */ |
| { |
| last_left = cur_left; |
| last_right = cur_right; |
| return; |
| } |
| cur_y = last_pos + d; |
| |
| if (cur_y >= LCD_HEIGHT) |
| { |
| if (osc.advance == ADV_SCROLL) |
| { |
| int shift = cur_y - (LCD_HEIGHT-1); |
| xlcd_scroll_up(shift); |
| full_update = true; |
| cur_y -= shift; |
| last_pos -= shift; |
| } |
| else |
| { |
| cur_y -= LCD_HEIGHT; |
| } |
| } |
| rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); |
| |
| if (cur_y > last_pos) |
| { |
| rb->lcd_fillrect(0, last_pos + 1, LCD_WIDTH, d); |
| } |
| else |
| { |
| rb->lcd_fillrect(0, last_pos + 1, LCD_WIDTH, LCD_HEIGHT - last_pos); |
| rb->lcd_fillrect(0, 0, LCD_WIDTH, cur_y + 1); |
| } |
| rb->lcd_set_drawmode(DRMODE_SOLID); |
| |
| switch (osc.draw) |
| { |
| case DRAW_FILLED: |
| left = last_left; |
| right = last_right; |
| dl = (cur_left - left) / d; |
| dr = (cur_right - right) / d; |
| |
| for (y = last_pos + 1; d > 0; y++, d--) |
| { |
| if (y == LCD_HEIGHT) |
| y = 0; |
| |
| left += dl; |
| right += dr; |
| |
| rb->lcd_hline(LCD_WIDTH/2-1, |
| LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), y); |
| rb->lcd_hline(LCD_WIDTH/2+1, |
| LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), y); |
| } |
| break; |
| |
| case DRAW_LINE: |
| if (cur_y > last_pos) |
| { |
| rb->lcd_drawline( |
| LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * last_left) >> 16), last_pos, |
| LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * cur_left) >> 16), cur_y |
| ); |
| rb->lcd_drawline( |
| LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * last_right) >> 16), last_pos, |
| LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * cur_right) >> 16), cur_y |
| ); |
| } |
| else |
| { |
| left = last_left |
| + (LCD_HEIGHT - last_pos) * (last_left - cur_left) / d; |
| right = last_right |
| + (LCD_HEIGHT - last_pos) * (last_right - cur_right) / d; |
| |
| rb->lcd_drawline( |
| LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * last_left) >> 16), last_pos, |
| LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), LCD_HEIGHT |
| ); |
| rb->lcd_drawline( |
| LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * last_right) >> 16), last_pos, |
| LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), LCD_HEIGHT |
| ); |
| if (cur_y > 0) |
| { |
| rb->lcd_drawline( |
| LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), 0, |
| LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * cur_left) >> 16), cur_y |
| ); |
| rb->lcd_drawline( |
| LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), 0, |
| LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * cur_right) >> 16), cur_y |
| ); |
| } |
| } |
| break; |
| |
| case DRAW_PIXEL: |
| left = last_left; |
| right = last_right; |
| dl = (cur_left - left) / d; |
| dr = (cur_right - right) / d; |
| |
| for (y = last_pos + 1; d > 0; y++, d--) |
| { |
| if (y == LCD_HEIGHT) |
| y = 0; |
| |
| left += dl; |
| right += dr; |
| |
| rb->lcd_drawpixel(LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), y); |
| rb->lcd_drawpixel(LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), y); |
| } |
| break; |
| |
| } |
| last_left = cur_left; |
| last_right = cur_right; |
| |
| if (displaymsg) |
| { |
| last_pos -= font_height - 1; |
| rb->lcd_putsxy(0, last_pos, message); |
| displaymsg = false; |
| |
| if (last_pos < 0) |
| last_pos = 0; |
| } |
| |
| if (full_update) |
| { |
| rb->lcd_update(); |
| } |
| else |
| { |
| #if LCD_DEPTH > 1 /* cursor bar */ |
| rb->lcd_set_foreground(CURSOR_COLOR); |
| rb->lcd_hline(0, LCD_WIDTH-1, cur_y + 1); |
| rb->lcd_set_foreground(GRAPH_COLOR); |
| #else |
| rb->lcd_set_drawmode(DRMODE_COMPLEMENT); |
| rb->lcd_hline(0, LCD_WIDTH-1, cur_y + 1); |
| rb->lcd_set_drawmode(DRMODE_SOLID); |
| #endif |
| |
| if (cur_y > last_pos) |
| { |
| rb->lcd_update_rect(0, last_pos, LCD_WIDTH, cur_y - last_pos + 2); |
| } |
| else |
| { |
| rb->lcd_update_rect(0, last_pos, LCD_WIDTH, LCD_HEIGHT - last_pos); |
| rb->lcd_update_rect(0, 0, LCD_WIDTH, cur_y + 2); |
| } |
| } |
| last_pos = cur_y; |
| } |
| |
| 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(rb); /* backlight control in lib/helper.c */ |
| } |
| |
| enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter) |
| { |
| int button, vol; |
| int lastbutton = BUTTON_NONE; |
| bool exit = false; |
| bool paused = false; |
| bool tell_speed; |
| |
| (void)parameter; |
| rb = api; |
| |
| xlcd_init(rb); |
| configfile_init(rb); |
| |
| configfile_load(cfg_filename, disk_config, |
| sizeof(disk_config) / sizeof(disk_config[0]), |
| CFGFILE_MINVERSION); |
| rb->memcpy(&osc, &osc_disk, sizeof(osc)); /* 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 |
| |
| /* Turn off backlight timeout */ |
| backlight_force_on(rb); /* backlight control in lib/helper.c */ |
| |
| rb->lcd_getstringsize("A", NULL, &font_height); |
| |
| while (!exit) |
| { |
| if (!paused) |
| { |
| int left, right; |
| |
| rb->sleep(MAX(last_tick + osc.delay - *rb->current_tick - 1, 0)); |
| |
| #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) |
| left = rb->mas_codec_readreg(0xC); |
| right = rb->mas_codec_readreg(0xD); |
| #elif (CONFIG_CODEC == SWCODEC) |
| rb->pcm_calculate_peaks(&left, &right); |
| #endif |
| if (osc.orientation == OSC_HORIZ) |
| anim_horizontal(left, right); |
| else |
| anim_vertical(left, right); |
| } |
| |
| tell_speed = false; |
| button = rb->button_get(paused); |
| switch (button) |
| { |
| #ifdef OSCILLOSCOPE_RC_QUIT |
| case OSCILLOSCOPE_RC_QUIT: |
| #endif |
| case OSCILLOSCOPE_QUIT: |
| exit = true; |
| break; |
| |
| case OSCILLOSCOPE_ADVMODE: |
| if (++osc.advance >= MAX_ADV) |
| osc.advance = 0; |
| break; |
| |
| case OSCILLOSCOPE_DRAWMODE: |
| #ifdef OSCILLOSCOPE_DRAWMODE_PRE |
| if (lastbutton != OSCILLOSCOPE_DRAWMODE_PRE) |
| break; |
| #endif |
| if (++osc.draw >= MAX_DRAW) |
| osc.draw = 0; |
| break; |
| |
| case OSCILLOSCOPE_ORIENTATION: |
| #ifdef OSCILLOSCOPE_ORIENTATION_PRE |
| if (lastbutton != OSCILLOSCOPE_ORIENTATION_PRE) |
| break; |
| #endif |
| if (++osc.orientation >= MAX_OSC) |
| osc.orientation = 0; |
| last_pos = 0; |
| last_tick = 0; |
| displaymsg = false; |
| rb->lcd_clear_display(); |
| rb->lcd_update(); |
| break; |
| |
| case OSCILLOSCOPE_PAUSE: |
| paused = !paused; |
| last_tick = 0; |
| break; |
| |
| case OSCILLOSCOPE_SPEED_UP: |
| case OSCILLOSCOPE_SPEED_UP | BUTTON_REPEAT: |
| if (osc.delay > 1) |
| { |
| osc.delay--; |
| tell_speed = true; |
| } |
| break; |
| |
| case OSCILLOSCOPE_SPEED_DOWN: |
| case OSCILLOSCOPE_SPEED_DOWN | BUTTON_REPEAT: |
| osc.delay++; |
| tell_speed = true; |
| break; |
| |
| case OSCILLOSCOPE_VOL_UP: |
| case OSCILLOSCOPE_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 OSCILLOSCOPE_VOL_DOWN: |
| case OSCILLOSCOPE_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", |
| (osc.orientation == OSC_VERT) ? "Speed: " : "", |
| 100 / osc.delay); |
| displaymsg = true; |
| } |
| } |
| cleanup(NULL); |
| if (rb->memcmp(&osc, &osc_disk, sizeof(osc))) /* save settings if changed */ |
| { |
| rb->memcpy(&osc_disk, &osc, sizeof(osc)); |
| configfile_save(cfg_filename, disk_config, |
| sizeof(disk_config) / sizeof(disk_config[0]), |
| CFGFILE_VERSION); |
| } |
| return PLUGIN_OK; |
| } |
| #endif /* HAVE_LCD_BITMAP */ |