rockbox/apps/plugins/oscilloscope.c
Daniel Stenberg 2acc0ac542 Updated our source code header to explicitly mention that we are GPL v2 or
later. We still need to hunt down snippets used that are not. 1324 modified
files...
http://www.rockbox.org/mail/archive/rockbox-dev-archive-2008-06/0060.shtml


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17847 a1c6a512-1295-4272-9138-f99709370657
2008-06-28 18:10:04 +00:00

815 lines
26 KiB
C

/***************************************************************************
* __________ __ ___.
* 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 */