blob: 4d807493d304c56998f8da0dad6b8cf4b9d0a82f [file] [log] [blame]
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
Jens Arnoldf9765d32006-03-11 01:13:51 +000010* Oscilloscope, with many different modes of operation.
Jens Arnolddb14d8e2004-11-07 10:31:39 +000011*
Jens Arnoldb318b3e2006-03-09 07:52:26 +000012* Copyright (C) 2004-2006 Jens Arnold
Jens Arnolddb14d8e2004-11-07 10:31:39 +000013*
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000014* This program is free software; you can redistribute it and/or
15* modify it under the terms of the GNU General Public License
16* as published by the Free Software Foundation; either version 2
17* of the License, or (at your option) any later version.
Jens Arnolddb14d8e2004-11-07 10:31:39 +000018*
19* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20* KIND, either express or implied.
21*
22****************************************************************************/
23
Jens Arnolddb14d8e2004-11-07 10:31:39 +000024#include "plugin.h"
Michael Sevakis95e23de2013-04-16 17:47:58 -040025#include "fixedpoint.h"
Björn Stenbergc6b3d382008-11-20 11:27:31 +000026#include "lib/helper.h"
Thomas Martitzcae4ae22010-08-24 14:30:46 +000027#include "lib/pluginlib_exit.h"
Björn Stenbergc6b3d382008-11-20 11:27:31 +000028#include "lib/xlcd.h"
29#include "lib/configfile.h"
Michael Sevakis0f8aedb2012-12-02 01:09:44 -050030#include "lib/osd.h"
Jens Arnolda36b1d42006-01-15 18:20:18 +000031
Jens Arnolddb14d8e2004-11-07 10:31:39 +000032/* variable button definitions */
33#if CONFIG_KEYPAD == RECORDER_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -050034#define OSCILLOSCOPE_QUIT BUTTON_OFF
35#define OSCILLOSCOPE_DRAWMODE BUTTON_F1
36#define OSCILLOSCOPE_ADVMODE BUTTON_F2
37#define OSCILLOSCOPE_ORIENTATION BUTTON_F3
38#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
39#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
40#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
41#define OSCILLOSCOPE_VOL_UP BUTTON_UP
42#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
Jens Arnolddb14d8e2004-11-07 10:31:39 +000043
Dave Chapmand64e6262007-01-14 13:48:09 +000044#elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -050045#define OSCILLOSCOPE_QUIT BUTTON_OFF
46#define OSCILLOSCOPE_DRAWMODE BUTTON_F1
47#define OSCILLOSCOPE_ADVMODE BUTTON_F2
48#define OSCILLOSCOPE_ORIENTATION BUTTON_F3
49#define OSCILLOSCOPE_PAUSE BUTTON_SELECT
50#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
51#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
52#define OSCILLOSCOPE_VOL_UP BUTTON_UP
53#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
Dave Chapmand64e6262007-01-14 13:48:09 +000054
Jens Arnolddb14d8e2004-11-07 10:31:39 +000055#elif CONFIG_KEYPAD == ONDIO_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -050056#define OSCILLOSCOPE_QUIT BUTTON_OFF
57#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_MENU
58#define OSCILLOSCOPE_DRAWMODE (BUTTON_MENU | BUTTON_REL)
59#define OSCILLOSCOPE_ADVMODE (BUTTON_MENU | BUTTON_RIGHT)
60#define OSCILLOSCOPE_ORIENTATION (BUTTON_MENU | BUTTON_LEFT)
61#define OSCILLOSCOPE_PAUSE (BUTTON_MENU | BUTTON_OFF)
62#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
63#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
64#define OSCILLOSCOPE_VOL_UP BUTTON_UP
65#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
66#define NEED_LASTBUTTON
Jens Arnoldb318b3e2006-03-09 07:52:26 +000067
68#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -050069#define OSCILLOSCOPE_QUIT BUTTON_OFF
70#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
71#define OSCILLOSCOPE_ADVMODE BUTTON_MODE
72#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_REC
73#define OSCILLOSCOPE_ORIENTATION (BUTTON_REC | BUTTON_REL)
74#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_REC
75#define OSCILLOSCOPE_GRAPHMODE (BUTTON_REC | BUTTON_REPEAT)
76#define OSCILLOSCOPE_PAUSE BUTTON_ON
77#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
78#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
79#define OSCILLOSCOPE_VOL_UP BUTTON_UP
80#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
81#define OSCILLOSCOPE_RC_QUIT BUTTON_RC_STOP
82#define NEED_LASTBUTTON
Jens Arnold61e798f2007-04-09 17:03:48 +000083
Jens Arnoldb7013222007-07-27 09:57:27 +000084#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
85 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -050086#define OSCILLOSCOPE_QUIT (BUTTON_SELECT | BUTTON_MENU)
87#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_PLAY)
88#define OSCILLOSCOPE_ADVMODE (BUTTON_SELECT | BUTTON_RIGHT)
89#define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_LEFT)
90#define OSCILLOSCOPE_GRAPHMODE BUTTON_MENU
91#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
92#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
93#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
94#define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD
95#define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK
96/* Need GRAPHMODE */
Jens Arnoldb318b3e2006-03-09 07:52:26 +000097
98#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -050099#define OSCILLOSCOPE_QUIT BUTTON_POWER
100#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
101#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
102#define OSCILLOSCOPE_ORIENTATION BUTTON_UP
103#define OSCILLOSCOPE_GRAPHMODE BUTTON_MENU
104#define OSCILLOSCOPE_PAUSE BUTTON_A
105#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
106#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
107#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
108#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000109
Barry Wardell24f4a2a2006-10-26 13:38:09 +0000110#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500111#define OSCILLOSCOPE_QUIT BUTTON_POWER
112#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
113#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
114#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT
115#define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT)
116#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
117#define OSCILLOSCOPE_PAUSE_PRE BUTTON_UP
118#define OSCILLOSCOPE_PAUSE (BUTTON_UP | BUTTON_REL)
119#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
120#define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
121#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
122#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
123#define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD
124#define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK
125#define NEED_LASTBUTTON
Barry Wardell24f4a2a2006-10-26 13:38:09 +0000126
Michael Giacomelli6d5823f2009-01-04 23:33:15 +0000127#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500128#define OSCILLOSCOPE_QUIT (BUTTON_HOME|BUTTON_REPEAT)
129#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
130#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
131#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT
132#define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT)
133#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
134#define OSCILLOSCOPE_PAUSE_PRE BUTTON_UP
135#define OSCILLOSCOPE_PAUSE (BUTTON_UP | BUTTON_REL)
136#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
137#define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
138#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
139#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
140#define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_FWD
141#define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_BACK
142#define NEED_LASTBUTTON
Michael Giacomelli6d5823f2009-01-04 23:33:15 +0000143
Marianne Arnold12ddb8e2007-09-20 10:49:48 +0000144#elif (CONFIG_KEYPAD == SANSA_C200_PAD)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500145#define OSCILLOSCOPE_QUIT BUTTON_POWER
146#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
147#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
148#define OSCILLOSCOPE_ORIENTATION BUTTON_UP
149#define OSCILLOSCOPE_PAUSE BUTTON_REC
150#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
151#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
152#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
153#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
154/* v1 - Need GRAPHMODE */
155/* v2 - Not enough plugin RAM for waveform view */
Marianne Arnold12ddb8e2007-09-20 10:49:48 +0000156
Rafaël Carré5656f822008-11-28 00:37:28 +0000157#elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500158#define OSCILLOSCOPE_QUIT BUTTON_POWER
159#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
160#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
161#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT
162#define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT)
163#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
164#define OSCILLOSCOPE_PAUSE BUTTON_UP
165#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
166#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
167#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
168#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
169#define NEED_LASTBUTTON
170/* Not enough plugin RAM for waveform view */
Rafaël Carré5656f822008-11-28 00:37:28 +0000171
Dominik Wenger90bcf9b2008-12-12 19:50:49 +0000172#elif (CONFIG_KEYPAD == SANSA_M200_PAD)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500173#define OSCILLOSCOPE_QUIT BUTTON_POWER
174#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
175#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
Michael Sevakis708bf1a2012-12-04 20:39:18 -0500176#define OSCILLOSCOPE_ORIENTATION BUTTON_UP
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500177#define OSCILLOSCOPE_PAUSE (BUTTON_SELECT | BUTTON_UP)
178#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
179#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
180#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
181#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
Michael Sevakis708bf1a2012-12-04 20:39:18 -0500182/* Not enough plugin RAM for waveform view */
Dominik Wenger90bcf9b2008-12-12 19:50:49 +0000183
Jens Arnold85a226d2007-03-16 23:02:39 +0000184#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500185#define OSCILLOSCOPE_QUIT BUTTON_POWER
186#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_SELECT
187#define OSCILLOSCOPE_DRAWMODE (BUTTON_SELECT | BUTTON_REL)
188#define OSCILLOSCOPE_ADVMODE BUTTON_REC
Jens Arnold61e798f2007-04-09 17:03:48 +0000189#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_SELECT
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500190#define OSCILLOSCOPE_ORIENTATION (BUTTON_SELECT | BUTTON_REPEAT)
191#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_PLAY
192#define OSCILLOSCOPE_GRAPHMODE (BUTTON_PLAY | BUTTON_REPEAT)
193#define OSCILLOSCOPE_PAUSE_PRE BUTTON_PLAY
194#define OSCILLOSCOPE_PAUSE (BUTTON_PLAY | BUTTON_REL)
195#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
196#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
197#define OSCILLOSCOPE_VOL_UP BUTTON_UP
198#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
199#define NEED_LASTBUTTON
Jens Arnolddb14d8e2004-11-07 10:31:39 +0000200
Daniel Stenberg1e88be52006-08-03 20:17:25 +0000201#elif CONFIG_KEYPAD == IRIVER_H10_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500202#define OSCILLOSCOPE_QUIT BUTTON_POWER
203#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_REW
204#define OSCILLOSCOPE_DRAWMODE (BUTTON_REW | BUTTON_REL)
205#define OSCILLOSCOPE_ADVMODE BUTTON_FF
Jens Arnold61e798f2007-04-09 17:03:48 +0000206#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_REW
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500207#define OSCILLOSCOPE_ORIENTATION (BUTTON_REW | BUTTON_REPEAT)
208#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_PLAY
209#define OSCILLOSCOPE_GRAPHMODE (BUTTON_PLAY | BUTTON_REPEAT)
210#define OSCILLOSCOPE_PAUSE_PRE BUTTON_PLAY
211#define OSCILLOSCOPE_PAUSE (BUTTON_PLAY | BUTTON_REL)
212#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
213#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
214#define OSCILLOSCOPE_VOL_UP BUTTON_SCROLL_UP
215#define OSCILLOSCOPE_VOL_DOWN BUTTON_SCROLL_DOWN
216#define NEED_LASTBUTTON
Daniel Stenberg1e88be52006-08-03 20:17:25 +0000217
Will Robertson8215b342008-02-17 12:23:02 +0000218#elif CONFIG_KEYPAD == GIGABEAT_S_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500219#define OSCILLOSCOPE_QUIT BUTTON_BACK
220#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
221#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
222#define OSCILLOSCOPE_ORIENTATION BUTTON_UP
223#define OSCILLOSCOPE_GRAPHMODE BUTTON_MENU
224#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
225#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
226#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
227#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
228#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
Will Robertson8215b342008-02-17 12:23:02 +0000229
Robert Kuklad6c8b572008-03-01 22:55:09 +0000230#elif (CONFIG_KEYPAD == MROBE100_PAD)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500231#define OSCILLOSCOPE_QUIT BUTTON_POWER
232#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
233#define OSCILLOSCOPE_ADVMODE BUTTON_MENU
234#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_PLAY
235#define OSCILLOSCOPE_ORIENTATION (BUTTON_PLAY | BUTTON_REL)
236#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_PLAY
237#define OSCILLOSCOPE_GRAPHMODE (BUTTON_PLAY | BUTTON_REPEAT)
238#define OSCILLOSCOPE_PAUSE BUTTON_DISPLAY
239#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
240#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
241#define OSCILLOSCOPE_VOL_UP BUTTON_UP
242#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
243#define NEED_LASTBUTTON
Will Robertson8215b342008-02-17 12:23:02 +0000244
Jens Arnold29361ab2008-03-22 10:24:28 +0000245#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500246#define OSCILLOSCOPE_QUIT BUTTON_RC_REC
247#define OSCILLOSCOPE_DRAWMODE_PRE BUTTON_RC_MODE
248#define OSCILLOSCOPE_DRAWMODE (BUTTON_RC_MODE|BUTTON_REL)
249#define OSCILLOSCOPE_ADVMODE BUTTON_RC_MENU
Jens Arnold29361ab2008-03-22 10:24:28 +0000250#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_RC_MODE
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500251#define OSCILLOSCOPE_ORIENTATION (BUTTON_RC_MODE|BUTTON_REPEAT)
252#define OSCILLOSCOPE_PAUSE_PRE BUTTON_RC_PLAY
253#define OSCILLOSCOPE_PAUSE (BUTTON_RC_PLAY|BUTTON_REL)
254#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_RC_PLAY
255#define SCILLLOSCOPE_GRAPHMODE (BUTTON_RC_PLAY|BUTTON_REPEAT)
256#define OSCILLOSCOPE_SPEED_UP BUTTON_RC_FF
257#define OSCILLOSCOPE_SPEED_DOWN BUTTON_RC_REW
258#define OSCILLOSCOPE_VOL_UP BUTTON_RC_VOL_UP
259#define OSCILLOSCOPE_VOL_DOWN BUTTON_RC_VOL_DOWN
260#define NEED_LASTBUTTON
Jens Arnold29361ab2008-03-22 10:24:28 +0000261
Tomer Shalev47ddbaa2009-12-15 20:51:41 +0000262#elif CONFIG_KEYPAD == COWON_D2_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500263#define OSCILLOSCOPE_QUIT BUTTON_POWER
264#define OSCILLOSCOPE_VOL_UP BUTTON_PLUS
265#define OSCILLOSCOPE_VOL_DOWN BUTTON_MINUS
Rob Purchase554d7ed2008-03-22 22:03:34 +0000266
Björn Stenbergcea285d2008-12-04 21:28:56 +0000267#elif CONFIG_KEYPAD == CREATIVEZVM_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500268#define OSCILLOSCOPE_QUIT BUTTON_BACK
269#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
270#define OSCILLOSCOPE_ADVMODE BUTTON_CUSTOM
271#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_MENU
272#define OSCILLOSCOPE_ORIENTATION (BUTTON_MENU | BUTTON_REL)
273#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_MENU
274#define OSCILLOSCOPE_GRAPHMODE (BUTTON_MENU | BUTTON_REPEAT)
275#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
276#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
277#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
278#define OSCILLOSCOPE_VOL_UP BUTTON_UP
279#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
280#define NEED_LASTBUTTON
Björn Stenbergcea285d2008-12-04 21:28:56 +0000281
Mark Arigo24902622009-01-24 22:41:55 +0000282#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500283#define OSCILLOSCOPE_QUIT BUTTON_POWER
284#define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
285#define OSCILLOSCOPE_ADVMODE BUTTON_VIEW
286#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_UP
287#define OSCILLOSCOPE_ORIENTATION (BUTTON_UP | BUTTON_REL)
288#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
289#define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
290#define OSCILLOSCOPE_PAUSE BUTTON_SELECT
291#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
292#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
293#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
294#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
295#define NEED_LASTBUTTON
Mark Arigo24902622009-01-24 22:41:55 +0000296
Robert Menesf7bcb662010-11-02 03:29:16 +0000297#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500298#define OSCILLOSCOPE_QUIT BUTTON_POWER
299#define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
300#define OSCILLOSCOPE_ADVMODE BUTTON_RIGHT
301#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_UP
302#define OSCILLOSCOPE_ORIENTATION (BUTTON_UP | BUTTON_REL)
303#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
304#define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
305#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
306#define OSCILLOSCOPE_SPEED_UP BUTTON_NEXT
307#define OSCILLOSCOPE_SPEED_DOWN BUTTON_PREV
308#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
309#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
310#define NEED_LASTBUTTON
Robert Menesf7bcb662010-11-02 03:29:16 +0000311
Robert Menes881eb5e2009-12-05 14:34:47 +0000312#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500313#define OSCILLOSCOPE_QUIT BUTTON_POWER
314#define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
315#define OSCILLOSCOPE_ADVMODE BUTTON_RIGHT
316#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_UP
317#define OSCILLOSCOPE_ORIENTATION (BUTTON_UP | BUTTON_REL)
318#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
319#define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
320#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
321#define OSCILLOSCOPE_SPEED_UP BUTTON_NEXT
322#define OSCILLOSCOPE_SPEED_DOWN BUTTON_PREV
323#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
324#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
325#define NEED_LASTBUTTON
Robert Menes881eb5e2009-12-05 14:34:47 +0000326
Maurus Cuelenaerefef405c2009-04-07 23:41:44 +0000327#elif CONFIG_KEYPAD == ONDAVX747_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500328#define OSCILLOSCOPE_QUIT BUTTON_POWER
329#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
330#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
Maurus Cuelenaerefef405c2009-04-07 23:41:44 +0000331
Maurus Cuelenaere96802442009-08-31 21:11:32 +0000332#elif CONFIG_KEYPAD == ONDAVX777_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500333#define OSCILLOSCOPE_QUIT BUTTON_POWER
Maurus Cuelenaere96802442009-08-31 21:11:32 +0000334
Karl Kurbjun48550062009-04-21 04:24:16 +0000335#elif CONFIG_KEYPAD == MROBE500_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500336#define OSCILLOSCOPE_QUIT BUTTON_POWER
Karl Kurbjun48550062009-04-21 04:24:16 +0000337
Michael Giacomelli594b6e22009-08-04 03:08:32 +0000338#elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500339#define OSCILLOSCOPE_QUIT BUTTON_REC
340#define OSCILLOSCOPE_DRAWMODE (BUTTON_PLAY|BUTTON_LEFT)
341#define OSCILLOSCOPE_ADVMODE (BUTTON_PLAY|BUTTON_RIGHT)
342#define OSCILLOSCOPE_ORIENTATION (BUTTON_PLAY|BUTTON_UP)
343#define OSCILLOSCOPE_PAUSE (BUTTON_PLAY|BUTTON_DOWN)
344#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
345#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
346#define OSCILLOSCOPE_VOL_UP BUTTON_UP
347#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
348/* Need GRAPHMODE */
Michael Giacomelli594b6e22009-08-04 03:08:32 +0000349
Szymon Dziok841cffa2010-02-13 15:46:34 +0000350#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500351#define OSCILLOSCOPE_QUIT BUTTON_REC
352#define OSCILLOSCOPE_DRAWMODE BUTTON_MENU
353#define OSCILLOSCOPE_ADVMODE BUTTON_CANCEL
354#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_OK
355#define OSCILLOSCOPE_ORIENTATION (BUTTON_OK | BUTTON_REL)
356#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_OK
357#define OSCILLOSCOPE_GRAPHMODE (BUTTON_OK | BUTTON_REPEAT)
358#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
359#define OSCILLOSCOPE_SPEED_UP BUTTON_PREV
360#define OSCILLOSCOPE_SPEED_DOWN BUTTON_NEXT
361#define OSCILLOSCOPE_VOL_UP BUTTON_UP
362#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
363#define NEED_LASTBUTTON
Szymon Dziok841cffa2010-02-13 15:46:34 +0000364
Marcin Bukatb09d3ae2010-04-26 21:40:00 +0000365#elif CONFIG_KEYPAD == MPIO_HD200_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500366#define OSCILLOSCOPE_QUIT (BUTTON_REC | BUTTON_PLAY)
367#define OSCILLOSCOPE_DRAWMODE BUTTON_FUNC
368#define OSCILLOSCOPE_ADVMODE BUTTON_REC
369#define OSCILLOSCOPE_ORIENTATION (BUTTON_FUNC | BUTTON_REPEAT)
370#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
371#define OSCILLOSCOPE_SPEED_UP BUTTON_FF
372#define OSCILLOSCOPE_SPEED_DOWN BUTTON_REW
373#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
374#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
375/* Need GRAPHMODE */
Marcin Bukatb09d3ae2010-04-26 21:40:00 +0000376
Marcin Bukatdd617022010-11-30 10:52:14 +0000377#elif CONFIG_KEYPAD == MPIO_HD300_PAD
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500378#define OSCILLOSCOPE_QUIT (BUTTON_MENU | BUTTON_REPEAT)
379#define OSCILLOSCOPE_DRAWMODE BUTTON_ENTER
380#define OSCILLOSCOPE_ADVMODE BUTTON_REC
Michael Sevakis708bf1a2012-12-04 20:39:18 -0500381#define OSCILLOSCOPE_ORIENTATION BUTTON_MENU
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500382#define OSCILLOSCOPE_PAUSE BUTTON_PLAY
383#define OSCILLOSCOPE_SPEED_UP BUTTON_FF
384#define OSCILLOSCOPE_SPEED_DOWN BUTTON_REW
385#define OSCILLOSCOPE_VOL_UP BUTTON_UP
386#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
Michael Sevakis708bf1a2012-12-04 20:39:18 -0500387/* Need GRAPHMODE */
Marcin Bukatdd617022010-11-30 10:52:14 +0000388
Amaury Poulya512db22011-10-02 16:20:47 +0000389#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
390#define OSCILLOSCOPE_QUIT BUTTON_POWER
391#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
392#define OSCILLOSCOPE_ADVMODE BUTTON_BACK
Jean-Louis Biasinid4139c82013-02-14 15:21:05 +0200393#define OSCILLOSCOPE_ORIENTATION BUTTON_UP
Amaury Poulya512db22011-10-02 16:20:47 +0000394#define OSCILLOSCOPE_PAUSE BUTTON_PLAYPAUSE
395#define OSCILLOSCOPE_SPEED_UP BUTTON_LEFT
396#define OSCILLOSCOPE_SPEED_DOWN BUTTON_RIGHT
397#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
398#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500399/* Need GRAPHMODE */
Amaury Poulya512db22011-10-02 16:20:47 +0000400
Tomasz Mońe8a8a1b2011-11-16 14:08:01 +0000401#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500402#define OSCILLOSCOPE_QUIT BUTTON_POWER
403#define OSCILLOSCOPE_DRAWMODE BUTTON_SELECT
404#define OSCILLOSCOPE_ADVMODE BUTTON_DOWN
405#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_UP
406#define OSCILLOSCOPE_ORIENTATION (BUTTON_UP | BUTTON_REL)
407#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_UP
408#define OSCILLOSCOPE_GRAPHMODE (BUTTON_UP | BUTTON_REPEAT)
409#define OSCILLOSCOPE_PAUSE BUTTON_NEXT
410#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
411#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
412#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP
413#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN
414#define NEED_LASTBUTTON
Tomasz Mońe8a8a1b2011-11-16 14:08:01 +0000415
Thomas Martitz249bba02011-12-24 11:56:46 +0000416#elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500417#define OSCILLOSCOPE_QUIT BUTTON_BACK
418#define OSCILLOSCOPE_DRAWMODE BUTTON_USER
419#define OSCILLOSCOPE_ADVMODE BUTTON_MENU
420#define OSCILLOSCOPE_ORIENTATION BUTTON_POWER
421#define OSCILLOSCOPE_PAUSE BUTTON_SELECT
422#define OSCILLOSCOPE_SPEED_UP BUTTON_RIGHT
423#define OSCILLOSCOPE_SPEED_DOWN BUTTON_LEFT
424#define OSCILLOSCOPE_VOL_UP BUTTON_UP
425#define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN
426/* Need GRAPHMODE */
Thomas Martitz249bba02011-12-24 11:56:46 +0000427
Andrew Ryabinin397863a2012-03-23 22:32:50 +0400428#elif (CONFIG_KEYPAD == HM60X_PAD)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500429#define OSCILLOSCOPE_QUIT BUTTON_POWER
430#define OSCILLOSCOPE_DRAWMODE (BUTTON_POWER | BUTTON_SELECT)
431#define OSCILLOSCOPE_ADVMODE (BUTTON_POWER | BUTTON_RIGHT)
432#define OSCILLOSCOPE_ORIENTATION (BUTTON_POWER | BUTTON_LEFT)
433#define OSCILLOSCOPE_PAUSE BUTTON_SELECT
434#define OSCILLOSCOPE_SPEED_UP BUTTON_UP
435#define OSCILLOSCOPE_SPEED_DOWN BUTTON_DOWN
436#define OSCILLOSCOPE_VOL_UP BUTTON_RIGHT
437#define OSCILLOSCOPE_VOL_DOWN BUTTON_LEFT
438/* Need GRAPHMODE */
Andrew Ryabinin397863a2012-03-23 22:32:50 +0400439
Andrew Ryabinin6ee3fc82012-04-06 20:17:27 +0400440#elif (CONFIG_KEYPAD == HM801_PAD)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500441#define OSCILLOSCOPE_QUIT BUTTON_POWER
442#define OSCILLOSCOPE_DRAWMODE BUTTON_PREV
443#define OSCILLOSCOPE_ADVMODE BUTTON_NEXT
444#define OSCILLOSCOPE_ORIENTATION BUTTON_PLAY
445#define OSCILLOSCOPE_PAUSE BUTTON_SELECT
446#define OSCILLOSCOPE_SPEED_UP BUTTON_UP
447#define OSCILLOSCOPE_SPEED_DOWN BUTTON_DOWN
448#define OSCILLOSCOPE_VOL_UP BUTTON_RIGHT
449#define OSCILLOSCOPE_VOL_DOWN BUTTON_LEFT
450/* Need GRAPHMODE */
Andrew Ryabinin6ee3fc82012-04-06 20:17:27 +0400451
Robert Kuklad6c8b572008-03-01 22:55:09 +0000452#else
453#error No keymap defined!
Jens Arnolddb14d8e2004-11-07 10:31:39 +0000454#endif
455
Maurus Cuelenaere1392dc22008-08-23 09:46:38 +0000456#ifdef HAVE_TOUCHSCREEN
Rob Purchase297e0502008-04-27 15:30:19 +0000457#ifndef OSCILLOSCOPE_QUIT
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500458#define OSCILLOSCOPE_QUIT BUTTON_TOPLEFT
Rob Purchase297e0502008-04-27 15:30:19 +0000459#endif
460#ifndef OSCILLOSCOPE_DRAWMODE
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500461#define OSCILLOSCOPE_DRAWMODE BUTTON_TOPMIDDLE
Rob Purchase297e0502008-04-27 15:30:19 +0000462#endif
463#ifndef OSCILLOSCOPE_ADVMODE
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500464#define OSCILLOSCOPE_ADVMODE BUTTON_BOTTOMMIDDLE
Rob Purchase297e0502008-04-27 15:30:19 +0000465#endif
466#ifndef OSCILLOSCOPE_ORIENTATION
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500467#define OSCILLOSCOPE_ORIENTATION_PRE BUTTON_BOTTOMLEFT
468#define OSCILLOSCOPE_ORIENTATION (BUTTON_BOTTOMLEFT|BUTTON_REL)
469#endif
470#ifndef OSCILLOSCOPE_GRAPHMODE
471#define OSCILLOSCOPE_GRAPHMODE_PRE BUTTON_BOTTOMLEFT
472#define OSCILLOSCOPE_GRAPHMODE (BUTTON_BOTTOMLEFT|BUTTON_REPEAT)
Rob Purchase297e0502008-04-27 15:30:19 +0000473#endif
474#ifndef OSCILLOSCOPE_PAUSE
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500475#define OSCILLOSCOPE_PAUSE BUTTON_CENTER
Rob Purchase297e0502008-04-27 15:30:19 +0000476#endif
477#ifndef OSCILLOSCOPE_SPEED_UP
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500478#define OSCILLOSCOPE_SPEED_UP BUTTON_MIDRIGHT
Rob Purchase297e0502008-04-27 15:30:19 +0000479#endif
480#ifndef OSCILLOSCOPE_SPEED_DOWN
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500481#define OSCILLOSCOPE_SPEED_DOWN BUTTON_MIDLEFT
Rob Purchase297e0502008-04-27 15:30:19 +0000482#endif
483#ifndef OSCILLOSCOPE_VOL_UP
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500484#define OSCILLOSCOPE_VOL_UP BUTTON_TOPRIGHT
Rob Purchase297e0502008-04-27 15:30:19 +0000485#endif
486#ifndef OSCILLOSCOPE_VOL_DOWN
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500487#define OSCILLOSCOPE_VOL_DOWN BUTTON_BOTTOMRIGHT
Rob Purchase297e0502008-04-27 15:30:19 +0000488#endif
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500489#define NEED_LASTBUTTON
490#endif /* HAVE_TOUCHSCREEN */
Rob Purchase297e0502008-04-27 15:30:19 +0000491
Jens Arnoldf9765d32006-03-11 01:13:51 +0000492/* colours */
493#if LCD_DEPTH > 1
494#ifdef HAVE_LCD_COLOR
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500495#define BACKG_COLOR LCD_BLACK
496#define GRAPH_COLOR LCD_RGBPACK(128, 255, 0)
497#define CURSOR_COLOR LCD_RGBPACK(255, 0, 0)
498#define GRID_COLOR LCD_RGBPACK(192, 255, 64)
499#define OSD_TEXT_COLOR LCD_WHITE
500#define OSD_BACKG_COLOR LCD_BLACK
501#define OSD_BORDER_COLOR LCD_RGBPACK(255, 0, 0)
502#define OSC_OSD_MARGIN_SIZE 0 /* Border and text are different */
Jens Arnoldf9765d32006-03-11 01:13:51 +0000503#else
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500504#define BACKG_COLOR LCD_WHITE
505#define GRAPH_COLOR LCD_BLACK
506#define CURSOR_COLOR LCD_DARKGRAY
507#define GRID_COLOR LCD_DARKGRAY
508#define OSD_TEXT_COLOR LCD_BLACK
509#define OSD_BACKG_COLOR LCD_WHITE
510#define OSD_BORDER_COLOR LCD_BLACK
Jens Arnoldf9765d32006-03-11 01:13:51 +0000511#endif
512#endif
513
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500514#ifndef OSC_OSD_MARGIN_SIZE
515#define OSC_OSD_MARGIN_SIZE 1
516#endif
517
518#define MIN_SPEED 1
519#define MAX_SPEED 100
520
Jens Arnoldf9765d32006-03-11 01:13:51 +0000521enum { DRAW_FILLED, DRAW_LINE, DRAW_PIXEL, MAX_DRAW };
522enum { ADV_SCROLL, ADV_WRAP, MAX_ADV };
523enum { OSC_HORIZ, OSC_VERT, MAX_OSC };
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500524enum
525{
526 GRAPH_PEAKS,
527#ifdef OSCILLOSCOPE_GRAPHMODE
528 GRAPH_WAVEFORM,
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000529#endif
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500530 MAX_GRAPH
531};
532
533#define CFGFILE_VERSION 1 /* Current config file version */
534#define CFGFILE_MINVERSION 0 /* Minimum config file version to accept */
Jens Arnolddb14d8e2004-11-07 10:31:39 +0000535
536/* global variables */
537
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500538/*
539 * / 99*[e ^ ((100 - x) / z) - 1] \
540 * osc_delay = HZ * | ---------------------------- + 1 |
541 * \ [e ^ (99 / z) - 1] /
542 *
543 * x: 1 .. 100, z: 15, delay: 100.00 .. 1.00
544 */
545static const unsigned short osc_delay_tbl[100] =
546{
547 10000, 9361, 8763, 8205, 7682, 7192, 6735, 6307, 5906, 5532,
548 5181, 4853, 4546, 4259, 3991, 3739, 3504, 3285, 3079, 2886,
549 2706, 2538, 2380, 2233, 2095, 1966, 1845, 1732, 1627, 1528,
550 1435, 1349, 1268, 1192, 1121, 1055, 993, 935, 880, 830,
551 782, 737, 696, 657, 620, 586, 554, 524, 497, 470,
552 446, 423, 402, 381, 363, 345, 329, 313, 299, 285,
553 273, 261, 250, 239, 230, 221, 212, 204, 197, 190,
554 183, 177, 171, 166, 161, 156, 152, 147, 144, 140,
555 136, 133, 130, 127, 125, 122, 120, 118, 116, 114,
556 112, 110, 108, 107, 106, 104, 103, 102, 101, 100
557};
558
559#define GRAPH_PEAKS_DEFAULT 68
560#define GRAPH_WAVEFORM_DEFAULT 50
561
Jens Arnoldf9765d32006-03-11 01:13:51 +0000562/* settings */
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500563static struct osc_config
564{
565 int speed[MAX_GRAPH];
Jens Arnold37f529c2006-03-11 08:35:45 +0000566 int draw;
567 int advance;
568 int orientation;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500569 int graphmode;
570} osc_disk =
571{
572 .speed =
573 {
574 [GRAPH_PEAKS] = GRAPH_PEAKS_DEFAULT,
575#ifdef OSCILLOSCOPE_GRAPHMODE
576 [GRAPH_WAVEFORM] = GRAPH_WAVEFORM_DEFAULT,
577#endif
578 },
579 .draw = DRAW_FILLED,
580 .advance = ADV_SCROLL,
581 .orientation = OSC_HORIZ,
582#ifdef OSCILLOSCOPE_GRAPHMODE
583 .graphmode = GRAPH_PEAKS,
584#endif
Jens Arnold37f529c2006-03-11 08:35:45 +0000585};
586
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500587static struct osc_config osc; /* running config */
Jens Arnoldf9765d32006-03-11 01:13:51 +0000588
589static const char cfg_filename[] = "oscilloscope.cfg";
590static char *draw_str[3] = { "filled", "line", "pixel" };
591static char *advance_str[2] = { "scroll", "wrap" };
592static char *orientation_str[2] = { "horizontal", "vertical" };
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500593#ifdef OSCILLOSCOPE_GRAPHMODE
594static char *graphmode_str[2] = { "peaks", "waveform" };
595#endif
Jens Arnoldf9765d32006-03-11 01:13:51 +0000596
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500597struct configdata disk_config[] =
598{
599 { TYPE_INT, MIN_SPEED, MAX_SPEED,
600 { .int_p = &osc_disk.speed[GRAPH_PEAKS] }, "speed", NULL },
Andrew Mahone0b41f052009-01-17 22:53:12 +0000601 { TYPE_ENUM, 0, MAX_DRAW, { .int_p = &osc_disk.draw }, "draw", draw_str },
602 { TYPE_ENUM, 0, MAX_ADV, { .int_p = &osc_disk.advance }, "advance",
603 advance_str },
604 { TYPE_ENUM, 0, MAX_OSC, { .int_p = &osc_disk.orientation }, "orientation",
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500605 orientation_str },
606#ifdef OSCILLOSCOPE_GRAPHMODE
607 { TYPE_INT, MAX_SPEED, MAX_SPEED,
608 { .int_p = &osc_disk.speed[GRAPH_WAVEFORM] }, "wavespeed", NULL },
609 { TYPE_ENUM, 0, MAX_GRAPH, { .int_p = &osc_disk.graphmode }, "graphmode",
610 graphmode_str },
611#endif
Jens Arnoldf9765d32006-03-11 01:13:51 +0000612};
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000613
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500614enum osc_message_ids
615{
616 OSC_MSG_ADVMODE,
617 OSC_MSG_DRAWMODE,
618#ifdef OSCILLOSCOPE_GRAPHMODE
619 OSC_MSG_GRAPHMODE,
620#endif
621 OSC_MSG_ORIENTATION,
622 OSC_MSG_PAUSED,
623 OSC_MSG_SPEED,
624 OSC_MSG_VOLUME,
625};
Jens Arnold37f529c2006-03-11 08:35:45 +0000626
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500627static long (*anim_draw)(void);
628static int message = -1, msgval = 0; /* popup message */
629static bool paused = false;
630static bool one_frame_paused = false; /* Allow one frame to be drawn when paused if
631 view is erased */
632static long osc_delay; /* delay in 100ths of a tick */
633static long osc_delay_error; /* delay fraction error accumulator */
Jens Arnolddb14d8e2004-11-07 10:31:39 +0000634
635/* implementation */
636
Jens Arnolddb14d8e2004-11-07 10:31:39 +0000637
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500638/** Messages **/
639
640static unsigned char osc_osd_message[16]; /* message to display (formatted) */
641
642static inline void osc_popupmsg(int msg, int val)
643{
644 message = msg; msgval = val;
645}
646
647/* Format a message to display */
648static void osc_osd_format_message(enum osc_message_ids id, int val)
649{
650 const char *msg = "";
651
652 switch (id)
653 {
654 case OSC_MSG_ADVMODE:
655 msg = val == ADV_WRAP ? "Wrap" : "Scroll";
656 break;
657
658 case OSC_MSG_DRAWMODE:
659 switch (val)
660 {
661 case DRAW_PIXEL: msg = "Pixel"; break;
662 case DRAW_LINE: msg = "Line"; break;
663 default: msg = "Filled";
664 }
665 break;
666
667#ifdef OSCILLOSCOPE_GRAPHMODE
668 case OSC_MSG_GRAPHMODE:
669 msg = val == GRAPH_WAVEFORM ? "Waveform" : "Peaks";
670 break;
671#endif
672
673 case OSC_MSG_ORIENTATION:
674 msg = val == OSC_VERT ? "Vertical" : "Horizontal";
675 break;
676
677 case OSC_MSG_PAUSED:
678 msg = val ? "Paused" : "Running";
679 break;
680
681 case OSC_MSG_SPEED:
682 msg = "Speed: %d";
683 break;
684
685 case OSC_MSG_VOLUME:
686 rb->snprintf(osc_osd_message, sizeof (osc_osd_message),
687 "Volume: %d%s",
688 rb->sound_val2phys(SOUND_VOLUME, val),
689 rb->sound_unit(SOUND_VOLUME));
690 return;
691 }
692
693 /* Default action: format integer */
694 rb->snprintf(osc_osd_message, sizeof (osc_osd_message), msg, val);
695}
696
697
698/** OSD **/
699
700/* Actually draw the OSD within the OSD viewport */
701extern void osd_lcd_draw_cb(int x, int y, int width, int height)
702{
703#if LCD_DEPTH > 1
704 rb->lcd_set_foreground(OSD_TEXT_COLOR);
705 rb->lcd_set_background(OSD_BACKG_COLOR);
706#endif
707#if OSC_OSD_MARGIN_SIZE != 0
708 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
709 rb->lcd_fillrect(1, 1, width - 2, height - 2);
710 rb->lcd_set_drawmode(DRMODE_SOLID);
711#endif
712 rb->lcd_putsxy(1+OSC_OSD_MARGIN_SIZE, 1+OSC_OSD_MARGIN_SIZE,
713 osc_osd_message);
714#if LCD_DEPTH > 1
715 rb->lcd_set_foreground(OSD_BORDER_COLOR);
716#endif
717 rb->lcd_drawrect(0, 0, width, height);
718
719 (void)x; (void)y;
720}
721
722/* Perform all necessary basic setup tasks for the OSD */
723static void osc_osd_init(void)
724{
725 /* Grab the plugin buffer for the OSD back buffer */
726 size_t bufsize;
727 void *buf = rb->plugin_get_buffer(&bufsize);
Michael Sevakis371c86b2012-12-07 01:50:52 -0500728
729 int width, height;
730 rb->lcd_setfont(FONT_UI);
731 rb->lcd_getstringsize("M", NULL, &height);
732 width = LCD_WIDTH;
733 height += 2 + 2*OSC_OSD_MARGIN_SIZE;
734 osd_init(OSD_INIT_MAJOR_HEIGHT | OSD_INIT_MINOR_MAX, buf, bufsize,
735 osd_lcd_draw_cb, &width, &height, NULL);
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500736}
737
738/* Format a message by ID and show the OSD */
739static void osc_osd_show_message(int id, int val)
740{
741 osc_osd_format_message(id, val);
742
743 if (!osd_enabled())
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000744 return;
745
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500746 int width, height;
747 int maxwidth, maxheight;
748
749 rb->lcd_set_viewport(osd_get_viewport());
750 osd_get_max_dims(&maxwidth, &maxheight);
751 rb->lcd_getstringsize(osc_osd_message, &width, &height);
752 rb->lcd_set_viewport(NULL); /* to regular viewport */
753
754 width += 2 + 2*OSC_OSD_MARGIN_SIZE;
755 if (width > maxwidth)
756 width = maxwidth;
757
758 height += 2 + 2*OSC_OSD_MARGIN_SIZE;
759 if (height > maxheight)
760 height = maxheight;
761
762 /* Center it on the screen */
763 bool drawn = osd_update_pos((LCD_WIDTH - width) / 2,
764 (LCD_HEIGHT - height) / 2,
765 width, height);
766
767 osd_show(OSD_SHOW | (drawn ? 0 : OSD_UPDATENOW));
768}
769
770/* Draw cursor bar for horizontal views */
771static void anim_draw_cursor_h(int x)
772{
773#if LCD_DEPTH > 1
774 rb->lcd_set_foreground(CURSOR_COLOR);
775 rb->lcd_vline(x, 0, LCD_HEIGHT-1);
776 rb->lcd_set_foreground(GRAPH_COLOR);
777#else
778 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
779 rb->lcd_vline(x, 0, LCD_HEIGHT-1);
780 rb->lcd_set_drawmode(DRMODE_SOLID);
781#endif
782}
783
784/* Draw cursor bar for vertical views */
785static void anim_draw_cursor_v(int y)
786{
787#if LCD_DEPTH > 1 /* cursor bar */
788 rb->lcd_set_foreground(CURSOR_COLOR);
789 rb->lcd_hline(0, LCD_WIDTH-1, y);
790 rb->lcd_set_foreground(GRAPH_COLOR);
791#else
792 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
793 rb->lcd_hline(0, LCD_WIDTH-1, y);
794 rb->lcd_set_drawmode(DRMODE_SOLID);
795#endif
796}
797
798
799/** Peaks View **/
800
801static long last_tick = 0; /* time of last drawing */
802static long last_delay = 0; /* last delay value used */
803static int last_pos = 0; /* last x or y drawing position. Reset for aspect switch. */
804static int last_left; /* last channel values */
805static int last_right;
806
807static void get_peaks(int *left, int *right)
808{
809#if CONFIG_CODEC == SWCODEC
810 static struct pcm_peaks peaks;
811 rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
812 &peaks);
813 *left = peaks.left;
814 *right = peaks.right;
815#elif defined (SIMULATOR)
816 *left = rand() % 0x8000;
817 *right = rand() % 0x8000;
818#elif (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
819 *left = rb->mas_codec_readreg(0xC);
820 *right = rb->mas_codec_readreg(0xD);
821#else
822 *left = 0;
823 *right = 0;
824#endif
825}
826
827static long get_next_delay(void)
828{
829 long delay = osc_delay / 100;
830 osc_delay_error += osc_delay - delay * 100;
831
832 if (osc_delay_error >= 100)
833 {
834 delay++;
835 osc_delay_error -= 100;
836 }
837
838 return delay;
839}
840
841static long anim_peaks_horizontal(void)
842{
843 long cur_tick = *rb->current_tick;
844 int cur_x, x;
845 int left, right, dl, dr;
846 long d = (cur_tick - last_tick) / last_delay;
847 bool full_update = false;
848
849 if (paused)
850 {
851 one_frame_paused = false;
852 osd_lcd_update_prepare();
853 anim_draw_cursor_h(0);
854 osd_lcd_update_rect(0, 0, 1, LCD_HEIGHT);
855 last_pos = -1;
856 return cur_tick + HZ/5;
857 }
858
859 if (d <= 0) /* too early, bail out */
860 return last_tick + last_delay;
861
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000862 last_tick = cur_tick;
863
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500864 int cur_left, cur_right;
865 get_peaks(&cur_left, &cur_right);
866
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000867 if (d > HZ) /* first call or too much delay, (re)start */
868 {
869 last_left = cur_left;
870 last_right = cur_right;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500871 return cur_tick + last_delay;
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000872 }
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500873
874 one_frame_paused = false;
875
876 osd_lcd_update_prepare();
877
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000878 cur_x = last_pos + d;
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000879
880 if (cur_x >= LCD_WIDTH)
881 {
Jens Arnold37f529c2006-03-11 08:35:45 +0000882 if (osc.advance == ADV_SCROLL)
Jens Arnolddb14d8e2004-11-07 10:31:39 +0000883 {
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000884 int shift = cur_x - (LCD_WIDTH-1);
885 xlcd_scroll_left(shift);
886 full_update = true;
887 cur_x -= shift;
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000888 last_pos -= shift;
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000889 }
Jens Arnoldf9765d32006-03-11 01:13:51 +0000890 else
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000891 {
892 cur_x -= LCD_WIDTH;
893 }
894 }
895 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
896
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000897 if (cur_x > last_pos)
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000898 {
Jens Arnoldf9765d32006-03-11 01:13:51 +0000899 rb->lcd_fillrect(last_pos + 1, 0, d, LCD_HEIGHT);
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000900 }
901 else
902 {
Jens Arnoldf9765d32006-03-11 01:13:51 +0000903 rb->lcd_fillrect(last_pos + 1, 0, LCD_WIDTH - last_pos, LCD_HEIGHT);
904 rb->lcd_fillrect(0, 0, cur_x + 1, LCD_HEIGHT);
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000905 }
906 rb->lcd_set_drawmode(DRMODE_SOLID);
907
Jens Arnold37f529c2006-03-11 08:35:45 +0000908 switch (osc.draw)
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000909 {
Jens Arnoldf9765d32006-03-11 01:13:51 +0000910 case DRAW_FILLED:
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000911 left = last_left;
912 right = last_right;
913 dl = (cur_left - left) / d;
914 dr = (cur_right - right) / d;
915
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000916 for (x = last_pos + 1; d > 0; x++, d--)
Jens Arnolddb14d8e2004-11-07 10:31:39 +0000917 {
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000918 if (x == LCD_WIDTH)
919 x = 0;
920
921 left += dl;
922 right += dr;
923
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000924 rb->lcd_vline(x, LCD_HEIGHT/2-1,
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000925 LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16));
926 rb->lcd_vline(x, LCD_HEIGHT/2+1,
927 LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16));
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000928 }
929 break;
930
Jens Arnoldf9765d32006-03-11 01:13:51 +0000931 case DRAW_LINE:
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000932 if (cur_x > last_pos)
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000933 {
934 rb->lcd_drawline(
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000935 last_pos, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * last_left) >> 16),
936 cur_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * cur_left) >> 16)
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000937 );
938 rb->lcd_drawline(
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000939 last_pos, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * last_right) >> 16),
940 cur_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * cur_right) >> 16)
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000941 );
Jens Arnolddb14d8e2004-11-07 10:31:39 +0000942 }
943 else
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000944 {
945 left = last_left
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000946 + (LCD_WIDTH - last_pos) * (last_left - cur_left) / d;
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000947 right = last_right
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000948 + (LCD_WIDTH - last_pos) * (last_right - cur_right) / d;
Jens Arnold19b45a42006-03-08 01:14:46 +0000949
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000950 rb->lcd_drawline(
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000951 last_pos, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * last_left) >> 16),
952 LCD_WIDTH, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16)
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000953 );
954 rb->lcd_drawline(
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000955 last_pos, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * last_right) >> 16),
956 LCD_WIDTH, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16)
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000957 );
Jens Arnoldf9765d32006-03-11 01:13:51 +0000958 if (cur_x > 0)
959 {
960 rb->lcd_drawline(
961 0, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16),
962 cur_x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * cur_left) >> 16)
963 );
964 rb->lcd_drawline(
965 0, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16),
966 cur_x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * cur_right) >> 16)
967 );
968 }
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000969 }
970 break;
Jens Arnolddb14d8e2004-11-07 10:31:39 +0000971
Jens Arnoldf9765d32006-03-11 01:13:51 +0000972 case DRAW_PIXEL:
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000973 left = last_left;
974 right = last_right;
975 dl = (cur_left - left) / d;
976 dr = (cur_right - right) / d;
977
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000978 for (x = last_pos + 1; d > 0; x++, d--)
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000979 {
980 if (x == LCD_WIDTH)
981 x = 0;
982
983 left += dl;
984 right += dr;
985
Jens Arnold78e4f4d2006-03-10 00:18:58 +0000986 rb->lcd_drawpixel(x, LCD_HEIGHT/2-1 - (((LCD_HEIGHT-2) * left) >> 16));
987 rb->lcd_drawpixel(x, LCD_HEIGHT/2+1 + (((LCD_HEIGHT-2) * right) >> 16));
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000988 }
989 break;
990
Jens Arnolddb14d8e2004-11-07 10:31:39 +0000991 }
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500992
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000993 last_left = cur_left;
994 last_right = cur_right;
Jens Arnoldf9765d32006-03-11 01:13:51 +0000995
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000996 if (full_update)
997 {
Michael Sevakis0f8aedb2012-12-02 01:09:44 -0500998 osd_lcd_update();
Jens Arnoldb318b3e2006-03-09 07:52:26 +0000999 }
1000 else
1001 {
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001002 anim_draw_cursor_h(cur_x + 1); /* cursor bar */
Jens Arnoldf9765d32006-03-11 01:13:51 +00001003
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001004 if (cur_x > last_pos)
Jens Arnoldb318b3e2006-03-09 07:52:26 +00001005 {
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001006 osd_lcd_update_rect(last_pos, 0, cur_x - last_pos + 2, LCD_HEIGHT);
Jens Arnoldb318b3e2006-03-09 07:52:26 +00001007 }
1008 else
1009 {
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001010 osd_lcd_update_rect(last_pos, 0, LCD_WIDTH - last_pos, LCD_HEIGHT);
1011 osd_lcd_update_rect(0, 0, cur_x + 2, LCD_HEIGHT);
Jens Arnoldb318b3e2006-03-09 07:52:26 +00001012 }
1013 }
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001014 last_pos = cur_x;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001015
1016 last_delay = get_next_delay();
1017 return cur_tick + last_delay;
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001018}
1019
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001020static long anim_peaks_vertical(void)
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001021{
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001022 long cur_tick = *rb->current_tick;
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001023 int cur_y, y;
1024 int left, right, dl, dr;
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001025 bool full_update = false;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001026 long d = (cur_tick - last_tick) / last_delay;
1027
1028 if (paused)
1029 {
1030 one_frame_paused = false;
1031 osd_lcd_update_prepare();
1032 anim_draw_cursor_v(0);
1033 osd_lcd_update_rect(0, 0, LCD_WIDTH, 1);
1034 last_pos = -1;
1035 return cur_tick + HZ/5;
1036 }
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001037
1038 if (d == 0) /* too early, bail out */
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001039 return last_tick + last_delay;
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001040
1041 last_tick = cur_tick;
1042
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001043 int cur_left, cur_right;
1044 get_peaks(&cur_left, &cur_right);
1045
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001046 if (d > HZ) /* first call or too much delay, (re)start */
1047 {
1048 last_left = cur_left;
1049 last_right = cur_right;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001050 return cur_tick + last_delay;
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001051 }
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001052
1053 one_frame_paused = false;
1054
1055 osd_lcd_update_prepare();
1056
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001057 cur_y = last_pos + d;
1058
1059 if (cur_y >= LCD_HEIGHT)
1060 {
Jens Arnold37f529c2006-03-11 08:35:45 +00001061 if (osc.advance == ADV_SCROLL)
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001062 {
1063 int shift = cur_y - (LCD_HEIGHT-1);
1064 xlcd_scroll_up(shift);
1065 full_update = true;
1066 cur_y -= shift;
1067 last_pos -= shift;
1068 }
Jens Arnoldf9765d32006-03-11 01:13:51 +00001069 else
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001070 {
1071 cur_y -= LCD_HEIGHT;
1072 }
1073 }
1074 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1075
1076 if (cur_y > last_pos)
1077 {
Jens Arnoldf9765d32006-03-11 01:13:51 +00001078 rb->lcd_fillrect(0, last_pos + 1, LCD_WIDTH, d);
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001079 }
1080 else
1081 {
Jens Arnoldf9765d32006-03-11 01:13:51 +00001082 rb->lcd_fillrect(0, last_pos + 1, LCD_WIDTH, LCD_HEIGHT - last_pos);
1083 rb->lcd_fillrect(0, 0, LCD_WIDTH, cur_y + 1);
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001084 }
1085 rb->lcd_set_drawmode(DRMODE_SOLID);
1086
Jens Arnold37f529c2006-03-11 08:35:45 +00001087 switch (osc.draw)
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001088 {
Jens Arnoldf9765d32006-03-11 01:13:51 +00001089 case DRAW_FILLED:
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001090 left = last_left;
1091 right = last_right;
1092 dl = (cur_left - left) / d;
1093 dr = (cur_right - right) / d;
1094
1095 for (y = last_pos + 1; d > 0; y++, d--)
1096 {
1097 if (y == LCD_HEIGHT)
1098 y = 0;
1099
1100 left += dl;
1101 right += dr;
1102
1103 rb->lcd_hline(LCD_WIDTH/2-1,
1104 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), y);
1105 rb->lcd_hline(LCD_WIDTH/2+1,
1106 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), y);
1107 }
1108 break;
1109
Jens Arnoldf9765d32006-03-11 01:13:51 +00001110 case DRAW_LINE:
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001111 if (cur_y > last_pos)
1112 {
1113 rb->lcd_drawline(
1114 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * last_left) >> 16), last_pos,
1115 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * cur_left) >> 16), cur_y
1116 );
1117 rb->lcd_drawline(
1118 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * last_right) >> 16), last_pos,
1119 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * cur_right) >> 16), cur_y
1120 );
1121 }
1122 else
1123 {
1124 left = last_left
1125 + (LCD_HEIGHT - last_pos) * (last_left - cur_left) / d;
1126 right = last_right
1127 + (LCD_HEIGHT - last_pos) * (last_right - cur_right) / d;
1128
1129 rb->lcd_drawline(
1130 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * last_left) >> 16), last_pos,
1131 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), LCD_HEIGHT
1132 );
1133 rb->lcd_drawline(
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001134 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * last_right) >> 16), last_pos,
1135 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), LCD_HEIGHT
1136 );
Jens Arnoldf9765d32006-03-11 01:13:51 +00001137 if (cur_y > 0)
1138 {
1139 rb->lcd_drawline(
1140 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), 0,
1141 LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * cur_left) >> 16), cur_y
1142 );
1143 rb->lcd_drawline(
1144 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), 0,
1145 LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * cur_right) >> 16), cur_y
1146 );
1147 }
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001148 }
1149 break;
1150
Jens Arnoldf9765d32006-03-11 01:13:51 +00001151 case DRAW_PIXEL:
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001152 left = last_left;
1153 right = last_right;
1154 dl = (cur_left - left) / d;
1155 dr = (cur_right - right) / d;
1156
1157 for (y = last_pos + 1; d > 0; y++, d--)
1158 {
1159 if (y == LCD_HEIGHT)
1160 y = 0;
1161
1162 left += dl;
1163 right += dr;
1164
1165 rb->lcd_drawpixel(LCD_WIDTH/2-1 - (((LCD_WIDTH-2) * left) >> 16), y);
1166 rb->lcd_drawpixel(LCD_WIDTH/2+1 + (((LCD_WIDTH-2) * right) >> 16), y);
1167 }
1168 break;
1169
1170 }
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001171
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001172 last_left = cur_left;
1173 last_right = cur_right;
1174
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001175 if (full_update)
1176 {
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001177 osd_lcd_update();
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001178 }
1179 else
1180 {
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001181 anim_draw_cursor_v(cur_y + 1); /* cursor bar */
Jens Arnoldf9765d32006-03-11 01:13:51 +00001182
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001183 if (cur_y > last_pos)
1184 {
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001185 osd_lcd_update_rect(0, last_pos, LCD_WIDTH, cur_y - last_pos + 2);
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001186 }
1187 else
1188 {
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001189 osd_lcd_update_rect(0, last_pos, LCD_WIDTH, LCD_HEIGHT - last_pos);
1190 osd_lcd_update_rect(0, 0, LCD_WIDTH, cur_y + 2);
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001191 }
1192 }
1193 last_pos = cur_y;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001194
1195 last_delay = get_next_delay();
1196 return cur_tick + last_delay;
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001197}
1198
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001199
1200/** Waveform View **/
1201
1202#ifdef OSCILLOSCOPE_GRAPHMODE
Michael Sevakisd37bf242013-05-23 13:58:51 -04001203static int16_t waveform_buffer[2*ALIGN_UP(PLAY_SAMPR_MAX, 2048)+2*2048]
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001204 MEM_ALIGN_ATTR;
1205static size_t waveform_buffer_threshold = 0;
1206static size_t volatile waveform_buffer_have = 0;
1207static size_t waveform_buffer_break = 0;
Michael Sevakisd37bf242013-05-23 13:58:51 -04001208static unsigned long mixer_sampr = PLAY_SAMPR_DEFAULT;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001209#define PCM_SAMPLESIZE (2*sizeof(int16_t))
Michael Sevakisd37bf242013-05-23 13:58:51 -04001210#define PCM_BYTERATE(sampr) ((sampr)*PCM_SAMPLESIZE)
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001211
1212#define WAVEFORM_SCALE_PCM(full_scale, sample) \
1213 ((((full_scale) * (sample)) + (1 << 14)) >> 15)
1214
1215static void waveform_buffer_set_threshold(size_t threshold)
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001216{
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001217 if (threshold > sizeof (waveform_buffer))
1218 threshold = sizeof (waveform_buffer);
1219
1220 if (threshold == waveform_buffer_threshold)
1221 return;
1222
1223 /* Avoid changing it in the middle of buffer callback */
1224 rb->pcm_play_lock();
1225
1226 waveform_buffer_threshold = threshold;
1227
1228 rb->pcm_play_unlock();
1229}
1230
1231static inline bool waveform_buffer_have_enough(void)
1232{
1233 return waveform_buffer_have >= waveform_buffer_threshold;
1234}
1235
1236static void waveform_buffer_done(void)
1237{
1238 /* This is safe because buffer callback won't add more data unless the
1239 treshold is changed or data is removed below the threshold. This isn't
1240 called until after the threshold is already met. */
1241 size_t threshold = waveform_buffer_threshold;
1242 size_t have = 0;
1243
1244 if (threshold != 0)
1245 {
1246 have = waveform_buffer_have;
1247 size_t slide = (have - 1) / threshold * threshold;
1248
1249 if (slide == 0)
1250 slide = threshold;
1251
1252 have -= slide;
1253
1254 if (have > 0)
1255 {
1256 /* memcpy: the slide >= threshold and have <= threshold */
1257 memcpy(waveform_buffer, (void *)waveform_buffer + slide, have);
1258 }
1259 }
1260
1261 waveform_buffer_have = have;
1262}
1263
1264/* where the samples are obtained and buffered */
1265static void waveform_buffer_callback(const void *start, size_t size)
1266{
1267 size_t threshold = waveform_buffer_threshold;
1268 size_t have = waveform_buffer_have;
1269
1270 if (have >= threshold)
1271 {
1272 waveform_buffer_break += size;
1273 return;
1274 }
1275
1276 if (waveform_buffer_break > 0)
1277 {
1278 /* Previosly missed a part or all of a frame and the break would
1279 happen within the data threshold area. Start where frame would
1280 end up if all had been processed fully. This might mean a period
1281 of resynchronization will have to happen first before the buffer
1282 is filled to the threshold or even begins filling. Maintaining
1283 scan phase relationship is important to proper appearance or else
1284 the waveform display looks sloppy. */
1285 size_t brk = have + waveform_buffer_break;
1286 waveform_buffer_have = have = 0;
1287
1288 brk %= threshold;
1289
1290 if (brk != 0)
1291 {
1292 brk += size;
1293
1294 if (brk <= threshold)
1295 {
1296 waveform_buffer_break = brk;
1297 return;
1298 }
1299
1300 brk -= threshold;
1301 start += size - brk;
1302 size = brk;
1303 }
1304
1305 waveform_buffer_break = 0;
1306 }
1307
1308 size_t remaining = sizeof (waveform_buffer) - have;
1309 size_t copy = size;
1310
1311 if (copy > remaining)
1312 {
1313 waveform_buffer_break = copy - remaining;
1314 copy = remaining;
1315 }
1316
1317 memcpy((void *)waveform_buffer + have, start, copy);
1318
1319 waveform_buffer_have = have + copy;
1320}
1321
1322static void waveform_buffer_reset(void)
1323{
1324 /* only called when callback is off */
1325 waveform_buffer_have = 0;
1326 waveform_buffer_threshold = 0;
1327 waveform_buffer_break = 0;
1328}
1329
1330static void anim_waveform_plot_filled_h(int x, int x_prev,
1331 int vmin, int vmax,
1332 int vmin_prev, int vmax_prev)
1333{
1334 if (vmin != vmax || vmin_prev != vmax_prev)
1335 {
1336 /* Graph compression */
1337 if (vmax > vmin_prev)
1338 vmax = vmin_prev;
1339 else if (vmin < vmax_prev)
1340 vmin = vmax_prev;
1341
1342 rb->lcd_vline(x, vmax, vmin);
1343 }
1344 else
1345 {
1346 /* 1:1 or stretch */
1347 rb->lcd_drawline(x_prev, vmin_prev, x, vmin);
1348 }
1349}
1350
1351static void anim_waveform_plot_lines_h(int x, int x_prev,
1352 int vmin, int vmax,
1353 int vmin_prev, int vmax_prev)
1354{
1355 rb->lcd_drawline(x_prev, vmin_prev, x, vmin);
1356
1357 if (vmax_prev != vmin_prev || vmax != vmin)
1358 rb->lcd_drawline(x_prev, vmax_prev, x, vmax);
1359}
1360
1361static void anim_waveform_plot_pixel_h(int x, int x_prev,
1362 int vmin, int vmax,
1363 int vmin_prev, int vmax_prev)
1364{
1365 rb->lcd_drawpixel(x, vmin);
1366
1367 if (vmax != vmin)
1368 rb->lcd_drawpixel(x, vmax);
1369
1370 (void)x_prev; (void)vmin_prev; (void)vmax_prev;
1371}
1372
1373static long anim_waveform_horizontal(void)
1374{
1375 static void (* const plot[MAX_DRAW])(int, int, int, int, int, int) =
1376 {
1377 [DRAW_FILLED] = anim_waveform_plot_filled_h,
1378 [DRAW_LINE] = anim_waveform_plot_lines_h,
1379 [DRAW_PIXEL] = anim_waveform_plot_pixel_h,
1380 };
1381
1382 long cur_tick = *rb->current_tick;
1383
1384 if (rb->mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_PLAYING)
1385 {
1386 osd_lcd_update_prepare();
1387 rb->lcd_hline(0, LCD_WIDTH-1, 1*LCD_HEIGHT/4);
1388 rb->lcd_hline(0, LCD_WIDTH-1, 3*LCD_HEIGHT/4);
1389 osd_lcd_update();
1390 one_frame_paused = false;
1391 return cur_tick + HZ/5;
1392 }
1393
Michael Sevakisd37bf242013-05-23 13:58:51 -04001394 int count = (mixer_sampr*osc_delay + 100*HZ - 1) / (100*HZ);
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001395
1396 waveform_buffer_set_threshold(count*PCM_SAMPLESIZE);
1397
1398 if (!waveform_buffer_have_enough())
1399 return cur_tick + HZ/100;
1400
1401 one_frame_paused = false;
1402
1403 osd_lcd_update_prepare();
1404
1405 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1406 rb->lcd_fillrect(0, 0, LCD_WIDTH, LCD_HEIGHT);
1407 rb->lcd_set_drawmode(DRMODE_SOLID);
1408#if LCD_DEPTH > 1
1409 rb->lcd_set_foreground(GRAPH_COLOR);
1410#endif
1411
1412 int x = 0, x_prev = count - 1;
1413 int x_step = (LCD_WIDTH-1) / x_prev;
1414 int x_a_step = (LCD_WIDTH-1) - x_step * x_prev;
1415 int x_a = 0;
1416
1417 int idx_step = (count / LCD_WIDTH) * 2;
1418 int idx_a_step = count - idx_step * (LCD_WIDTH/2);
1419 int idx = idx_step, idx_prev = 0;
1420 int idx_a = idx_a_step;
1421
1422 int a_lim = MIN(x_prev, LCD_WIDTH-1);
1423
1424 int lmin, lmin_prev = 0;
1425 int rmin, rmin_prev = 0;
1426 int lmax, lmax_prev = 0;
1427 int rmax, rmax_prev = 0;
1428
1429 if (osc.draw == DRAW_PIXEL)
1430 goto plot_start_noprev; /* Doesn't need previous points */
1431
1432 lmax = lmin = waveform_buffer[0];
1433 rmax = rmin = waveform_buffer[1];
1434
1435 /* Find min-max envelope for interval */
1436 for (int i = 2; i < idx; i += 2)
1437 {
1438 int sl = waveform_buffer[i + 0];
1439 int sr = waveform_buffer[i + 1];
1440
1441 if (sl < lmin)
1442 lmin = sl;
1443 if (sl > lmax)
1444 lmax = sl;
1445
1446 if (sr < rmin)
1447 rmin = sr;
1448 if (sr > rmax)
1449 rmax = sr;
1450 }
1451
1452 lmin = (1*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, lmin);
1453 lmax = (1*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, lmax);
1454 rmin = (3*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, rmin);
1455 rmax = (3*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, rmax);
1456
1457 while (1)
1458 {
1459 x_prev = x;
1460 x += x_step;
1461 x_a += x_a_step;
1462
1463 if (x_a >= a_lim)
1464 {
1465 x_a -= a_lim;
1466 x++;
1467 }
1468
1469 if (x >= LCD_WIDTH)
1470 break;
1471
1472 idx_prev = idx;
1473 idx += idx_step;
1474 idx_a += idx_a_step;
1475
1476 if (idx_a > a_lim)
1477 {
1478 idx_a -= a_lim + 1;
1479 idx += 2;
1480 }
1481
1482 lmin_prev = lmin, lmax_prev = lmax;
1483 rmin_prev = rmin, rmax_prev = rmax;
1484
1485 plot_start_noprev:
1486 lmax = lmin = waveform_buffer[idx_prev + 0];
1487 rmax = rmin = waveform_buffer[idx_prev + 1];
1488
1489 /* Find min-max envelope for interval */
1490 for (int i = idx_prev + 2; i < idx; i += 2)
1491 {
1492 int sl = waveform_buffer[i + 0];
1493 int sr = waveform_buffer[i + 1];
1494
1495 if (sl < lmin)
1496 lmin = sl;
1497 if (sl > lmax)
1498 lmax = sl;
1499
1500 if (sr < rmin)
1501 rmin = sr;
1502 if (sr > rmax)
1503 rmax = sr;
1504 }
1505
1506 lmin = (1*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, lmin);
1507 lmax = (1*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, lmax);
1508 rmin = (3*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, rmin);
1509 rmax = (3*LCD_HEIGHT/4) - WAVEFORM_SCALE_PCM(LCD_HEIGHT/4-1, rmax);
1510
1511 plot[osc.draw](x, x_prev, lmin, lmax, lmin_prev, lmax_prev);
1512 plot[osc.draw](x, x_prev, rmin, rmax, rmin_prev, rmax_prev);
1513 }
1514
1515 waveform_buffer_done();
1516
1517 osd_lcd_update();
1518
1519 long delay = get_next_delay();
Michael Sevakisd37bf242013-05-23 13:58:51 -04001520 return cur_tick + delay - waveform_buffer_have * HZ /
1521 PCM_BYTERATE(mixer_sampr);
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001522}
1523
1524static void anim_waveform_plot_filled_v(int y, int y_prev,
1525 int vmin, int vmax,
1526 int vmin_prev, int vmax_prev)
1527{
1528 if (vmin != vmax || vmin_prev != vmax_prev)
1529 {
1530 /* Graph compression */
1531 if (vmax < vmin_prev)
1532 vmax = vmin_prev;
1533 else if (vmin > vmax_prev)
1534 vmin = vmax_prev;
1535
1536 rb->lcd_hline(vmin, vmax, y);
1537 }
1538 else
1539 {
1540 /* 1:1 or stretch */
1541 rb->lcd_drawline(vmin_prev, y_prev, vmin, y);
1542 }
1543}
1544
1545static void anim_waveform_plot_lines_v(int y, int y_prev,
1546 int vmin, int vmax,
1547 int vmin_prev, int vmax_prev)
1548{
1549 rb->lcd_drawline(vmin_prev, y_prev, vmin, y);
1550
1551 if (vmax_prev != vmin_prev || vmax != vmin)
1552 rb->lcd_drawline(vmax_prev, y_prev, vmax, y);
1553}
1554
1555static void anim_waveform_plot_pixel_v(int y, int y_prev,
1556 int vmin, int vmax,
1557 int vmin_prev, int vmax_prev)
1558{
1559 rb->lcd_drawpixel(vmin, y);
1560
1561 if (vmax != vmin)
1562 rb->lcd_drawpixel(vmax, y);
1563
1564 (void)y_prev; (void)vmin_prev; (void)vmax_prev;
1565}
1566
1567static long anim_waveform_vertical(void)
1568{
1569 static void (* const plot[MAX_DRAW])(int, int, int, int, int, int) =
1570 {
1571 [DRAW_FILLED] = anim_waveform_plot_filled_v,
1572 [DRAW_LINE] = anim_waveform_plot_lines_v,
1573 [DRAW_PIXEL] = anim_waveform_plot_pixel_v,
1574 };
1575
1576 long cur_tick = *rb->current_tick;
1577
1578 if (rb->mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK) != CHANNEL_PLAYING)
1579 {
1580 osd_lcd_update_prepare();
1581 rb->lcd_vline(1*LCD_WIDTH/4, 0, LCD_HEIGHT-1);
1582 rb->lcd_vline(3*LCD_WIDTH/4, 0, LCD_HEIGHT-1);
1583 osd_lcd_update();
1584 one_frame_paused = false;
1585 return cur_tick + HZ/5;
1586 }
1587
Michael Sevakisd37bf242013-05-23 13:58:51 -04001588 int count = (mixer_sampr*osc_delay + 100*HZ - 1) / (100*HZ);
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001589
1590 waveform_buffer_set_threshold(count*PCM_SAMPLESIZE);
1591
1592 if (!waveform_buffer_have_enough())
1593 return cur_tick + HZ/100;
1594
1595 one_frame_paused = false;
1596
1597 osd_lcd_update_prepare();
1598
1599 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1600 rb->lcd_fillrect(0, 0, LCD_WIDTH, LCD_HEIGHT);
1601 rb->lcd_set_drawmode(DRMODE_SOLID);
1602#if LCD_DEPTH > 1
1603 rb->lcd_set_foreground(GRAPH_COLOR);
1604#endif
1605
1606 int y = 0, y_prev = count - 1;
1607 int y_step = (LCD_HEIGHT-1) / y_prev;
1608 int y_a_step = (LCD_HEIGHT-1) - y_step * y_prev;
1609 int y_a = 0;
1610
1611 int idx_step = (count / LCD_HEIGHT) * 2;
1612 int idx_a_step = count - idx_step * (LCD_HEIGHT/2);
1613 int idx = idx_step, idx_prev = 0;
1614 int idx_a = idx_a_step;
1615
1616 int a_lim = MIN(y_prev, LCD_HEIGHT-1);
1617
1618 int lmin, lmin_prev = 0;
1619 int rmin, rmin_prev = 0;
1620 int lmax, lmax_prev = 0;
1621 int rmax, rmax_prev = 0;
1622
1623 if (osc.draw == DRAW_PIXEL)
1624 goto plot_start_noprev; /* Doesn't need previous points */
1625
1626 lmax = lmin = waveform_buffer[0];
1627 rmax = rmin = waveform_buffer[1];
1628
1629 /* Find min-max envelope for interval */
1630 for (int i = 2; i < idx; i += 2)
1631 {
1632 int sl = waveform_buffer[i + 0];
1633 int sr = waveform_buffer[i + 1];
1634
1635 if (sl < lmin)
1636 lmin = sl;
1637 if (sl > lmax)
1638 lmax = sl;
1639
1640 if (sr < rmin)
1641 rmin = sr;
1642 if (sr > rmax)
1643 rmax = sr;
1644 }
1645
1646 lmin = (1*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, lmin);
1647 lmax = (1*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, lmax);
1648 rmin = (3*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, rmin);
1649 rmax = (3*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, rmax);
1650
1651 while (1)
1652 {
1653 y_prev = y;
1654 y += y_step;
1655 y_a += y_a_step;
1656
1657 if (y_a >= a_lim)
1658 {
1659 y_a -= a_lim;
1660 y++;
1661 }
1662
1663 if (y >= LCD_HEIGHT)
1664 break;
1665
1666 idx_prev = idx;
1667 idx += idx_step;
1668 idx_a += idx_a_step;
1669
1670 if (idx_a > a_lim)
1671 {
1672 idx_a -= a_lim + 1;
1673 idx += 2;
1674 }
1675
1676 lmin_prev = lmin, lmax_prev = lmax;
1677 rmin_prev = rmin, rmax_prev = rmax;
1678
1679 plot_start_noprev:
1680 lmax = lmin = waveform_buffer[idx_prev + 0];
1681 rmax = rmin = waveform_buffer[idx_prev + 1];
1682
1683 /* Find min-max envelope for interval */
1684 for (int i = idx_prev + 2; i < idx; i += 2)
1685 {
1686 int sl = waveform_buffer[i + 0];
1687 int sr = waveform_buffer[i + 1];
1688
1689 if (sl < lmin)
1690 lmin = sl;
1691 if (sl > lmax)
1692 lmax = sl;
1693
1694 if (sr < rmin)
1695 rmin = sr;
1696 if (sr > rmax)
1697 rmax = sr;
1698 }
1699
1700 lmin = (1*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, lmin);
1701 lmax = (1*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, lmax);
1702 rmin = (3*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, rmin);
1703 rmax = (3*LCD_WIDTH/4) + WAVEFORM_SCALE_PCM(LCD_WIDTH/4-1, rmax);
1704
1705 plot[osc.draw](y, y_prev, lmin, lmax, lmin_prev, lmax_prev);
1706 plot[osc.draw](y, y_prev, rmin, rmax, rmin_prev, rmax_prev);
1707 }
1708
1709 waveform_buffer_done();
1710
1711 osd_lcd_update();
1712
1713 long delay = get_next_delay();
Michael Sevakisd37bf242013-05-23 13:58:51 -04001714 return cur_tick + delay - waveform_buffer_have * HZ
1715 / PCM_BYTERATE(mixer_sampr);
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001716}
1717
1718static void anim_waveform_exit(void)
1719{
1720 /* Remove any buffer hook */
1721 rb->mixer_channel_set_buffer_hook(PCM_MIXER_CHAN_PLAYBACK, NULL);
1722#ifdef HAVE_SCHEDULER_BOOSTCTRL
1723 /* Remove our boost */
1724 rb->cancel_cpu_boost();
1725#endif
1726}
1727#endif /* OSCILLOSCOPE_GRAPHMODE */
1728
1729static void graphmode_reset(void)
1730{
1731 static long (* const fns[MAX_GRAPH][MAX_OSC])(void) =
1732 {
1733 [GRAPH_PEAKS] =
1734 {
1735 [OSC_HORIZ] = anim_peaks_horizontal,
1736 [OSC_VERT] = anim_peaks_vertical,
1737 },
1738#ifdef OSCILLOSCOPE_GRAPHMODE
1739 [GRAPH_WAVEFORM] =
1740 {
1741 [OSC_HORIZ] = anim_waveform_horizontal,
1742 [OSC_VERT] = anim_waveform_vertical,
1743 },
1744#endif /* OSCILLOSCOPE_GRAPHMODE */
1745 };
1746
1747 /* For peaks view */
1748 last_left = 0;
1749 last_right = 0;
1750 last_pos = 0;
1751 last_tick = *rb->current_tick;
1752 last_delay = 1;
1753
1754 /* General */
1755 osd_lcd_update_prepare();
1756 rb->lcd_clear_display();
1757 osd_lcd_update();
1758
1759 one_frame_paused = true;
1760 osd_set_timeout(paused ? 4*HZ : HZ);
1761 anim_draw = fns[osc.graphmode][osc.orientation];
1762}
1763
1764static void graphmode_pause_unpause(bool paused)
1765{
1766 if (paused)
1767 return;
1768
1769 last_tick = *rb->current_tick;
1770 osd_set_timeout(HZ);
1771 one_frame_paused = false;
1772#ifdef OSCILLOSCOPE_GRAPHMODE
1773 if (osc.graphmode == GRAPH_WAVEFORM)
1774 waveform_buffer_done();
1775#endif /* OSCILLOSCOPE_GRAPHMODE */
1776}
1777
1778static void update_osc_delay(int value)
1779{
1780 osc_delay = osc_delay_tbl[value - 1];
1781 osc_delay_error = 0;
1782}
1783
1784static void graphmode_setup(void)
1785{
1786#ifdef OSCILLOSCOPE_GRAPHMODE
1787 if (osc.graphmode == GRAPH_WAVEFORM)
1788 {
1789 rb->mixer_channel_set_buffer_hook(PCM_MIXER_CHAN_PLAYBACK,
1790 waveform_buffer_callback);
1791#ifdef HAVE_SCHEDULER_BOOSTCTRL
1792 rb->trigger_cpu_boost(); /* Just looks better */
1793#endif
1794 }
1795 else
1796 {
1797 rb->mixer_channel_set_buffer_hook(PCM_MIXER_CHAN_PLAYBACK,
1798 NULL);
1799#ifdef HAVE_SCHEDULER_BOOSTCTRL
1800 rb->cancel_cpu_boost();
1801#endif
1802 waveform_buffer_reset();
1803 }
1804#endif /* OSCILLOSCOPE_GRAPHMODE */
1805
1806 update_osc_delay(osc.speed[osc.graphmode]);
1807 graphmode_reset();
1808}
1809
1810static long oscilloscope_draw(void)
1811{
1812 if (message != -1)
1813 {
1814 osc_osd_show_message((enum osc_message_ids)message, msgval);
1815 message = -1;
1816 }
1817 else
1818 {
1819 osd_monitor_timeout();
1820 }
1821
1822 long delay = HZ/5;
1823
1824 if (!paused || one_frame_paused)
1825 {
1826 delay = anim_draw() - *rb->current_tick;
1827
1828 if (delay > HZ/5)
1829 delay = HZ/5;
1830 }
1831
1832 return delay;
1833}
1834
1835static void osc_cleanup(void)
1836{
Michael Sevakis371c86b2012-12-07 01:50:52 -05001837 osd_destroy();
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001838
1839#ifdef OSCILLOSCOPE_GRAPHMODE
1840 anim_waveform_exit();
1841#endif
1842
Jens Arnoldf9765d32006-03-11 01:13:51 +00001843#if LCD_DEPTH > 1
Jens Arnoldb318b3e2006-03-09 07:52:26 +00001844 rb->lcd_set_foreground(LCD_DEFAULT_FG);
1845 rb->lcd_set_background(LCD_DEFAULT_BG);
Jens Arnoldf9765d32006-03-11 01:13:51 +00001846#endif
Peter D'Hoyecb53e3c2007-08-15 12:42:09 +00001847 /* Turn on backlight timeout (revert to settings) */
Teruaki Kawashima01313d52011-01-24 12:29:16 +00001848 backlight_use_settings();
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001849
1850
1851 /* save settings if changed */
1852 if (rb->memcmp(&osc, &osc_disk, sizeof(osc)))
1853 {
1854 rb->memcpy(&osc_disk, &osc, sizeof(osc));
1855 configfile_save(cfg_filename, disk_config, ARRAYLEN(disk_config),
1856 CFGFILE_VERSION);
1857 }
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001858}
1859
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001860static void osc_setup(void)
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001861{
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001862 atexit(osc_cleanup);
1863 configfile_load(cfg_filename, disk_config, ARRAYLEN(disk_config),
Jens Arnoldf9765d32006-03-11 01:13:51 +00001864 CFGFILE_MINVERSION);
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001865 osc = osc_disk; /* copy to running config */
1866
1867 osc_osd_init();
Jens Arnoldf9765d32006-03-11 01:13:51 +00001868
1869#if LCD_DEPTH > 1
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001870 osd_lcd_update_prepare();
Jens Arnoldf9765d32006-03-11 01:13:51 +00001871 rb->lcd_set_foreground(GRAPH_COLOR);
1872 rb->lcd_set_background(BACKG_COLOR);
Karl Kurbjund6b0c972006-11-15 06:14:27 +00001873 rb->lcd_set_backdrop(NULL);
Jens Arnoldb318b3e2006-03-09 07:52:26 +00001874 rb->lcd_clear_display();
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001875 osd_lcd_update();
Jens Arnoldf9765d32006-03-11 01:13:51 +00001876#endif
Peter D'Hoyecb53e3c2007-08-15 12:42:09 +00001877
Michael Sevakisd37bf242013-05-23 13:58:51 -04001878#ifdef OSCILLOSCOPE_GRAPHMODE
1879 mixer_sampr = rb->mixer_get_frequency();
1880#endif
1881
Peter D'Hoyecb53e3c2007-08-15 12:42:09 +00001882 /* Turn off backlight timeout */
Teruaki Kawashima01313d52011-01-24 12:29:16 +00001883 backlight_ignore_timeout();
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001884 graphmode_setup();
1885}
Peter D'Hoyecb53e3c2007-08-15 12:42:09 +00001886
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001887enum plugin_status plugin_start(const void* parameter)
1888{
1889 bool exit = false;
1890#ifdef NEED_LASTBUTTON
1891 int lastbutton = BUTTON_NONE;
1892#endif
1893
1894 osc_setup();
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001895
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001896 while (!exit)
1897 {
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001898 long delay = oscilloscope_draw();
1899
1900 if (delay <= 0)
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001901 {
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001902 delay = 0;
1903 rb->yield(); /* tmo = 0 won't yield */
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001904 }
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001905
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001906 int button = rb->button_get_w_tmo(delay);
1907
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001908 switch (button)
1909 {
Kevin Ferrare0e027bd2006-06-30 16:43:47 +00001910#ifdef OSCILLOSCOPE_RC_QUIT
1911 case OSCILLOSCOPE_RC_QUIT:
1912#endif
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001913 case OSCILLOSCOPE_QUIT:
1914 exit = true;
1915 break;
1916
Jens Arnoldf9765d32006-03-11 01:13:51 +00001917 case OSCILLOSCOPE_ADVMODE:
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001918#ifdef OSCILLOSCOPE_GRAPHMODE
1919 if (osc.graphmode == GRAPH_WAVEFORM)
1920 break; /* Not applicable */
1921#endif
Jens Arnold37f529c2006-03-11 08:35:45 +00001922 if (++osc.advance >= MAX_ADV)
1923 osc.advance = 0;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001924
1925 osc_popupmsg(OSC_MSG_ADVMODE, osc.advance);
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001926 break;
1927
Jens Arnoldf9765d32006-03-11 01:13:51 +00001928 case OSCILLOSCOPE_DRAWMODE:
1929#ifdef OSCILLOSCOPE_DRAWMODE_PRE
1930 if (lastbutton != OSCILLOSCOPE_DRAWMODE_PRE)
Jens Arnoldb318b3e2006-03-09 07:52:26 +00001931 break;
1932#endif
Jens Arnold37f529c2006-03-11 08:35:45 +00001933 if (++osc.draw >= MAX_DRAW)
1934 osc.draw = 0;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001935
1936 osc_popupmsg(OSC_MSG_DRAWMODE, osc.draw);
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001937 break;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001938
1939 /* Need all keymaps for this (remove extra condition when
1940 completed) */
1941#ifdef OSCILLOSCOPE_GRAPHMODE
1942 case OSCILLOSCOPE_GRAPHMODE:
1943#ifdef OSCILLOSCOPE_GRAPHMODE_PRE
1944 if (lastbutton != OSCILLOSCOPE_GRAPHMODE_PRE)
1945 break;
1946#endif
1947 if (++osc.graphmode >= MAX_GRAPH)
1948 osc.graphmode = 0;
1949
1950 graphmode_setup();
1951
1952 osc_popupmsg(OSC_MSG_GRAPHMODE, osc.graphmode);
1953 break;
1954#endif /* OSCILLOSCOPE_GRAPHMODE */
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001955
1956 case OSCILLOSCOPE_ORIENTATION:
Jens Arnold61e798f2007-04-09 17:03:48 +00001957#ifdef OSCILLOSCOPE_ORIENTATION_PRE
1958 if (lastbutton != OSCILLOSCOPE_ORIENTATION_PRE)
1959 break;
1960#endif
Jens Arnold37f529c2006-03-11 08:35:45 +00001961 if (++osc.orientation >= MAX_OSC)
1962 osc.orientation = 0;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001963
1964 graphmode_reset();
1965 osc_popupmsg(OSC_MSG_ORIENTATION, osc.orientation);
Jens Arnold78e4f4d2006-03-10 00:18:58 +00001966 break;
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001967
1968 case OSCILLOSCOPE_PAUSE:
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001969#ifdef OSCILLOSCOPE_PAUSE_PRE
1970 if (lastbutton != OSCILLOSCOPE_PAUSE_PRE)
1971 break;
1972#endif
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001973 paused = !paused;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001974 graphmode_pause_unpause(paused);
1975 osc_popupmsg(OSC_MSG_PAUSED, paused ? 1 : 0);
Jens Arnolddb14d8e2004-11-07 10:31:39 +00001976 break;
1977
Jens Arnoldb318b3e2006-03-09 07:52:26 +00001978 case OSCILLOSCOPE_SPEED_UP:
1979 case OSCILLOSCOPE_SPEED_UP | BUTTON_REPEAT:
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001980 {
1981 int *val = &osc.speed[osc.graphmode];
1982
1983 if (*val < MAX_SPEED)
1984 ++*val;
1985
1986 update_osc_delay(*val);
1987 osc_popupmsg(OSC_MSG_SPEED, *val);
Jens Arnoldb318b3e2006-03-09 07:52:26 +00001988 break;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001989 }
Jens Arnoldb318b3e2006-03-09 07:52:26 +00001990
1991 case OSCILLOSCOPE_SPEED_DOWN:
1992 case OSCILLOSCOPE_SPEED_DOWN | BUTTON_REPEAT:
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05001993 {
1994 int *val = &osc.speed[osc.graphmode];
1995
1996 if (*val > MIN_SPEED)
1997 --*val;
1998
1999 update_osc_delay(*val);
2000 osc_popupmsg(OSC_MSG_SPEED, *val);
Jens Arnoldb318b3e2006-03-09 07:52:26 +00002001 break;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05002002 }
Jens Arnoldb318b3e2006-03-09 07:52:26 +00002003
Jens Arnolddb14d8e2004-11-07 10:31:39 +00002004 case OSCILLOSCOPE_VOL_UP:
2005 case OSCILLOSCOPE_VOL_UP | BUTTON_REPEAT:
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05002006 {
2007 int vol = rb->global_settings->volume;
2008
Jens Arnoldc80e0c12005-12-17 21:13:30 +00002009 if (vol < rb->sound_max(SOUND_VOLUME))
Jens Arnolddb14d8e2004-11-07 10:31:39 +00002010 {
2011 vol++;
Linus Nielsen Feltzing674eaca2005-04-01 13:41:03 +00002012 rb->sound_set(SOUND_VOLUME, vol);
Jens Arnolddb14d8e2004-11-07 10:31:39 +00002013 rb->global_settings->volume = vol;
2014 }
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05002015
2016 osc_popupmsg(OSC_MSG_VOLUME, vol);
Jens Arnolddb14d8e2004-11-07 10:31:39 +00002017 break;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05002018 }
Jens Arnolddb14d8e2004-11-07 10:31:39 +00002019
2020 case OSCILLOSCOPE_VOL_DOWN:
2021 case OSCILLOSCOPE_VOL_DOWN | BUTTON_REPEAT:
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05002022 {
2023 int vol = rb->global_settings->volume;
2024
Jens Arnoldc80e0c12005-12-17 21:13:30 +00002025 if (vol > rb->sound_min(SOUND_VOLUME))
Jens Arnolddb14d8e2004-11-07 10:31:39 +00002026 {
2027 vol--;
Linus Nielsen Feltzing674eaca2005-04-01 13:41:03 +00002028 rb->sound_set(SOUND_VOLUME, vol);
Jens Arnolddb14d8e2004-11-07 10:31:39 +00002029 rb->global_settings->volume = vol;
2030 }
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05002031
2032 osc_popupmsg(OSC_MSG_VOLUME, vol);
Jens Arnolddb14d8e2004-11-07 10:31:39 +00002033 break;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05002034 }
Jens Arnolddb14d8e2004-11-07 10:31:39 +00002035
2036 default:
Thomas Martitzcae4ae22010-08-24 14:30:46 +00002037 exit_on_usb(button);
Jens Arnolddb14d8e2004-11-07 10:31:39 +00002038 break;
2039 }
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05002040
2041#ifdef NEED_LASTBUTTON
Jens Arnoldb318b3e2006-03-09 07:52:26 +00002042 if (button != BUTTON_NONE)
2043 lastbutton = button;
Andree Buschmann27d153d2011-05-01 14:44:20 +00002044#endif
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05002045 } /* while */
Andree Buschmann27d153d2011-05-01 14:44:20 +00002046
Jens Arnolddb14d8e2004-11-07 10:31:39 +00002047 return PLUGIN_OK;
Michael Sevakis0f8aedb2012-12-02 01:09:44 -05002048 (void)parameter;
Jens Arnolddb14d8e2004-11-07 10:31:39 +00002049}