Fix some quotation marks. Thanks to Alexander Levin for pointing it out.
[Rockbox.git] / apps / plugins / oscilloscope.c
blobd576c81d881a428c1cdb68f4127012f430d42502
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Oscilloscope, with many different modes of operation.
12 * Copyright (C) 2004-2006 Jens Arnold
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "plugin.h"
23 #include "helper.h"
25 #ifdef HAVE_LCD_BITMAP
26 #include "xlcd.h"
27 #include "configfile.h"
29 PLUGIN_HEADER
31 /* variable button definitions */
32 #if CONFIG_KEYPAD == RECORDER_PAD
33 #define OSCILLOSCOPE_QUIT BUTTON_OFF
34 #define OSCILLOSCOPE_DRAWMODE BUTTON_F1
35 #define OSCILLOSCOPE_ADVMODE BUTTON_F2
36 #define OSCILLOSCOPE_ORIENTATION BUTTON_F3
37 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
38 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
39 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
40 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
41 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
43 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
44 #define OSCILLOSCOPE_QUIT BUTTON_OFF
45 #define OSCILLOSCOPE_DRAWMODE BUTTON_F1
46 #define OSCILLOSCOPE_ADVMODE BUTTON_F2
47 #define OSCILLOSCOPE_ORIENTATION BUTTON_F3
48 #define OSCILLOSCOPE_PAUSE BUTTON_SELECT
49 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
50 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
51 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
52 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
54 #elif CONFIG_KEYPAD == ONDIO_PAD
55 #define OSCILLOSCOPE_QUIT BUTTON_OFF
56 #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_MENU
57 #define OSCILLOSCOPE_DRAWMODE (BUTTON_MENU | BUTTON_REL)
58 #define OSCILLOSCOPE_ADVMODE (BUTTON_MENU | BUTTON_RIGHT)
59 #define OSCILLOSCOPE_ORIENTATION (BUTTON_MENU | BUTTON_LEFT)
60 #define OSCILLOSCOPE_PAUSE (BUTTON_MENU | BUTTON_OFF)
61 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
62 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
63 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
64 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
66 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
67 #define OSCILLOSCOPE_QUIT BUTTON_OFF
68 #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
69 #define OSCILLOSCOPE_ADVMODE BUTTON_MODE
70 #define OSCILLOSCOPE_ORIENTATION BUTTON_REC
71 #define OSCILLOSCOPE_PAUSE BUTTON_ON
72 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
73 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
74 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
75 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
76 #define OSCILLOSCOPE_RC_QUIT BUTTON_RC_STOP
78 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
79 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
80 #define OSCILLOSCOPE_QUIT (BUTTON_SELECT | BUTTON_MENU)
81 #define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_PLAY)
82 #define OSCILLOSCOPE_ADVMODE (BUTTON_SELECT | BUTTON_RIGHT)
83 #define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_LEFT)
84 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
85 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
86 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
87 #define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD
88 #define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK
90 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
91 #define OSCILLOSCOPE_QUIT BUTTON_POWER
92 #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
93 #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
94 #define OSCILLOSCOPE_ORIENTATION BUTTON_UP
95 #define OSCILLOSCOPE_PAUSE BUTTON_A
96 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
97 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
98 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
99 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
101 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
102 #define OSCILLOSCOPE_QUIT BUTTON_POWER
103 #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
104 #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
105 #define OSCILLOSCOPE_ORIENTATION BUTTON_UP
106 #define OSCILLOSCOPE_PAUSE BUTTON_REC
107 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
108 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
109 #define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD
110 #define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK
112 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
113 #define OSCILLOSCOPE_QUIT BUTTON_POWER
114 #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
115 #define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
116 #define OSCILLOSCOPE_ORIENTATION BUTTON_UP
117 #define OSCILLOSCOPE_PAUSE BUTTON_REC
118 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
119 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
120 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
121 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
123 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
124 #define OSCILLOSCOPE_QUIT BUTTON_POWER
125 #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
126 #define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
127 #define OSCILLOSCOPE_ADVMODE BUTTON_REC
128 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT
129 #define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT)
130 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
131 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
132 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
133 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
134 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
136 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
137 #define OSCILLOSCOPE_QUIT BUTTON_POWER
138 #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_REW
139 #define OSCILLOSCOPE_DRAWMODE (BUTTON_REW | BUTTON_REL)
140 #define OSCILLOSCOPE_ADVMODE BUTTON_FF
141 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_REW
142 #define OSCILLOSCOPE_ORIENTATION (BUTTON_REW | BUTTON_REPEAT)
143 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
144 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
145 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
146 #define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_UP
147 #define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_DOWN
149 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
150 #define OSCILLOSCOPE_QUIT BUTTON_BACK
151 #define OSCILLOSCOPE_DRAWMODE BUTTON_PREV
152 #define OSCILLOSCOPE_ADVMODE BUTTON_NEXT
153 #define OSCILLOSCOPE_ORIENTATION BUTTON_MENU
154 #define OSCILLOSCOPE_PAUSE BUTTON_PLAY
155 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
156 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
157 #define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
158 #define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
160 #elif (CONFIG_KEYPAD == MROBE100_PAD)
161 #define OSCILLOSCOPE_QUIT BUTTON_POWER
162 #define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
163 #define OSCILLOSCOPE_ADVMODE BUTTON_MENU
164 #define OSCILLOSCOPE_ORIENTATION BUTTON_PLAY
165 #define OSCILLOSCOPE_PAUSE BUTTON_DISPLAY
166 #define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
167 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
168 #define OSCILLOSCOPE_VOL_UP BUTTON_UP
169 #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
171 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
172 #define OSCILLOSCOPE_QUIT BUTTON_RC_REC
173 #define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_RC_MODE
174 #define OSCILLOSCOPE_DRAWMODE (BUTTON_RC_MODE|BUTTON_REL)
175 #define OSCILLOSCOPE_ADVMODE BUTTON_RC_MENU
176 #define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_RC_MODE
177 #define OSCILLOSCOPE_ORIENTATION (BUTTON_RC_MODE|BUTTON_REPEAT)
178 #define OSCILLOSCOPE_PAUSE BUTTON_RC_PLAY
179 #define OSCILLOSCOPE_SPEED_UP BUTTON_RC_FF
180 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_RC_REW
181 #define OSCILLOSCOPE_VOL_UP BUTTON_RC_VOL_UP
182 #define OSCILLOSCOPE_VOL_DOWN BUTTON_RC_VOL_DOWN
184 #elif CONFIG_KEYPAD == COWOND2_PAD
185 #define OSCILLOSCOPE_QUIT BUTTON_POWER
186 #define OSCILLOSCOPE_DRAWMODE_PRE (BUTTON_LEFT | BUTTON_MENU)
187 #define OSCILLOSCOPE_DRAWMODE (BUTTON_RIGHT | BUTTON_MENU)
188 #define OSCILLOSCOPE_ADVMODE (BUTTON_SELECT|BUTTON_MENU)
189 #define OSCILLOSCOPE_ORIENTATION_PRE (BUTTON_UP | BUTTON_MENU)
190 #define OSCILLOSCOPE_ORIENTATION (BUTTON_DOWN | BUTTON_MENU)
191 #define OSCILLOSCOPE_PAUSE BUTTON_SELECT
192 #define OSCILLOSCOPE_SPEED_UP BUTTON_UP
193 #define OSCILLOSCOPE_SPEED_DOWN BUTTON_DOWN
194 #define OSCILLOSCOPE_VOL_UP BUTTON_PLUS
195 #define OSCILLOSCOPE_VOL_DOWN BUTTON_MINUS
197 #else
198 #error No keymap defined!
199 #endif
201 /* colours */
202 #if LCD_DEPTH > 1
203 #ifdef HAVE_LCD_COLOR
204 #define BACKG_COLOR LCD_BLACK
205 #define GRAPH_COLOR LCD_RGBPACK(128, 255, 0)
206 #define CURSOR_COLOR LCD_RGBPACK(255, 0, 0)
207 #else
208 #define BACKG_COLOR LCD_WHITE
209 #define GRAPH_COLOR LCD_BLACK
210 #define CURSOR_COLOR LCD_DARKGRAY
211 #endif
212 #endif
214 enum { DRAW_FILLED, DRAW_LINE, DRAW_PIXEL, MAX_DRAW };
215 enum { ADV_SCROLL, ADV_WRAP, MAX_ADV };
216 enum { OSC_HORIZ, OSC_VERT, MAX_OSC };
218 #define CFGFILE_VERSION 0 /* Current config file version */
219 #define CFGFILE_MINVERSION 0 /* Minimum config file version to accept */
222 #define MAX_PEAK 0x8000
224 #if defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
225 #define mas_codec_readreg(x) rand()%MAX_PEAK
226 #endif
228 /* global variables */
230 struct plugin_api* rb; /* global api struct pointer */
232 /* settings */
233 struct osc_config {
234 int delay; /* in ticks */
235 int draw;
236 int advance;
237 int orientation;
240 struct osc_config osc_disk = { 2, DRAW_FILLED, ADV_SCROLL, OSC_HORIZ };
241 struct osc_config osc; /* running config */
243 static const char cfg_filename[] = "oscilloscope.cfg";
244 static char *draw_str[3] = { "filled", "line", "pixel" };
245 static char *advance_str[2] = { "scroll", "wrap" };
246 static char *orientation_str[2] = { "horizontal", "vertical" };
248 struct configdata disk_config[] = {
249 { TYPE_INT, 1, 99, &osc_disk.delay, "delay", NULL, NULL },
250 { TYPE_ENUM, 0, MAX_DRAW, &osc_disk.draw, "draw", draw_str, NULL },
251 { TYPE_ENUM, 0, MAX_ADV, &osc_disk.advance, "advance", advance_str, NULL },
252 { TYPE_ENUM, 0, MAX_OSC, &osc_disk.orientation, "orientation", orientation_str, NULL }
256 long last_tick = 0; /* time of last drawing */
257 int last_pos = 0; /* last x or y drawing position. Reset for aspect switch. */
258 int last_left; /* last channel values */
259 int last_right;
261 unsigned char message[16]; /* message to display */
262 bool displaymsg = false;
263 int font_height = 8;
265 /* implementation */
267 void anim_horizontal(int cur_left, int cur_right)
269 int cur_x, x;
270 int left, right, dl, dr;
271 long cur_tick = *rb->current_tick;
272 long d = (cur_tick - last_tick) / osc.delay;
273 bool full_update = false;
275 if (d == 0) /* too early, bail out */
276 return;
278 last_tick = cur_tick;
280 if (d > HZ) /* first call or too much delay, (re)start */
282 last_left = cur_left;
283 last_right = cur_right;
284 return;
286 cur_x = last_pos + d;
288 if (cur_x >= LCD_WIDTH)
290 if (osc.advance == ADV_SCROLL)
292 int shift = cur_x - (LCD_WIDTH-1);
293 xlcd_scroll_left(shift);
294 full_update = true;
295 cur_x -= shift;
296 last_pos -= shift;
298 else
300 cur_x -= LCD_WIDTH;
303 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
305 if (cur_x > last_pos)
307 rb->lcd_fillrect(last_pos + 1, 0, d, LCD_HEIGHT);
309 else
311 rb->lcd_fillrect(last_pos + 1, 0, LCD_WIDTH - last_pos, LCD_HEIGHT);
312 rb->lcd_fillrect(0, 0, cur_x + 1, LCD_HEIGHT);
314 rb->lcd_set_drawmode(DRMODE_SOLID);
316 switch (osc.draw)
318 case DRAW_FILLED:
319 left = last_left;
320 right = last_right;
321 dl = (cur_left - left) / d;
322 dr = (cur_right - right) / d;
324 for (x = last_pos + 1; d > 0; x++, d--)
326 if (x == LCD_WIDTH)
327 x = 0;
329 left += dl;
330 right += dr;
332 rb->lcd_vline(x, LCD_HEIGHT/2-1,
333 LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16));
334 rb->lcd_vline(x, LCD_HEIGHT/2+1,
335 LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16));
337 break;
339 case DRAW_LINE:
340 if (cur_x > last_pos)
342 rb->lcd_drawline(
343 last_pos, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * last_left) >> 16),
344 cur_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * cur_left) >> 16)
346 rb->lcd_drawline(
347 last_pos, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * last_right) >> 16),
348 cur_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * cur_right) >> 16)
351 else
353 left = last_left
354 + (LCD_WIDTH - last_pos) * (last_left - cur_left) / d;
355 right = last_right
356 + (LCD_WIDTH - last_pos) * (last_right - cur_right) / d;
358 rb->lcd_drawline(
359 last_pos, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * last_left) >> 16),
360 LCD_WIDTH, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16)
362 rb->lcd_drawline(
363 last_pos, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * last_right) >> 16),
364 LCD_WIDTH, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16)
366 if (cur_x > 0)
368 rb->lcd_drawline(
369 0, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16),
370 cur_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * cur_left) >> 16)
372 rb->lcd_drawline(
373 0, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16),
374 cur_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * cur_right) >> 16)
378 break;
380 case DRAW_PIXEL:
381 left = last_left;
382 right = last_right;
383 dl = (cur_left - left) / d;
384 dr = (cur_right - right) / d;
386 for (x = last_pos + 1; d > 0; x++, d--)
388 if (x == LCD_WIDTH)
389 x = 0;
391 left += dl;
392 right += dr;
394 rb->lcd_drawpixel(x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16));
395 rb->lcd_drawpixel(x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16));
397 break;
400 last_left = cur_left;
401 last_right = cur_right;
403 if (displaymsg)
405 int width;
407 rb->lcd_getstringsize(message, &width, NULL);
408 last_pos -= width - 1;
409 rb->lcd_putsxy(last_pos, 0, message);
410 displaymsg = false;
412 if (last_pos < 0)
413 last_pos = 0;
416 if (full_update)
418 rb->lcd_update();
420 else
422 #if LCD_DEPTH > 1 /* cursor bar */
423 rb->lcd_set_foreground(CURSOR_COLOR);
424 rb->lcd_vline(cur_x + 1, 0, LCD_HEIGHT-1);
425 rb->lcd_set_foreground(GRAPH_COLOR);
426 #else
427 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
428 rb->lcd_vline(cur_x + 1, 0, LCD_HEIGHT-1);
429 rb->lcd_set_drawmode(DRMODE_SOLID);
430 #endif
432 if (cur_x > last_pos)
434 rb->lcd_update_rect(last_pos, 0, cur_x - last_pos + 2, LCD_HEIGHT);
436 else
438 rb->lcd_update_rect(last_pos, 0, LCD_WIDTH - last_pos, LCD_HEIGHT);
439 rb->lcd_update_rect(0, 0, cur_x + 2, LCD_HEIGHT);
442 last_pos = cur_x;
445 void anim_vertical(int cur_left, int cur_right)
447 int cur_y, y;
448 int left, right, dl, dr;
449 long cur_tick = *rb->current_tick;
450 long d = (cur_tick - last_tick) / osc.delay;
451 bool full_update = false;
453 if (d == 0) /* too early, bail out */
454 return;
456 last_tick = cur_tick;
458 if (d > HZ) /* first call or too much delay, (re)start */
460 last_left = cur_left;
461 last_right = cur_right;
462 return;
464 cur_y = last_pos + d;
466 if (cur_y >= LCD_HEIGHT)
468 if (osc.advance == ADV_SCROLL)
470 int shift = cur_y - (LCD_HEIGHT-1);
471 xlcd_scroll_up(shift);
472 full_update = true;
473 cur_y -= shift;
474 last_pos -= shift;
476 else
478 cur_y -= LCD_HEIGHT;
481 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
483 if (cur_y > last_pos)
485 rb->lcd_fillrect(0, last_pos + 1, LCD_WIDTH, d);
487 else
489 rb->lcd_fillrect(0, last_pos + 1, LCD_WIDTH, LCD_HEIGHT - last_pos);
490 rb->lcd_fillrect(0, 0, LCD_WIDTH, cur_y + 1);
492 rb->lcd_set_drawmode(DRMODE_SOLID);
494 switch (osc.draw)
496 case DRAW_FILLED:
497 left = last_left;
498 right = last_right;
499 dl = (cur_left - left) / d;
500 dr = (cur_right - right) / d;
502 for (y = last_pos + 1; d > 0; y++, d--)
504 if (y == LCD_HEIGHT)
505 y = 0;
507 left += dl;
508 right += dr;
510 rb->lcd_hline(LCD_WIDTH/2-1,
511 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), y);
512 rb->lcd_hline(LCD_WIDTH/2+1,
513 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), y);
515 break;
517 case DRAW_LINE:
518 if (cur_y > last_pos)
520 rb->lcd_drawline(
521 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * last_left) >> 16), last_pos,
522 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * cur_left) >> 16), cur_y
524 rb->lcd_drawline(
525 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * last_right) >> 16), last_pos,
526 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * cur_right) >> 16), cur_y
529 else
531 left = last_left
532 + (LCD_HEIGHT - last_pos) * (last_left - cur_left) / d;
533 right = last_right
534 + (LCD_HEIGHT - last_pos) * (last_right - cur_right) / d;
536 rb->lcd_drawline(
537 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * last_left) >> 16), last_pos,
538 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), LCD_HEIGHT
540 rb->lcd_drawline(
541 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * last_right) >> 16), last_pos,
542 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), LCD_HEIGHT
544 if (cur_y > 0)
546 rb->lcd_drawline(
547 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), 0,
548 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * cur_left) >> 16), cur_y
550 rb->lcd_drawline(
551 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), 0,
552 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * cur_right) >> 16), cur_y
556 break;
558 case DRAW_PIXEL:
559 left = last_left;
560 right = last_right;
561 dl = (cur_left - left) / d;
562 dr = (cur_right - right) / d;
564 for (y = last_pos + 1; d > 0; y++, d--)
566 if (y == LCD_HEIGHT)
567 y = 0;
569 left += dl;
570 right += dr;
572 rb->lcd_drawpixel(LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), y);
573 rb->lcd_drawpixel(LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), y);
575 break;
578 last_left = cur_left;
579 last_right = cur_right;
581 if (displaymsg)
583 last_pos -= font_height - 1;
584 rb->lcd_putsxy(0, last_pos, message);
585 displaymsg = false;
587 if (last_pos < 0)
588 last_pos = 0;
591 if (full_update)
593 rb->lcd_update();
595 else
597 #if LCD_DEPTH > 1 /* cursor bar */
598 rb->lcd_set_foreground(CURSOR_COLOR);
599 rb->lcd_hline(0, LCD_WIDTH-1, cur_y + 1);
600 rb->lcd_set_foreground(GRAPH_COLOR);
601 #else
602 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
603 rb->lcd_hline(0, LCD_WIDTH-1, cur_y + 1);
604 rb->lcd_set_drawmode(DRMODE_SOLID);
605 #endif
607 if (cur_y > last_pos)
609 rb->lcd_update_rect(0, last_pos, LCD_WIDTH, cur_y - last_pos + 2);
611 else
613 rb->lcd_update_rect(0, last_pos, LCD_WIDTH, LCD_HEIGHT - last_pos);
614 rb->lcd_update_rect(0, 0, LCD_WIDTH, cur_y + 2);
617 last_pos = cur_y;
620 void cleanup(void *parameter)
622 (void)parameter;
623 #if LCD_DEPTH > 1
624 rb->lcd_set_foreground(LCD_DEFAULT_FG);
625 rb->lcd_set_background(LCD_DEFAULT_BG);
626 #endif
627 /* Turn on backlight timeout (revert to settings) */
628 backlight_use_settings(rb); /* backlight control in lib/helper.c */
631 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
633 int button, vol;
634 int lastbutton = BUTTON_NONE;
635 bool exit = false;
636 bool paused = false;
637 bool tell_speed;
639 (void)parameter;
640 rb = api;
642 xlcd_init(rb);
643 configfile_init(rb);
645 configfile_load(cfg_filename, disk_config,
646 sizeof(disk_config) / sizeof(disk_config[0]),
647 CFGFILE_MINVERSION);
648 rb->memcpy(&osc, &osc_disk, sizeof(osc)); /* copy to running config */
650 #if LCD_DEPTH > 1
651 rb->lcd_set_foreground(GRAPH_COLOR);
652 rb->lcd_set_background(BACKG_COLOR);
653 rb->lcd_set_backdrop(NULL);
654 rb->lcd_clear_display();
655 rb->lcd_update();
656 #endif
658 /* Turn off backlight timeout */
659 backlight_force_on(rb); /* backlight control in lib/helper.c */
661 rb->lcd_getstringsize("A", NULL, &font_height);
663 while (!exit)
665 if (!paused)
667 int left, right;
669 rb->sleep(MAX(last_tick + osc.delay - *rb->current_tick - 1, 0));
671 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
672 left = rb->mas_codec_readreg(0xC);
673 right = rb->mas_codec_readreg(0xD);
674 #elif (CONFIG_CODEC == SWCODEC)
675 rb->pcm_calculate_peaks(&left, &right);
676 #endif
677 if (osc.orientation == OSC_HORIZ)
678 anim_horizontal(left, right);
679 else
680 anim_vertical(left, right);
683 tell_speed = false;
684 button = rb->button_get(paused);
685 switch (button)
687 #ifdef OSCILLOSCOPE_RC_QUIT
688 case OSCILLOSCOPE_RC_QUIT:
689 #endif
690 case OSCILLOSCOPE_QUIT:
691 exit = true;
692 break;
694 case OSCILLOSCOPE_ADVMODE:
695 if (++osc.advance >= MAX_ADV)
696 osc.advance = 0;
697 break;
699 case OSCILLOSCOPE_DRAWMODE:
700 #ifdef OSCILLOSCOPE_DRAWMODE_PRE
701 if (lastbutton != OSCILLOSCOPE_DRAWMODE_PRE)
702 break;
703 #endif
704 if (++osc.draw >= MAX_DRAW)
705 osc.draw = 0;
706 break;
708 case OSCILLOSCOPE_ORIENTATION:
709 #ifdef OSCILLOSCOPE_ORIENTATION_PRE
710 if (lastbutton != OSCILLOSCOPE_ORIENTATION_PRE)
711 break;
712 #endif
713 if (++osc.orientation >= MAX_OSC)
714 osc.orientation = 0;
715 last_pos = 0;
716 last_tick = 0;
717 displaymsg = false;
718 rb->lcd_clear_display();
719 rb->lcd_update();
720 break;
722 case OSCILLOSCOPE_PAUSE:
723 paused = !paused;
724 last_tick = 0;
725 break;
727 case OSCILLOSCOPE_SPEED_UP:
728 case OSCILLOSCOPE_SPEED_UP | BUTTON_REPEAT:
729 if (osc.delay > 1)
731 osc.delay--;
732 tell_speed = true;
734 break;
736 case OSCILLOSCOPE_SPEED_DOWN:
737 case OSCILLOSCOPE_SPEED_DOWN | BUTTON_REPEAT:
738 osc.delay++;
739 tell_speed = true;
740 break;
742 case OSCILLOSCOPE_VOL_UP:
743 case OSCILLOSCOPE_VOL_UP | BUTTON_REPEAT:
744 vol = rb->global_settings->volume;
745 if (vol < rb->sound_max(SOUND_VOLUME))
747 vol++;
748 rb->sound_set(SOUND_VOLUME, vol);
749 rb->global_settings->volume = vol;
751 break;
753 case OSCILLOSCOPE_VOL_DOWN:
754 case OSCILLOSCOPE_VOL_DOWN | BUTTON_REPEAT:
755 vol = rb->global_settings->volume;
756 if (vol > rb->sound_min(SOUND_VOLUME))
758 vol--;
759 rb->sound_set(SOUND_VOLUME, vol);
760 rb->global_settings->volume = vol;
762 break;
764 default:
765 if (rb->default_event_handler_ex(button, cleanup, NULL)
766 == SYS_USB_CONNECTED)
767 return PLUGIN_USB_CONNECTED;
768 break;
770 if (button != BUTTON_NONE)
771 lastbutton = button;
773 if (tell_speed)
775 rb->snprintf(message, sizeof(message), "%s%d",
776 (osc.orientation == OSC_VERT) ? "Speed: " : "",
777 100 / osc.delay);
778 displaymsg = true;
781 cleanup(NULL);
782 if (rb->memcmp(&osc, &osc_disk, sizeof(osc))) /* save settings if changed */
784 rb->memcpy(&osc_disk, &osc, sizeof(osc));
785 configfile_save(cfg_filename, disk_config,
786 sizeof(disk_config) / sizeof(disk_config[0]),
787 CFGFILE_VERSION);
789 return PLUGIN_OK;
791 #endif /* HAVE_LCD_BITMAP */