A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 Pengxuan Liu (Isaac)
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/*
23 00 01 21 22 23 43 44 45 65 66 67 87 88 89 109110111
2400 |-----------|-----------|-----------|-----------|-----------|
2501 | | | | | |
26 |***********|***********|***********|***********|***********|
27 |***********|***********|***********|***********|***********|
2811 | | | | | |
2912 |-----------|-----------|-----------|-----------|-----------|
3013 |-----------|-----------|-----------|-----------|-----------| y1
3114 | | | | | |
32 | | | | | |
3322 | | | | | |
3423 |-----------|-----------|-----------|-----------|-----------| y2
3524 | | | | | |
36 | | | | | |
3732 | | | | | |
3833 |-----------|-----------|-----------|-----------|-----------| y3
3934 | | | | | |
40 | | | | | |
4142 | | | | | |
4243 |-----------|-----------|-----------|-----------|-----------| y4
4344 | | | | | |
44 | | | | | |
4552 | | | | | |
4653 |-----------|-----------|-----------|-----------|-----------| y5
4754 | | | | | |
48 | | | | | |
4962 | | | | | |
5063 |-----------|-----------|-----------|-----------|-----------| y6
51 x0 x1 x2 x3 x4 x5
52*/
53
54/*---------------------------------------------------------------------------
55Features:
56- Scientific number format core code. Support range 10^-999 ~ 10^999
57- Number of significant figures up to 10
58
59Limitations:
60- Right now, only accept "num, operator (+,-,*,/), num, =" input sequence.
61 Input "3, +, 5, -, 2, =", the calculator will only do 5-2 and result = 3
62 You have to input "3, +, 5, =, -, 2, =" to get 3+5-2 = 6
63
64- "*,/" have no priority. Actually you can't input 3+5*2 yet.
65
66User Instructions:
67use arrow button to move cursor, "play" button to select, "off" button to exit
68F1: if typing numbers, it's equal to "Del"; otherwise, equal to "C"
69F2: circle input "+, -, *, /"
70F3: equal to "="
71
72"MR" : load temp memory
73"M+" : add currently display to temp memory
74"C" : reset calculator
75---------------------------------------------------------------------------*/
76
77#include "plugin.h"
78
79#include "math.h"
80
81
82
83
84#define M_TWOPI (M_PI * 2.0)
85
86#define BUTTON_ROWS 5
87#define BUTTON_COLS 5
88
89#define REC_HEIGHT (int)(LCD_HEIGHT / (BUTTON_ROWS + 1))
90#define REC_WIDTH (int)(LCD_WIDTH / BUTTON_COLS)
91
92#define Y_6_POS (LCD_HEIGHT) /* Leave room for the border */
93#define Y_5_POS (Y_6_POS - REC_HEIGHT) /* y5 = 53 */
94#define Y_4_POS (Y_5_POS - REC_HEIGHT) /* y4 = 43 */
95#define Y_3_POS (Y_4_POS - REC_HEIGHT) /* y3 = 33 */
96#define Y_2_POS (Y_3_POS - REC_HEIGHT) /* y2 = 23 */
97#define Y_1_POS (Y_2_POS - REC_HEIGHT) /* y1 = 13 */
98#define Y_0_POS 0 /* y0 = 0 */
99
100#define X_0_POS 0 /* x0 = 0 */
101#define X_1_POS (X_0_POS + REC_WIDTH) /* x1 = 22 */
102#define X_2_POS (X_1_POS + REC_WIDTH) /* x2 = 44 */
103#define X_3_POS (X_2_POS + REC_WIDTH) /* x3 = 66 */
104#define X_4_POS (X_3_POS + REC_WIDTH) /* x4 = 88 */
105#define X_5_POS (X_4_POS + REC_WIDTH) /* x5 = 110, column 111 left blank */
106
107#define SIGN(x) ((x)<0?-1:1)
108#ifndef ABS
109#define ABS(a) (((a) < 0) ? -(a) : (a))
110#endif
111
112/* variable button definitions */
113#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
114 (CONFIG_KEYPAD == IRIVER_H300_PAD)
115#define CALCULATOR_LEFT BUTTON_LEFT
116#define CALCULATOR_RIGHT BUTTON_RIGHT
117#define CALCULATOR_UP BUTTON_UP
118#define CALCULATOR_DOWN BUTTON_DOWN
119#define CALCULATOR_QUIT BUTTON_OFF
120#define CALCULATOR_INPUT BUTTON_SELECT
121#define CALCULATOR_CALC BUTTON_ON
122#define CALCULATOR_OPERATORS BUTTON_MODE
123#define CALCULATOR_CLEAR BUTTON_REC
124
125#define CALCULATOR_RC_QUIT BUTTON_RC_STOP
126
127#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
128 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
129 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
130
131#define CALCULATOR_LEFT BUTTON_LEFT
132#define CALCULATOR_RIGHT BUTTON_RIGHT
133#define CALCULATOR_UP_W_SHIFT BUTTON_SCROLL_BACK
134#define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
135#define CALCULATOR_QUIT BUTTON_MENU
136#define CALCULATOR_INPUT BUTTON_SELECT
137#define CALCULATOR_CALC BUTTON_PLAY
138
139#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
140
141#define CALCULATOR_LEFT BUTTON_LEFT
142#define CALCULATOR_RIGHT BUTTON_RIGHT
143#define CALCULATOR_UP BUTTON_UP
144#define CALCULATOR_DOWN BUTTON_DOWN
145#define CALCULATOR_QUIT BUTTON_POWER
146#define CALCULATOR_INPUT BUTTON_SELECT
147#define CALCULATOR_CALC BUTTON_PLAY
148#define CALCULATOR_CLEAR BUTTON_REC
149
150#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
151
152#define CALCULATOR_LEFT BUTTON_LEFT
153#define CALCULATOR_RIGHT BUTTON_RIGHT
154#define CALCULATOR_UP BUTTON_UP
155#define CALCULATOR_DOWN BUTTON_DOWN
156#define CALCULATOR_QUIT BUTTON_POWER
157#define CALCULATOR_INPUT BUTTON_SELECT
158#define CALCULATOR_CALC BUTTON_MENU
159#define CALCULATOR_CLEAR BUTTON_A
160
161#elif (CONFIG_KEYPAD == SANSA_E200_PAD)
162#define CALCULATOR_LEFT BUTTON_LEFT
163#define CALCULATOR_RIGHT BUTTON_RIGHT
164#define CALCULATOR_UP BUTTON_UP
165#define CALCULATOR_DOWN BUTTON_DOWN
166#define CALCULATOR_UP_W_SHIFT BUTTON_SCROLL_BACK
167#define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
168#define CALCULATOR_QUIT BUTTON_POWER
169#define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
170#define CALCULATOR_INPUT (BUTTON_SELECT|BUTTON_REL)
171#define CALCULATOR_CALC (BUTTON_SELECT|BUTTON_REPEAT)
172#define CALCULATOR_CLEAR BUTTON_REC
173
174#elif (CONFIG_KEYPAD == SANSA_C200_PAD)
175#define CALCULATOR_LEFT BUTTON_LEFT
176#define CALCULATOR_RIGHT BUTTON_RIGHT
177#define CALCULATOR_UP BUTTON_UP
178#define CALCULATOR_DOWN BUTTON_DOWN
179#define CALCULATOR_QUIT BUTTON_POWER
180#define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
181#define CALCULATOR_INPUT (BUTTON_SELECT|BUTTON_REL)
182#define CALCULATOR_CALC (BUTTON_SELECT|BUTTON_REPEAT)
183
184#elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
185#define CALCULATOR_LEFT BUTTON_LEFT
186#define CALCULATOR_RIGHT BUTTON_RIGHT
187#define CALCULATOR_UP BUTTON_UP
188#define CALCULATOR_DOWN BUTTON_DOWN
189#define CALCULATOR_UP_W_SHIFT BUTTON_SCROLL_BACK
190#define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
191#define CALCULATOR_QUIT (BUTTON_HOME|BUTTON_REPEAT)
192#define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
193#define CALCULATOR_INPUT (BUTTON_SELECT|BUTTON_REL)
194#define CALCULATOR_CALC (BUTTON_SELECT|BUTTON_REPEAT)
195#define CALCULATOR_CLEAR BUTTON_HOME
196
197
198#elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
199#define CALCULATOR_LEFT BUTTON_LEFT
200#define CALCULATOR_RIGHT BUTTON_RIGHT
201#define CALCULATOR_UP BUTTON_UP
202#define CALCULATOR_DOWN BUTTON_DOWN
203#define CALCULATOR_QUIT BUTTON_POWER
204#define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
205#define CALCULATOR_INPUT (BUTTON_SELECT|BUTTON_REL)
206#define CALCULATOR_CALC (BUTTON_SELECT|BUTTON_REPEAT)
207#define CALCULATOR_CLEAR BUTTON_HOME
208
209#elif (CONFIG_KEYPAD == SANSA_M200_PAD)
210#define CALCULATOR_LEFT BUTTON_LEFT
211#define CALCULATOR_RIGHT BUTTON_RIGHT
212#define CALCULATOR_UP BUTTON_UP
213#define CALCULATOR_DOWN BUTTON_DOWN
214#define CALCULATOR_QUIT BUTTON_POWER
215#define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
216#define CALCULATOR_INPUT (BUTTON_SELECT|BUTTON_REL)
217#define CALCULATOR_CALC (BUTTON_SELECT|BUTTON_REPEAT)
218#define CALCULATOR_CLEAR (BUTTON_SELECT|BUTTON_UP)
219
220#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
221
222#define CALCULATOR_LEFT BUTTON_LEFT
223#define CALCULATOR_RIGHT BUTTON_RIGHT
224#define CALCULATOR_UP BUTTON_SCROLL_UP
225#define CALCULATOR_DOWN BUTTON_SCROLL_DOWN
226#define CALCULATOR_QUIT BUTTON_POWER
227#define CALCULATOR_INPUT_CALC_PRE BUTTON_PLAY
228#define CALCULATOR_INPUT (BUTTON_PLAY | BUTTON_REL)
229#define CALCULATOR_CALC (BUTTON_PLAY | BUTTON_REPEAT)
230#define CALCULATOR_CLEAR BUTTON_REW
231
232#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
233
234#define CALCULATOR_LEFT BUTTON_LEFT
235#define CALCULATOR_RIGHT BUTTON_RIGHT
236#define CALCULATOR_UP BUTTON_UP
237#define CALCULATOR_DOWN BUTTON_DOWN
238#define CALCULATOR_QUIT BUTTON_BACK
239#define CALCULATOR_INPUT BUTTON_SELECT
240#define CALCULATOR_CALC BUTTON_MENU
241#define CALCULATOR_CLEAR BUTTON_PLAY
242
243#elif (CONFIG_KEYPAD == MROBE100_PAD)
244
245#define CALCULATOR_LEFT BUTTON_LEFT
246#define CALCULATOR_RIGHT BUTTON_RIGHT
247#define CALCULATOR_UP BUTTON_UP
248#define CALCULATOR_DOWN BUTTON_DOWN
249#define CALCULATOR_QUIT BUTTON_POWER
250#define CALCULATOR_INPUT BUTTON_SELECT
251#define CALCULATOR_CALC BUTTON_MENU
252#define CALCULATOR_CLEAR BUTTON_DISPLAY
253
254#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
255
256#define CALCULATOR_LEFT BUTTON_RC_REW
257#define CALCULATOR_RIGHT BUTTON_RC_FF
258#define CALCULATOR_UP BUTTON_RC_VOL_UP
259#define CALCULATOR_DOWN BUTTON_RC_VOL_DOWN
260#define CALCULATOR_QUIT BUTTON_RC_REC
261#define CALCULATOR_INPUT BUTTON_RC_PLAY
262#define CALCULATOR_CALC BUTTON_RC_MODE
263#define CALCULATOR_CLEAR BUTTON_RC_MENU
264
265#define CALCULATOR_RC_QUIT BUTTON_REC
266
267#elif (CONFIG_KEYPAD == COWON_D2_PAD)
268
269#define CALCULATOR_QUIT BUTTON_POWER
270#define CALCULATOR_CLEAR BUTTON_MENU
271
272#elif (CONFIG_KEYPAD == CREATIVEZVM_PAD)
273
274#define CALCULATOR_LEFT BUTTON_LEFT
275#define CALCULATOR_RIGHT BUTTON_RIGHT
276#define CALCULATOR_UP BUTTON_UP
277#define CALCULATOR_DOWN BUTTON_DOWN
278#define CALCULATOR_QUIT BUTTON_BACK
279#define CALCULATOR_INPUT BUTTON_SELECT
280#define CALCULATOR_CALC BUTTON_MENU
281#define CALCULATOR_CLEAR BUTTON_PLAY
282
283#elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD
284
285#define CALCULATOR_LEFT (BUTTON_BACK|BUTTON_REL)
286#define CALCULATOR_RIGHT BUTTON_MENU
287#define CALCULATOR_UP BUTTON_UP
288#define CALCULATOR_DOWN BUTTON_DOWN
289#define CALCULATOR_QUIT BUTTON_POWER
290#define CALCULATOR_INPUT (BUTTON_PLAY|BUTTON_REL)
291#define CALCULATOR_CALC (BUTTON_PLAY|BUTTON_REPEAT)
292#define CALCULATOR_CLEAR (BUTTON_BACK|BUTTON_REPEAT)
293
294#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
295
296#define CALCULATOR_LEFT BUTTON_LEFT
297#define CALCULATOR_RIGHT BUTTON_RIGHT
298#define CALCULATOR_UP BUTTON_UP
299#define CALCULATOR_DOWN BUTTON_DOWN
300#define CALCULATOR_QUIT BUTTON_POWER
301#define CALCULATOR_INPUT BUTTON_SELECT
302#define CALCULATOR_CALC BUTTON_MENU
303#define CALCULATOR_CLEAR BUTTON_VIEW
304
305#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
306
307#define CALCULATOR_LEFT BUTTON_PREV
308#define CALCULATOR_RIGHT BUTTON_NEXT
309#define CALCULATOR_UP BUTTON_UP
310#define CALCULATOR_DOWN BUTTON_DOWN
311#define CALCULATOR_QUIT BUTTON_POWER
312#define CALCULATOR_INPUT BUTTON_PLAY
313#define CALCULATOR_CALC BUTTON_MENU
314#define CALCULATOR_CLEAR BUTTON_RIGHT
315
316#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
317
318#define CALCULATOR_LEFT BUTTON_PREV
319#define CALCULATOR_RIGHT BUTTON_NEXT
320#define CALCULATOR_UP BUTTON_UP
321#define CALCULATOR_DOWN BUTTON_DOWN
322#define CALCULATOR_QUIT BUTTON_POWER
323#define CALCULATOR_INPUT BUTTON_PLAY
324#define CALCULATOR_CALC BUTTON_MENU
325#define CALCULATOR_CLEAR BUTTON_RIGHT
326
327#elif (CONFIG_KEYPAD == ONDAVX747_PAD)
328
329#define CALCULATOR_QUIT BUTTON_POWER
330#define CALCULATOR_CLEAR BUTTON_MENU
331
332#elif (CONFIG_KEYPAD == ONDAVX777_PAD)
333#define CALCULATOR_QUIT BUTTON_POWER
334
335#elif CONFIG_KEYPAD == MROBE500_PAD
336#define CALCULATOR_QUIT BUTTON_POWER
337
338#elif CONFIG_KEYPAD == SAMSUNG_YH820_PAD
339
340#define CALCULATOR_LEFT BUTTON_LEFT
341#define CALCULATOR_RIGHT BUTTON_RIGHT
342#define CALCULATOR_UP BUTTON_UP
343#define CALCULATOR_DOWN BUTTON_DOWN
344#define CALCULATOR_QUIT (BUTTON_REW|BUTTON_REPEAT)
345#define CALCULATOR_INPUT BUTTON_PLAY
346#define CALCULATOR_CALC BUTTON_FFWD
347#define CALCULATOR_CLEAR (BUTTON_REW|BUTTON_REL)
348#define CALCULATOR_OPERATORS BUTTON_REC
349
350#elif CONFIG_KEYPAD == SAMSUNG_YH92X_PAD
351
352#define CALCULATOR_LEFT BUTTON_LEFT
353#define CALCULATOR_RIGHT BUTTON_RIGHT
354#define CALCULATOR_UP BUTTON_UP
355#define CALCULATOR_DOWN BUTTON_DOWN
356#define CALCULATOR_QUIT (BUTTON_REW|BUTTON_REPEAT)
357#define CALCULATOR_INPUT BUTTON_PLAY
358#define CALCULATOR_CALC BUTTON_FFWD
359#define CALCULATOR_CLEAR (BUTTON_REW|BUTTON_REL)
360
361#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
362
363#define CALCULATOR_LEFT BUTTON_PREV
364#define CALCULATOR_RIGHT BUTTON_NEXT
365#define CALCULATOR_UP BUTTON_UP
366#define CALCULATOR_DOWN BUTTON_DOWN
367#define CALCULATOR_QUIT BUTTON_REC
368#define CALCULATOR_INPUT BUTTON_OK
369#define CALCULATOR_CALC BUTTON_PLAY
370#define CALCULATOR_CLEAR BUTTON_CANCEL
371
372#elif CONFIG_KEYPAD == MPIO_HD200_PAD
373#define CALCULATOR_LEFT BUTTON_REW
374#define CALCULATOR_RIGHT BUTTON_FF
375#define CALCULATOR_QUIT (BUTTON_REC|BUTTON_PLAY)
376#define CALCULATOR_INPUT BUTTON_FUNC
377#define CALCULATOR_CALC BUTTON_PLAY
378#define CALCULATOR_CLEAR BUTTON_REC
379
380#elif CONFIG_KEYPAD == MPIO_HD300_PAD
381#define CALCULATOR_LEFT BUTTON_REW
382#define CALCULATOR_RIGHT BUTTON_FF
383#define CALCULATOR_UP BUTTON_UP
384#define CALCULATOR_DOWN BUTTON_DOWN
385#define CALCULATOR_QUIT (BUTTON_MENU|BUTTON_REPEAT)
386#define CALCULATOR_INPUT BUTTON_ENTER
387#define CALCULATOR_CALC BUTTON_PLAY
388#define CALCULATOR_CLEAR BUTTON_MENU
389
390#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
391#define CALCULATOR_LEFT BUTTON_LEFT
392#define CALCULATOR_RIGHT BUTTON_RIGHT
393#define CALCULATOR_UP BUTTON_UP
394#define CALCULATOR_DOWN BUTTON_DOWN
395#define CALCULATOR_QUIT (BUTTON_BACK|BUTTON_REPEAT)
396#define CALCULATOR_INPUT BUTTON_SELECT
397#define CALCULATOR_CALC BUTTON_PLAYPAUSE
398#define CALCULATOR_CLEAR (BUTTON_BACK|BUTTON_REL)
399
400#elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
401#define CALCULATOR_LEFT BUTTON_LEFT
402#define CALCULATOR_RIGHT BUTTON_RIGHT
403#define CALCULATOR_UP BUTTON_UP
404#define CALCULATOR_DOWN BUTTON_DOWN
405#define CALCULATOR_UP_W_SHIFT BUTTON_SCROLL_BACK
406#define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
407#define CALCULATOR_QUIT BUTTON_POWER
408#define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
409#define CALCULATOR_INPUT (BUTTON_SELECT|BUTTON_REL)
410#define CALCULATOR_CALC BUTTON_NEXT
411#define CALCULATOR_CLEAR BUTTON_PREV
412
413#elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
414
415#define CALCULATOR_LEFT BUTTON_LEFT
416#define CALCULATOR_RIGHT BUTTON_RIGHT
417#define CALCULATOR_UP BUTTON_UP
418#define CALCULATOR_DOWN BUTTON_DOWN
419#define CALCULATOR_QUIT BUTTON_BACK
420#define CALCULATOR_INPUT BUTTON_SELECT
421#define CALCULATOR_CALC BUTTON_MENU
422#define CALCULATOR_CLEAR BUTTON_USER
423
424#elif (CONFIG_KEYPAD == HM60X_PAD)
425
426#define CALCULATOR_LEFT BUTTON_LEFT
427#define CALCULATOR_RIGHT BUTTON_RIGHT
428#define CALCULATOR_UP BUTTON_UP
429#define CALCULATOR_DOWN BUTTON_DOWN
430#define CALCULATOR_QUIT BUTTON_POWER
431#define CALCULATOR_INPUT BUTTON_SELECT
432#define CALCULATOR_CALC (BUTTON_UP|BUTTON_POWER)
433#define CALCULATOR_CLEAR (BUTTON_DOWN|BUTTON_POWER)
434
435#elif (CONFIG_KEYPAD == HM801_PAD)
436
437#define CALCULATOR_LEFT BUTTON_LEFT
438#define CALCULATOR_RIGHT BUTTON_RIGHT
439#define CALCULATOR_UP BUTTON_UP
440#define CALCULATOR_DOWN BUTTON_DOWN
441#define CALCULATOR_QUIT BUTTON_POWER
442#define CALCULATOR_INPUT BUTTON_SELECT
443#define CALCULATOR_CALC BUTTON_PLAY
444#define CALCULATOR_CLEAR BUTTON_PREV
445
446#elif CONFIG_KEYPAD == SONY_NWZ_PAD
447#define CALCULATOR_LEFT BUTTON_LEFT
448#define CALCULATOR_RIGHT BUTTON_RIGHT
449#define CALCULATOR_UP BUTTON_UP
450#define CALCULATOR_DOWN BUTTON_DOWN
451#define CALCULATOR_QUIT (BUTTON_BACK|BUTTON_REPEAT)
452#define CALCULATOR_INPUT BUTTON_PLAY
453#define CALCULATOR_CALC BUTTON_POWER
454#define CALCULATOR_CLEAR BUTTON_BACK
455
456#elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD
457#define CALCULATOR_LEFT BUTTON_LEFT
458#define CALCULATOR_RIGHT BUTTON_RIGHT
459#define CALCULATOR_UP BUTTON_UP
460#define CALCULATOR_DOWN BUTTON_DOWN
461#define CALCULATOR_QUIT BUTTON_BACK
462#define CALCULATOR_INPUT BUTTON_SELECT
463#define CALCULATOR_CALC BUTTON_PLAYPAUSE
464#define CALCULATOR_CLEAR BUTTON_SHORTCUT
465
466#elif CONFIG_KEYPAD == DX50_PAD
467#define CALCULATOR_QUIT BUTTON_POWER
468
469#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD
470#define CALCULATOR_QUIT BUTTON_POWER
471#define CALCULATOR_INPUT BUTTON_MENU
472
473#elif CONFIG_KEYPAD == AGPTEK_ROCKER_PAD
474#define CALCULATOR_LEFT BUTTON_LEFT
475#define CALCULATOR_RIGHT BUTTON_RIGHT
476#define CALCULATOR_UP BUTTON_UP
477#define CALCULATOR_DOWN BUTTON_DOWN
478#define CALCULATOR_QUIT BUTTON_POWER
479#define CALCULATOR_INPUT BUTTON_SELECT
480#define CALCULATOR_CALC BUTTON_VOLUP
481#define CALCULATOR_CLEAR (BUTTON_SELECT|BUTTON_REPEAT)
482
483#elif CONFIG_KEYPAD == XDUOO_X3_PAD || CONFIG_KEYPAD == XDUOO_X3II_PAD || CONFIG_KEYPAD == XDUOO_X20_PAD
484#define CALCULATOR_LEFT BUTTON_PREV
485#define CALCULATOR_RIGHT BUTTON_NEXT
486#define CALCULATOR_UP BUTTON_HOME
487#define CALCULATOR_DOWN BUTTON_OPTION
488#define CALCULATOR_QUIT BUTTON_POWER
489#define CALCULATOR_INPUT_CALC_PRE (BUTTON_OPTION|BUTTON_REPEAT)
490#define CALCULATOR_INPUT (BUTTON_PLAY|BUTTON_REL)
491#define CALCULATOR_CALC (BUTTON_PLAY|BUTTON_REPEAT)
492#define CALCULATOR_CLEAR (BUTTON_POWER|BUTTON_REPEAT)
493
494#elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD
495#define CALCULATOR_LEFT BUTTON_PREV
496#define CALCULATOR_RIGHT BUTTON_NEXT
497#define CALCULATOR_UP BUTTON_HOME
498#define CALCULATOR_DOWN BUTTON_OPTION
499#define CALCULATOR_QUIT BUTTON_POWER
500#define CALCULATOR_INPUT_CALC_PRE (BUTTON_OPTION|BUTTON_REPEAT)
501#define CALCULATOR_INPUT (BUTTON_PLAY|BUTTON_REL)
502#define CALCULATOR_CALC (BUTTON_PLAY|BUTTON_REPEAT)
503#define CALCULATOR_CLEAR (BUTTON_POWER|BUTTON_REPEAT)
504
505#elif CONFIG_KEYPAD == IHIFI_770_PAD || CONFIG_KEYPAD == IHIFI_800_PAD
506#define CALCULATOR_LEFT BUTTON_HOME
507#define CALCULATOR_RIGHT BUTTON_VOL_DOWN
508#define CALCULATOR_UP BUTTON_PREV
509#define CALCULATOR_DOWN BUTTON_NEXT
510#define CALCULATOR_QUIT BUTTON_POWER
511#define CALCULATOR_INPUT_CALC_PRE (BUTTON_HOME|BUTTON_REPEAT)
512#define CALCULATOR_INPUT (BUTTON_PLAY|BUTTON_REL)
513#define CALCULATOR_CALC (BUTTON_PLAY|BUTTON_REPEAT)
514#define CALCULATOR_CLEAR (BUTTON_POWER|BUTTON_REPEAT)
515
516#elif CONFIG_KEYPAD == EROSQ_PAD
517#define CALCULATOR_LEFT BUTTON_SCROLL_BACK
518#define CALCULATOR_RIGHT BUTTON_SCROLL_FWD
519#define CALCULATOR_UP BUTTON_PREV
520#define CALCULATOR_DOWN BUTTON_NEXT
521#define CALCULATOR_QUIT BUTTON_POWER
522#define CALCULATOR_INPUT BUTTON_PLAY
523#define CALCULATOR_CALC BUTTON_MENU
524#define CALCULATOR_CLEAR BUTTON_BACK
525
526#elif CONFIG_KEYPAD == FIIO_M3K_PAD
527#define CALCULATOR_LEFT BUTTON_LEFT
528#define CALCULATOR_RIGHT BUTTON_RIGHT
529#define CALCULATOR_UP BUTTON_UP
530#define CALCULATOR_DOWN BUTTON_DOWN
531#define CALCULATOR_QUIT BUTTON_POWER
532#define CALCULATOR_INPUT BUTTON_PLAY
533#define CALCULATOR_CALC BUTTON_MENU
534#define CALCULATOR_CLEAR BUTTON_BACK
535
536#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
537#define CALCULATOR_QUIT BUTTON_POWER
538
539#elif CONFIG_KEYPAD == SDL_PAD
540/* use touchscreen */
541#elif CONFIG_KEYPAD == MA_PAD
542#define CALCULATOR_LEFT BUTTON_LEFT
543#define CALCULATOR_RIGHT BUTTON_RIGHT
544#define CALCULATOR_UP BUTTON_UP
545#define CALCULATOR_DOWN BUTTON_DOWN
546#define CALCULATOR_QUIT (BUTTON_BACK|BUTTON_REPEAT)
547#define CALCULATOR_INPUT BUTTON_PLAY
548#define CALCULATOR_CALC BUTTON_MENU
549#define CALCULATOR_CLEAR BUTTON_BACK
550
551#elif CONFIG_KEYPAD == RG_NANO_PAD
552
553#define CALCULATOR_LEFT BUTTON_LEFT
554#define CALCULATOR_RIGHT BUTTON_RIGHT
555#define CALCULATOR_UP BUTTON_UP
556#define CALCULATOR_DOWN BUTTON_DOWN
557#define CALCULATOR_QUIT BUTTON_START
558#define CALCULATOR_INPUT BUTTON_A
559#define CALCULATOR_CALC BUTTON_X
560#define CALCULATOR_CLEAR BUTTON_B
561
562#else
563#error No keymap defined!
564#endif
565
566#ifdef HAVE_TOUCHSCREEN
567#ifndef CALCULATOR_LEFT
568#define CALCULATOR_LEFT BUTTON_MIDLEFT
569#endif
570#ifndef CALCULATOR_RIGHT
571#define CALCULATOR_RIGHT BUTTON_MIDRIGHT
572#endif
573#ifndef CALCULATOR_UP
574#define CALCULATOR_UP BUTTON_TOPMIDDLE
575#endif
576#ifndef CALCULATOR_DOWN
577#define CALCULATOR_DOWN BUTTON_BOTTOMMIDDLE
578#endif
579#ifndef CALCULATOR_CALC
580#define CALCULATOR_CALC BUTTON_BOTTOMRIGHT
581#endif
582#ifndef CALCULATOR_INPUT
583#define CALCULATOR_INPUT BUTTON_CENTER
584#endif
585#ifndef CALCULATOR_CLEAR
586#define CALCULATOR_CLEAR BUTTON_TOPRIGHT
587#endif
588
589#include "lib/pluginlib_touchscreen.h"
590static struct ts_raster calc_raster = { X_0_POS, Y_1_POS,
591 BUTTON_COLS*REC_WIDTH, BUTTON_ROWS*REC_HEIGHT, REC_WIDTH, REC_HEIGHT };
592#endif
593
594enum {
595 basicButtons,
596 sciButtons
597} buttonGroup;
598
599unsigned char* buttonChar[2][5][5] = {
600 { { "MR" , "M+" , "2nd" , "CE" , "C" },
601 { "7" , "8" , "9" , "/" , "sqr" },
602 { "4" , "5" , "6" , "*" , "x^2" },
603 { "1" , "2" , "3" , "-" , "1/x" },
604 { "0" , "+/-", "." , "+" , "=" } },
605
606 { { "n!" , "PI" , "1st" , "sin" , "asi" },
607 { "7" , "8" , "9" , "cos" , "aco" },
608 { "4" , "5" , "6" , "tan" , "ata" },
609 { "1" , "2" , "3" , "ln" , "e^x" },
610 { "0" , "+/-", "." , "log" , "x^y" } }
611};
612
613enum { btn_MR , btn_M , btn_bas , btn_CE , btn_C ,
614 btn_7 , btn_8 , btn_9 , btn_div , btn_sqr ,
615 btn_4 , btn_5 , btn_6 , btn_time , btn_square ,
616 btn_1 , btn_2 , btn_3 , btn_minus , btn_rec ,
617 btn_0 , btn_sign , btn_dot , btn_add , btn_equal
618 };
619
620enum { sci_fac, sci_pi , sci_sci , sci_sin , sci_asin ,
621 sci_7 , sci_8 , sci_9 , sci_cos , sci_acos ,
622 sci_4 , sci_5 , sci_6 , sci_tan , sci_atan ,
623 sci_1 , sci_2 , sci_3 , sci_ln , sci_exp ,
624 sci_0 , sci_sign , sci_dot , sci_log , sci_xy
625 };
626
627#define MINIMUM 0.000000000001 /* e-12 */
628 /* ^ ^ ^ ^ */
629 /* 123456789abcdef */
630
631#define DIGITLEN 10 /* must <= 10 */
632#define SCIENTIFIC_FORMAT ( power < -(DIGITLEN-3) || power > (DIGITLEN))
633 /* 0.000 00000 0001 */
634 /* ^ ^ ^ ^ ^ ^ */
635 /* DIGITLEN 12345 6789a bcdef */
636 /* power 12 34567 89abc def */
637 /* 10^- 123 45678 9abcd ef */
638
639unsigned char buf[19];/* 18 bytes of output line,
640 buf[0] is operator
641 buf[1] = 'M' if memTemp is not 0
642 buf[2] = ' '
643
644 if SCIENTIFIC_FORMAT
645 buf[2]-buf[12] or buf[3]-buf[13] = result;
646 format X.XXXXXXXX
647 buf[13] or buf[14] -buf[17] = power;
648 format eXXX or e-XXX
649 else
650 buf[3]-buf[6] = ' ';
651 buf[7]-buf[17] = result;
652
653 buf[18] = '\0' */
654
655unsigned char typingbuf[DIGITLEN+2];/* byte 0 is sign or ' ',
656 byte 1~DIGITLEN are num and '.'
657 byte (DIGITLEN+1) is '\0' */
658unsigned char* typingbufPointer = typingbuf;
659
660double result = 0; /* main operand, format 0.xxxxx */
661int power = 0; /* 10^power */
662double modifier = 0.1; /* position of next input */
663double operand = 0; /* second operand, format 0.xxxxx */
664int operandPower = 0; /* 10^power of second operand */
665char oper = ' '; /* operators: + - * / */
666bool operInputted = false; /* false: do calculation first and
667 replace current oper
668 true: just replace current oper */
669
670double memTemp = 0; /* temp memory */
671int memTempPower = 0; /* 10^^power of memTemp */
672
673int btn_row, btn_col; /* current position index for button */
674int prev_btn_row, prev_btn_col; /* previous cursor position */
675#define CAL_BUTTON (btn_row*5+btn_col)
676
677int btn = BUTTON_NONE;
678int lastbtn = BUTTON_NONE;
679
680/* Status of calculator */
681enum {cal_normal, /* 0, normal status, display result */
682 cal_typing, /* 1, currently typing, dot hasn't been typed */
683 cal_dotted, /* 2, currently typing, dot already has been typed. */
684 cal_error,
685 cal_exit,
686 cal_toDo
687} calStatus;
688
689/* constant table for CORDIC algorithm */
690static const double cordicTable[51][2]= {
691 /* pow(2,0) - pow(2,-50) atan(pow(2,0) - atan(pow(2,-50) */
692 {1e+00, 7.853981633974483e-01},
693 {5e-01, 4.636476090008061e-01},
694 {2.5e-01, 2.449786631268641e-01},
695 {1.25e-01, 1.243549945467614e-01},
696 {6.25e-02, 6.241880999595735e-02},
697 {3.125e-02, 3.123983343026828e-02},
698 {1.5625e-02, 1.562372862047683e-02},
699 {7.8125e-03, 7.812341060101111e-03},
700 {3.90625e-03, 3.906230131966972e-03},
701 {1.953125e-03, 1.953122516478819e-03},
702 {9.765625e-04, 9.765621895593195e-04},
703 {4.8828125e-04, 4.882812111948983e-04},
704 {2.44140625e-04, 2.441406201493618e-04},
705 {1.220703125e-04, 1.220703118936702e-04},
706 {6.103515625e-05, 6.103515617420877e-05},
707 {3.0517578125e-05, 3.051757811552610e-05},
708 {1.52587890625e-05, 1.525878906131576e-05},
709 {7.62939453125e-06, 7.629394531101970e-06},
710 {3.814697265625e-06, 3.814697265606496e-06},
711 {1.9073486328125e-06, 1.907348632810187e-06},
712 {9.5367431640625e-07, 9.536743164059608e-07},
713 {4.76837158203125e-07, 4.768371582030888e-07},
714 {2.384185791015625e-07, 2.384185791015580e-07},
715 {1.1920928955078125e-07, 1.192092895507807e-07},
716 {5.9604644775390625e-08, 5.960464477539055e-08},
717 {2.98023223876953125e-08, 2.980232238769530e-08},
718 {1.490116119384765625e-08, 1.490116119384765e-08},
719 {7.450580596923828125e-09, 7.450580596923828e-09},
720 {3.7252902984619140625e-09, 3.725290298461914e-09},
721 {1.86264514923095703125e-09, 1.862645149230957e-09},
722 {9.31322574615478515625e-10, 9.313225746154785e-10},
723 {4.656612873077392578125e-10, 4.656612873077393e-10},
724 {2.3283064365386962890625e-10, 2.328306436538696e-10},
725 {1.16415321826934814453125e-10, 1.164153218269348e-10},
726 {5.82076609134674072265625e-11, 5.820766091346741e-11},
727 {2.910383045673370361328125e-11, 2.910383045673370e-11},
728 {1.4551915228366851806640625e-11, 1.455191522836685e-11},
729 {7.2759576141834259033203125e-12, 7.275957614183426e-12},
730 {3.63797880709171295166015625e-12, 3.637978807091713e-12},
731 {1.818989403545856475830078125e-12, 1.818989403545856e-12},
732 {9.094947017729282379150390625e-13, 9.094947017729282e-13},
733 {4.5474735088646411895751953125e-13, 4.547473508864641e-13},
734 {2.27373675443232059478759765625e-13, 2.273736754432321e-13},
735 {1.136868377216160297393798828125e-13, 1.136868377216160e-13},
736 {5.684341886080801486968994140625e-14, 5.684341886080801e-14},
737 {2.8421709430404007434844970703125e-14, 2.842170943040401e-14},
738 {1.42108547152020037174224853515625e-14, 1.421085471520200e-14},
739 {7.10542735760100185871124267578125e-15, 7.105427357601002e-15},
740 {3.552713678800500929355621337890625e-15, 3.552713678800501e-15},
741 {1.7763568394002504646778106689453125e-15, 1.776356839400250e-15},
742 {8.8817841970012523233890533447265625e-16, 8.881784197001252e-16}
743};
744
745static void doMultiple(double* operandOne, int* powerOne,
746 double operandTwo, int powerTwo);
747static void doAdd (double* operandOne, int* powerOne,
748 double operandTwo, int powerTwo);
749static void doExponent(double* operandOne, int* powerOne,
750 double operandTwo, int powerTwo);
751static void printResult(void);
752static void formatResult(void);
753static void oneOperand(void);
754
755static void drawLines(void);
756static void drawButtons(int group);
757
758#ifndef _WIN32
759double strtod(const char *nptr, char **endptr);
760#endif
761long long atoll(const char *nptr);
762
763/* -----------------------------------------------------------------------
764Standard library function
765----------------------------------------------------------------------- */
766#ifndef _WIN32
767double strtod(const char *nptr, char **endptr)
768{
769 double out;
770 long mantissa;
771 int length=0, end=0;
772 mantissa=atoll(nptr);
773 while(!end)
774 {
775 switch(*nptr)
776 {
777 case '\0':
778 end=1;
779 break;
780 case ',':
781 case '.':
782 case '\'':
783 end=1;
784 /* fallthrough */
785 default:
786 nptr++;
787 }
788 }
789 out=atoll(nptr);
790 while( (*nptr == '0')||(*nptr == '1')||(*nptr == '2')||(*nptr == '3')||(*nptr == '4')||
791 (*nptr == '5')||(*nptr == '6')||(*nptr == '7')||(*nptr == '8')||(*nptr == '9') )
792 {
793 nptr++;
794 length++;
795 }
796 for(;length;length--)
797 out /= 10;
798 out += mantissa;
799 if(endptr != NULL)
800 *endptr=(char *) nptr;
801 return out;
802}
803#endif
804
805// WARNING Unsafe: Use strtoll instead
806long long atoll(const char *nptr)
807{
808 long long result=0;
809 char negative=0;
810 while( (*nptr == ' ') || (*nptr == '\f') || (*nptr == '\n')||
811 (*nptr == '\r') || (*nptr == '\t') || (*nptr == '\v') )
812 nptr++;
813 if(*nptr == '+')
814 nptr++;
815 if(*nptr == '-')
816 {
817 negative++;
818 nptr++;
819 }
820 while (*nptr)
821 {
822 if( (*nptr < '0') || (*nptr > '9') )
823 break;
824 result *=10;
825 result+= (*(nptr++) -'0');
826 }
827 if(negative)
828 result = 0 - result;
829 return result;
830}
831
832/* -----------------------------------------------------------------------
833Handy functions
834----------------------------------------------------------------------- */
835static void cleartypingbuf(void)
836{
837 int k;
838 for( k=1; k<=(DIGITLEN+1); k++)
839 typingbuf[k] = 0;
840 typingbuf[0] = ' ';
841 typingbufPointer = typingbuf+1;
842}
843static void clearbuf(void)
844{
845 int k;
846 for(k=0;k<18;k++)
847 buf[k]=' ';
848 buf[18] = 0;
849}
850static void clearResult(void)
851{
852 result = 0;
853 power = 0;
854 modifier = 0.1;
855}
856
857static void clearInput(void)
858{
859 calStatus = cal_normal;
860 clearResult();
861 cleartypingbuf();
862 rb->lcd_clear_display();
863 drawButtons(buttonGroup);
864 drawLines();
865}
866
867static void clearOperand(void)
868{
869 operand = 0;
870 operandPower = 0;
871}
872
873static void clearMemTemp(void)
874{
875 memTemp = 0;
876 memTempPower = 0;
877}
878
879static void clearOper(void)
880{
881 oper = ' ';
882 operInputted = false;
883}
884
885static void clearMem(void)
886{
887 clearInput();
888 clearMemTemp();
889 clearOperand();
890 clearOper();
891 btn = BUTTON_NONE;
892}
893
894static void switchOperands(void)
895{
896 double tempr = operand;
897 int tempp = operandPower;
898 operand = result;
899 operandPower = power;
900 result = tempr;
901 power = tempp;
902}
903
904static void drawLines(void)
905{
906 int i;
907 rb->lcd_hline(0, LCD_WIDTH, Y_1_POS-1);
908 for (i = 0; i < 5 ; i++)
909 rb->lcd_hline(0, LCD_WIDTH, Y_1_POS+i*REC_HEIGHT);
910 for (i = 0; i < 4 ; i++)
911 rb->lcd_vline(X_1_POS+i*REC_WIDTH, Y_1_POS, LCD_HEIGHT);
912}
913
914static void drawButtons(int group)
915{
916 int i, j, w, h;
917 for (i = 0; i <= 4; i++){
918 for (j = 0; j <= 4; j++){
919 rb->lcd_getstringsize( buttonChar[group][i][j],&w,&h);
920 if (i == btn_row && j == btn_col) /* selected item */
921 rb->lcd_set_drawmode(DRMODE_SOLID);
922 else
923 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
924 rb->lcd_fillrect( X_0_POS + j*REC_WIDTH,
925 Y_1_POS + i*REC_HEIGHT,
926 REC_WIDTH, REC_HEIGHT+1);
927 if (i == btn_row && j == btn_col) /* selected item */
928 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
929 else
930 rb->lcd_set_drawmode(DRMODE_SOLID);
931 rb->lcd_putsxy( X_0_POS + j*REC_WIDTH + (REC_WIDTH - w)/2,
932 Y_1_POS + i*REC_HEIGHT + (REC_HEIGHT - h)/2 + 1,
933 buttonChar[group][i][j] );
934 }
935 }
936 rb->lcd_set_drawmode(DRMODE_SOLID);
937}
938
939/* -----------------------------------------------------------------------
940Initiate calculator
941----------------------------------------------------------------------- */
942static void cal_initial (void)
943{
944 int w,h;
945
946 rb->lcd_getstringsize("2nd",&w,&h);
947 if (w > REC_WIDTH || h > REC_HEIGHT)
948 rb->lcd_setfont(FONT_SYSFIXED);
949
950 rb->lcd_clear_display();
951
952#ifdef CALCULATOR_OPERATORS
953 /* basic operators are available through separate button */
954 buttonGroup = sciButtons;
955#else
956 buttonGroup = basicButtons;
957#endif
958
959 /* initially, invert button "5" */
960 btn_row = 2;
961 btn_col = 1;
962 prev_btn_row = btn_row;
963 prev_btn_col = btn_col;
964 drawButtons(buttonGroup);
965 drawLines();
966 rb->lcd_update();
967
968 /* initial mem and output display*/
969 clearMem();
970 printResult();
971
972 /* clear button queue */
973 rb->button_clear_queue();
974}
975
976/* -----------------------------------------------------------------------
977 mySqrt uses Heron's algorithm, which is the Newtone-Raphson algorhitm
978 in it's private case for sqrt.
979 Thanks BlueChip for his intro text and Dave Straayer for the actual name.
980 ----------------------------------------------------------------------- */
981static double mySqrt(double square)
982{
983 int k = 0;
984 double temp = 0;
985 double root= ABS(square+1)/2;
986
987 while( ABS(root - temp) > MINIMUM ){
988 temp = root;
989 root = (square/temp + temp)/2;
990 k++;
991 if (k>10000) return 0;
992 }
993
994 return root;
995}
996
997/*Uses the sequence sum(x^k/k!) that tends to exp(x)*/
998static double myExp (double x) {
999 unsigned int k=0;
1000 double res=0, xPow=1,fact=1,toAdd;
1001
1002 do {
1003 toAdd = xPow/fact;
1004 res += toAdd;
1005 xPow *= x; //xPow = x^k
1006 k++;
1007 fact*=k; //fact = k!
1008 } while (ABS(toAdd) > MINIMUM && xPow<1e302);
1009 return res;
1010}
1011
1012/*myLn : uses the series ln(a) = 2 * ∑(1/(2n+1) * ((a-1)/(a+1))^(2k+1) )*/
1013static double myLn (double a) {
1014 unsigned int k=1;
1015 double res=0,xPow,xSquare,fract=1,toAdd;
1016
1017 xPow = (a-1)/(a+1);
1018 xSquare = xPow*xPow;
1019
1020 do {
1021 toAdd = fract*xPow;
1022 res += toAdd;
1023 xPow *= xSquare; // ((a-1)/(a+1))^k
1024 k+=2;
1025 fract=1./k;
1026 } while (ABS(toAdd) > MINIMUM);
1027 return res * 2;
1028}
1029
1030
1031/* -----------------------------------------------------------------------
1032 transcendFunc uses CORDIC (COordinate Rotation DIgital Computer) method
1033 transcendFunc can do sin,cos,log,exp,asin,acos,atan
1034 input parameter is angle
1035----------------------------------------------------------------------- */
1036static void transcendFunc(char* func, double* tt, int* ttPower)
1037{
1038 double t = (*tt);
1039 int tPower = *ttPower;
1040 int sign = 1;
1041 int n = 50; /* n <=50, tables are all <= 50 */
1042 int j;
1043 double x,y,z,xt,yt,zt;
1044
1045 if (tPower < -998) {
1046 calStatus = cal_normal;
1047 return;
1048 }
1049 if (tPower > 8) {
1050 calStatus = cal_error;
1051 return;
1052 }
1053 *ttPower = 0;
1054 calStatus = cal_normal;
1055
1056 /* Powerscale */
1057 while (tPower > 0){
1058 t *= 10;
1059 tPower--;
1060 }
1061 while (tPower < 0) {
1062 t /= 10;
1063 tPower++;
1064 }
1065
1066 /* Vectoring mode */
1067 if(func[0] == 'a' || func[0] == 'A') {
1068 if(func[1] == 's' || func[1] == 'S') { /* arcsin */
1069 /* arcsin input must be in [-1, 1] */
1070 if(t < -1.0 || t > 1.0) {
1071 calStatus = cal_error;
1072 return;
1073 }
1074 /* Avoid division by zero */
1075 if(t == 1.0) {
1076 *tt = 90.0; /* arcsin(1) = 90° */
1077 return;
1078 }
1079 if(t == -1.0) {
1080 *tt = -90.0; /* arcsin(-1) = -90° */
1081 return;
1082 }
1083
1084 /* Vectoring mode */
1085 /* Start with vector (sqrt(1-t^2), t) and find its angle */
1086 double magnitude = mySqrt(1.0 - t*t);
1087 x = magnitude;
1088 y = t;
1089 z = 0.0;
1090
1091 /* Vectoring mode: drive y to 0 */
1092 for (j = 1; j < n + 2; j++) {
1093 if(y >= 0) {
1094 /* Rotate clockwise (negative direction) */
1095 xt = x + y * cordicTable[j-1][0];
1096 yt = y - x * cordicTable[j-1][0];
1097 zt = z - cordicTable[j-1][1];
1098 } else {
1099 /* Rotate anticlockwise (positive direction) */
1100 xt = x - y * cordicTable[j-1][0];
1101 yt = y + x * cordicTable[j-1][0];
1102 zt = z + cordicTable[j-1][1];
1103 }
1104 x = xt;
1105 y = yt;
1106 z = zt;
1107 }
1108 *tt = z * 180/M_PI * -1; /* Convert to degrees and invert sign */
1109 return;
1110 }
1111 else if(func[1] == 'c' || func[1] == 'C') { /* arccos */
1112 /* arccos input must be in [-1, 1] */
1113 if(t < -1.0 || t > 1.0) {
1114 calStatus = cal_error;
1115 return;
1116 }
1117 /* For arccos: use arcsin relationship: arccos(t) = π/2 - arcsin(t) */
1118 double arcsin_input = t;
1119 int arcsin_power = 0;
1120
1121 /* Save current function context */
1122 char original_func[3];
1123 strncpy(original_func, func, 3);
1124
1125 transcendFunc("asin", &arcsin_input, &arcsin_power);
1126
1127 if (calStatus == cal_error) {
1128 return;
1129 }
1130
1131 /* arccos(t) = 90° - arcsin(t) */
1132 /* arcsin_input now contains arcsin(t) in degrees */
1133 double arccos_degrees = 90.0 - arcsin_input;
1134 *tt = arccos_degrees;
1135 return;
1136 }
1137 else if(func[1] == 't' || func[1] == 'T') { /* arctan */
1138 /* start with x=1, y=input, z=0 and drive y to 0 */
1139 x = 1.0;
1140 y = t;
1141 z = 0.0;
1142
1143 /* Vectoring mode: drive y to 0 */
1144 for (j=1; j<n+2; j++){
1145 if(y < 0) {
1146 /* Rotate anticlockwise */
1147 xt = x - y*cordicTable[j-1][0];
1148 yt = y + x*cordicTable[j-1][0];
1149 zt = z + cordicTable[j-1][1];
1150 } else {
1151 /* Rotate clockwise */
1152 xt = x + y*cordicTable[j-1][0];
1153 yt = y - x*cordicTable[j-1][0];
1154 zt = z - cordicTable[j-1][1];
1155 }
1156 x = xt; y = yt; z = zt;
1157 }
1158 *tt = z * 180/M_PI * -1; /* Convert back to degrees and invert sign */
1159 return;
1160 }
1161 }
1162
1163 if( func[0] =='s' || func[0] =='S'|| func[0] =='t' || func[0] =='T')
1164 sign = SIGN(t);
1165 else {
1166 /* if( func[0] =='c' || func[0] =='C') */
1167 sign = 1;
1168 }
1169 t = ABS(t);
1170
1171 /* Jump to radians for rotation mode */
1172 t = t * M_PI / 180;
1173
1174 while (tPower > 0){
1175 t *= 10;
1176 tPower--;
1177 }
1178 while (tPower < 0) {
1179 t /= 10;
1180 tPower++;
1181 }
1182 j = 0;
1183 while (t > j*M_TWOPI) {j++;}
1184 t -= (j-1)*M_TWOPI;
1185 if (M_PI_2 < t && t < 3*M_PI_2){
1186 t = M_PI - t;
1187 if (func[0] =='c' || func[0] =='C')
1188 sign = -1;
1189 else if (func[0] =='t' || func[0] =='T')
1190 t*=-1;
1191 }
1192 else if ( 3*M_PI_2 <= t && t <= M_TWOPI)
1193 t -= M_TWOPI;
1194
1195 x = 0.60725293500888; y = 0; z = t;
1196 for (j=1;j<n+2;j++){
1197 xt = x - SIGN(z) * y*cordicTable[j-1][0];
1198 yt = y + SIGN(z) * x*cordicTable[j-1][0];
1199 zt = z - SIGN(z) * cordicTable[j-1][1];
1200 x = xt;
1201 y=yt;
1202 z=zt;
1203 }
1204 if( func[0] =='s' || func[0] =='S') {
1205 *tt = sign*y;
1206 return;
1207 }
1208 else if( func[0] =='c' || func[0] =='C') {
1209 *tt = sign*x;
1210 return;
1211 }
1212 else /*if( func[0] =='t' || func[0] =='T')*/ {
1213 if(t==M_PI_2||t==-M_PI_2){
1214 calStatus = cal_error;
1215 return;
1216 }
1217 else{
1218 *tt = sign*(y/x);
1219 return;
1220 }
1221 }
1222
1223}
1224/* -----------------------------------------------------------------------
1225 add in scientific number format
1226----------------------------------------------------------------------- */
1227static void doAdd (double* operandOne, int* powerOne,
1228 double operandTwo, int powerTwo)
1229{
1230 if ( *powerOne >= powerTwo ){
1231 if (*powerOne - powerTwo <= DIGITLEN+1){
1232 while (powerTwo < *powerOne){
1233 operandTwo /=10;
1234 powerTwo++;
1235 }
1236 *operandOne += operandTwo;
1237 }
1238 /*do nothing if operandTwo is too small*/
1239 }
1240 else{
1241 if (powerTwo - *powerOne <= DIGITLEN+1){
1242 while(powerTwo > *powerOne){
1243 *operandOne /=10;
1244 (*powerOne)++;
1245 }
1246 (*operandOne) += operandTwo;
1247 }
1248 else{/* simply copy operandTwo if operandOne is too small */
1249 *operandOne = operandTwo;
1250 *powerOne = powerTwo;
1251 }
1252 }
1253}
1254/* -----------------------------------------------------------------------
1255multiple in scientific number format
1256----------------------------------------------------------------------- */
1257static void doMultiple(double* operandOne, int* powerOne,
1258 double operandTwo, int powerTwo)
1259{
1260 (*operandOne) *= operandTwo;
1261 (*powerOne) += powerTwo;
1262}
1263
1264/* -----------------------------------------------------------------------
1265exponentiate in scientific number format
1266----------------------------------------------------------------------- */
1267static void doExponent(double* operandOne, int* powerOne,
1268 double operandTwo, int powerTwo)
1269{
1270 char negative=0;
1271 char *lastDigit;
1272 char negativeBuffer[25];
1273 if (*operandOne == 0)
1274 {
1275 if (operandTwo == 0)
1276 {
1277 calStatus=cal_error; // result is undefined
1278 }
1279 else{
1280 *powerOne = 0;
1281 *operandOne = 0;
1282 }
1283 return;
1284 }
1285 if (operandTwo == 0)
1286 {
1287 *powerOne = 1;
1288 *operandOne = 0.1;
1289 return;
1290 }
1291 if (operandTwo < 0)
1292 {
1293 negative+=2;
1294 operandTwo= ABS(operandTwo);
1295 }
1296 if (*operandOne < 0)
1297 {
1298#if MEMORYSIZE < 8
1299 (void)negativeBuffer;
1300 (void)lastDigit;
1301 calStatus=cal_error;
1302 return;
1303#else
1304 if(powerTwo < 0)
1305 {
1306 calStatus=cal_error; // result is imaginary
1307 return;
1308 }
1309
1310 /*Truncate operandTwo to three places past the radix
1311 in order to eliminate floating point artifacts
1312 (function should set error if truncating a non-integer) */
1313 rb->snprintf(negativeBuffer, 25, "%.*f", powerTwo+3, operandTwo);
1314 operandTwo = strtod(negativeBuffer, NULL);
1315
1316 /*Truncate operandTwo to powerTwo digits by way of string
1317 in order to confirm operandTwo *10^powerTwo is an integer*/
1318 rb->snprintf(negativeBuffer, 25, "%.*f", powerTwo, operandTwo);
1319
1320 if(strtod(negativeBuffer, &lastDigit) != operandTwo)
1321 {
1322 calStatus=cal_error; // result is imaginary
1323 return;
1324 }
1325 if(rb->atoi(lastDigit-1) % 2)
1326 negative++;
1327#endif
1328 }
1329 (*operandOne) = myLn(ABS(*operandOne)) + (double) (*powerOne) * 2.302585092994046;
1330 (*powerOne) = 0;
1331 doMultiple(operandOne, powerOne, ABS(operandTwo), powerTwo);
1332 while(*powerOne)
1333 {
1334 if(*powerOne > 0)
1335 {
1336 (*operandOne) *= 10;
1337 (*powerOne) --;
1338 }
1339 else{
1340 (*operandOne) /= 10;
1341 (*powerOne) ++;
1342 }
1343 }
1344 (*operandOne) = myExp(*operandOne);
1345 if(negative & 2)
1346 (*operandOne) = 1/(*operandOne);
1347 if(negative & 1)
1348 *operandOne = -(*operandOne);
1349}
1350
1351/* -----------------------------------------------------------------------
1352Handles all one operand calculations
1353----------------------------------------------------------------------- */
1354static void oneOperand(void)
1355{
1356 int k = 0;
1357
1358 if (buttonGroup == basicButtons){
1359 switch(CAL_BUTTON){
1360 case btn_sqr:
1361 if (result<0)
1362 calStatus = cal_error;
1363 else{
1364 if (power%2 == 1){
1365 result = (mySqrt(result*10))/10;
1366 power = (power+1) / 2;
1367 }
1368 else{
1369 result = mySqrt(result);
1370 power = power / 2;
1371 }
1372 calStatus = cal_normal;
1373 }
1374 break;
1375 case btn_square:
1376 power *= 2;
1377 result *= result;
1378 calStatus = cal_normal;
1379 break;
1380
1381 case btn_rec:
1382 if (result==0)
1383 calStatus = cal_error;
1384 else{
1385 power = -power;
1386 result = 1/result;
1387 calStatus = cal_normal;
1388 }
1389 break;
1390 default:
1391 calStatus = cal_toDo;
1392 break; /* just for the safety */
1393 }
1394 }
1395 else{ /* sciButtons */
1396 switch(CAL_BUTTON){
1397 case sci_sin:
1398 transcendFunc("sin", &result, &power);
1399 break;
1400 case sci_cos:
1401 transcendFunc("cos", &result, &power);
1402 break;
1403 case sci_tan:
1404 transcendFunc("tan", &result, &power);
1405 break;
1406 case sci_asin:
1407 transcendFunc("asin", &result, &power);
1408 break;
1409 case sci_acos:
1410 transcendFunc("acos", &result, &power);
1411 break;
1412 case sci_atan:
1413 transcendFunc("atan", &result, &power);
1414 break;
1415 case sci_fac:
1416 if (power<0 || power>8 || result<0 )
1417 calStatus = cal_error;
1418 else if(result == 0) {
1419 result = 1;
1420 power = 0;
1421 }
1422 else{
1423 while(power > 0) {
1424 result *= 10;
1425 power--;
1426 }
1427 if ( ( result - (int)result) > MINIMUM )
1428 calStatus = cal_error;
1429 else {
1430 k = result; result = 1;
1431 while (k > 1){
1432 doMultiple(&result, &power, k, 0);
1433 formatResult();
1434 k--;
1435 }
1436 calStatus = cal_normal;
1437 }
1438 }
1439 break;
1440 case sci_exp:
1441 /*Uses the sequence (1+a/n)^n -> exp(a) */
1442 if (power>3 || result > 1e3) calStatus = cal_error;
1443 else {
1444 while(power < 0) {
1445 result /= 10;
1446 power++;
1447 }
1448 while (power > 0){
1449 power--;
1450 result*=10;
1451 }
1452 result = myExp(result);
1453 calStatus = cal_normal;
1454 }
1455 break;
1456 case sci_ln:
1457 if (result<=0) calStatus = cal_error;
1458 else {
1459 //ln(a*10^n) = ln(a) + n*ln(10), with ln(10) ≈ 2.30
1460 result = myLn(result) + power * 2.302585092994046;
1461 power=0;
1462 calStatus = cal_normal;
1463 }
1464 break;
1465 case sci_log:
1466 if (result<=0) calStatus = cal_error;
1467 else {
1468 //log10(a+10^n) = ln(a)/ln(10) + n, with ln(10) ≈ 2.30
1469 result = myLn(result)/2.302585092994046 + power;
1470 power=0;
1471 calStatus = cal_normal;
1472 }
1473 break;
1474 default:
1475 calStatus = cal_toDo;
1476 break; /* just for the safety */
1477 }
1478 }
1479}
1480
1481
1482/* -----------------------------------------------------------------------
1483Handles all two operands calculations
1484----------------------------------------------------------------------- */
1485static void twoOperands(void)
1486{
1487 switch(oper){
1488 case '-':
1489 doAdd(&operand, &operandPower, -result, power);
1490 break;
1491 case '+':
1492 doAdd(&operand, &operandPower, result, power);
1493 break;
1494 case '*':
1495 doMultiple(&operand, &operandPower, result, power);
1496 break;
1497 case '/':
1498 if ( ABS(result) > MINIMUM ){
1499 doMultiple(&operand, &operandPower, 1/result, -power);
1500 }
1501 else
1502 calStatus = cal_error;
1503 break;
1504 case '^':
1505 doExponent(&operand, &operandPower, result, power);
1506 break;
1507 default: /* ' ' */
1508 switchOperands(); /* counter switchOperands() below */
1509 break;
1510 } /* switch(oper) */
1511 switchOperands();
1512 clearOper();
1513}
1514
1515/* First, increases *dimen1 by dimen1_delta modulo dimen1_modulo.
1516 If dimen1 wraps, increases *dimen2 by dimen2_delta modulo dimen2_modulo.
1517*/
1518static void move_with_wrap_and_shift(
1519 int *dimen1, int dimen1_delta, int dimen1_modulo,
1520 int *dimen2, int dimen2_delta, int dimen2_modulo)
1521{
1522 bool wrapped = false;
1523
1524 *dimen1 += dimen1_delta;
1525 if (*dimen1 < 0)
1526 {
1527 *dimen1 = dimen1_modulo - 1;
1528 wrapped = true;
1529 }
1530 else if (*dimen1 >= dimen1_modulo)
1531 {
1532 *dimen1 = 0;
1533 wrapped = true;
1534 }
1535
1536 if (wrapped)
1537 {
1538 /* Make the dividend always positive to be sure about the result.
1539 Adding dimen2_modulo does not change it since we do it modulo. */
1540 *dimen2 = (*dimen2 + dimen2_modulo + dimen2_delta) % dimen2_modulo;
1541 }
1542}
1543
1544/* -----------------------------------------------------------------------
1545Print buttons when switching 1st and 2nd
1546int group = {basicButtons, sciButtons}
1547----------------------------------------------------------------------- */
1548static void printButtonGroups(int group)
1549{
1550 drawButtons(group);
1551 drawLines();
1552 rb->lcd_update();
1553}
1554/* -----------------------------------------------------------------------
1555flash the currently marked button
1556----------------------------------------------------------------------- */
1557static void flashButton(void)
1558{
1559 int k, w, h;
1560 for (k=2;k>0;k--)
1561 {
1562 rb->lcd_getstringsize( buttonChar[buttonGroup][btn_row][btn_col],&w,&h);
1563 rb->lcd_set_drawmode(DRMODE_SOLID|(k==1) ? 0 : DRMODE_INVERSEVID);
1564 rb->lcd_fillrect( X_0_POS + btn_col*REC_WIDTH + 1,
1565 Y_1_POS + btn_row*REC_HEIGHT + 1,
1566 REC_WIDTH - 1, REC_HEIGHT - 1);
1567 rb->lcd_putsxy( X_0_POS + btn_col*REC_WIDTH + (REC_WIDTH - w)/2,
1568 Y_1_POS + btn_row*REC_HEIGHT + (REC_HEIGHT - h)/2 +1,
1569 buttonChar[buttonGroup][btn_row][btn_col] );
1570 rb->lcd_update_rect( X_0_POS + btn_col*REC_WIDTH + 1,
1571 Y_1_POS + btn_row*REC_HEIGHT + 1,
1572 REC_WIDTH - 1, REC_HEIGHT - 1);
1573
1574 if (k!= 1)
1575 rb->sleep(HZ/22);
1576
1577 }
1578}
1579
1580/* -----------------------------------------------------------------------
1581pos is the position that needs animation. pos = [1~18]
1582----------------------------------------------------------------------- */
1583#if defined(CALCULATOR_CLEAR) || defined(CALCULATOR_OPERATORS)
1584static void deleteAnimation(int pos)
1585{
1586 int k, w, h, x;
1587 if (pos<1 || pos >18)
1588 return;
1589
1590 rb->lcd_getstringsize("0", &w, &h);
1591 x = (pos==1? 4: LCD_WIDTH - 4 - w);
1592
1593 for (k=0;k<4;k++){
1594 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1595 rb->lcd_fillrect(x, Y_1_POS - h -1, w, h);
1596 rb->lcd_set_drawmode(DRMODE_SOLID);
1597 rb->lcd_fillrect(x + (w*k)/8, Y_1_POS - h -1 + (h*k)/8,
1598 (w*(4-k))/4, (h*(4-k))/4);
1599 rb->lcd_update_rect(x, Y_1_POS - h -1, w, h);
1600 rb->sleep(HZ/32);
1601 }
1602}
1603#endif
1604
1605/* -----------------------------------------------------------------------
1606result may be one of these formats:
16070
1608xxxx.xxxx
16090.xxxx
16100.0000xxxx
1611
1612formatResult() change result to standard format: 0.xxxx
1613if result is close to 0, let it be 0;
1614if result is close to 1, let it be 0.1 and power++;
1615----------------------------------------------------------------------- */
1616static void formatResult(void)
1617{
1618 int resultsign = SIGN(result);
1619 result = ABS(result);
1620 if(result > MINIMUM ){ /* doesn't check power, might have problem
1621 input wouldn't,
1622 + - * / of two formatted number wouldn't.
1623 only a calculation that makes a formatted
1624 number (0.xxxx) less than MINIMUM in only
1625 one operation */
1626
1627 if (result<1){
1628 while( (int)(result*10) == 0 ){
1629 result *= 10;
1630 power--;
1631 modifier *= 10;
1632 }
1633 }
1634 else{ /* result >= 1 */
1635 while( (int)result != 0 ){
1636 result /= 10;
1637 power++;
1638 modifier /= 10;
1639 }
1640 } /* if result<1 */
1641
1642 if (result > (1-MINIMUM)){
1643 result = 0.1;
1644 power++;
1645 modifier /= 10;
1646 }
1647 result *= resultsign;
1648 }
1649 else {
1650 result = 0;
1651 power = 0;
1652 modifier = 0.1;
1653 }
1654}
1655
1656/* -----------------------------------------------------------------------
1657result2typingbuf() outputs standard format result to typingbuf.
1658case SCIENTIFIC_FORMAT, let temppower = 1;
1659case temppower > 0: print '.' in the middle
1660case temppower <= 0: print '.' in the begining
1661----------------------------------------------------------------------- */
1662static void result2typingbuf(void)
1663{
1664 bool haveDot = false;
1665 char tempchar = 0;
1666 int k;
1667 double tempresult = ABS(result); /* positive num makes things simple */
1668
1669 int temppower;
1670 double tempmodifier = 1;
1671 int count;
1672
1673 if(SCIENTIFIC_FORMAT)
1674 temppower = 1; /* output x.xxxx format */
1675 else
1676 temppower = power;
1677
1678 cleartypingbuf();
1679
1680 if(tempresult < MINIMUM){ /* if 0,faster display and avoid complication*/
1681 typingbuf[0] = ' ';
1682 typingbuf[1] = '0';
1683 }
1684 else{ /* tempresult > 0 */
1685 typingbuf[0] = (SIGN(result)<0)?'-':' ';
1686
1687 typingbufPointer = typingbuf;
1688 if(temppower > 0){
1689 for (k = 0; k<DIGITLEN+1 ; k++){
1690 typingbufPointer++;
1691 if(temppower || *(typingbufPointer-1) == '.'){
1692 count = 0;
1693 tempmodifier = tempmodifier/10;
1694 while( (tempresult-tempmodifier*count) >
1695 (tempmodifier-MINIMUM)){
1696 count++;
1697 }
1698 tempresult -= tempmodifier*count;
1699 tempresult = ABS(tempresult);
1700 temppower-- ;
1701 *typingbufPointer = count + '0';
1702 }
1703 else{ /* temppower == 0 */
1704 *typingbufPointer = '.';
1705 haveDot = true;
1706 }
1707 } /* for */
1708 }
1709 else{
1710 haveDot = true;
1711 typingbufPointer++; *typingbufPointer = '0';
1712 typingbufPointer++; *typingbufPointer = '.';
1713 for (k = 2; k<DIGITLEN+1 ; k++){
1714 typingbufPointer++;
1715 count = 0;
1716 if ( (-temppower) < (k-1)){
1717 tempmodifier = tempmodifier/10;
1718 while((tempresult-tempmodifier*count)>(tempmodifier-MINIMUM)){
1719 count++;
1720
1721 }
1722 tempresult -= tempmodifier*count;
1723 tempresult = ABS(tempresult);
1724 temppower-- ;
1725 }
1726 *typingbufPointer = count + '0';
1727 }
1728 }
1729 /* now, typingbufPointer = typingbuf + 16 */
1730 /* backward strip off 0 and '.' */
1731 if (haveDot){
1732 while( (*typingbufPointer == '0') || (*typingbufPointer == '.')){
1733 tempchar = *typingbufPointer;
1734 *typingbufPointer = 0;
1735 typingbufPointer--;
1736 if (tempchar == '.') break;
1737 }
1738 }
1739 typingbuf[DIGITLEN+1] = 0;
1740 } /* else tempresult > 0 */
1741}
1742
1743/* -----------------------------------------------------------------------
1744printResult() generates LCD display.
1745----------------------------------------------------------------------- */
1746static void printResult(void)
1747{
1748 int k, w, h;
1749
1750 char operbuf[3] = {0, 0, 0};
1751
1752 switch_Status:
1753 switch(calStatus){
1754 case cal_exit:
1755 return;
1756 case cal_error:
1757 clearbuf();
1758 rb->snprintf(buf, 19, "%18s","Error");
1759 break;
1760 case cal_toDo:
1761 clearbuf();
1762 rb->snprintf(buf, 19, "%18s","Coming soon ^_* ");
1763 break;
1764
1765 case cal_normal:
1766 formatResult();
1767
1768 if( power > 1000 ){ /* power -1 > 999 */
1769 calStatus = cal_error;
1770 goto switch_Status;
1771 }
1772 if (power < -998 ) /* power -1 < -999 */
1773 clearResult(); /* too small, let it be 0 */
1774
1775 result2typingbuf();
1776 clearbuf();
1777
1778 operbuf[0] = oper;
1779 operbuf[1] = ( ABS(memTemp) > MINIMUM )?'M':' ';
1780 operbuf[2] = '\0';
1781
1782 if(SCIENTIFIC_FORMAT){
1783 /* output format: X.XXXX eXXX */
1784 if(power > -98){ /* power-1 >= -99, eXXX or e-XX */
1785 rb->snprintf(buf, 12, "%11s",typingbuf);
1786 for(k=11;k<=14;k++) buf[k] = ' ';
1787 cleartypingbuf();
1788 rb->snprintf(typingbuf, 5, "e%d",power-1);
1789 rb->snprintf(buf+11, 5, "%4s",typingbuf);
1790 }
1791 else{ /* power-1 <= -100, e-XXX */
1792 rb->snprintf(buf, 12, "%11s",typingbuf);
1793 rb->snprintf(buf+11, 6, "e%d",power-1);
1794 }
1795 }
1796 else{
1797 rb->snprintf(buf, 12, "%11s",typingbuf);
1798 } /* if SCIENTIFIC_FORMAT */
1799 break;
1800 case cal_typing:
1801 case cal_dotted:
1802 clearbuf();
1803 operbuf[0] = oper;
1804 operbuf[1] = ( ABS(memTemp) > MINIMUM )?'M':' ';
1805 rb->snprintf(buf, 12, "%11s",typingbuf);
1806 break;
1807
1808 }
1809
1810 rb->lcd_getstringsize(buf, &w, &h);
1811 rb->screen_clear_area(rb->screens[0], 0, 0, LCD_WIDTH, Y_1_POS - 1);
1812 rb->lcd_putsxy(4, Y_1_POS - h -1, operbuf);
1813 rb->lcd_putsxy(LCD_WIDTH - w - 4, Y_1_POS - h -1, buf);
1814 rb->lcd_update_rect(0, 1, LCD_WIDTH, Y_1_POS);
1815}
1816
1817/* -----------------------------------------------------------------------
1818Process typing buttons: 1-9, '.', sign
1819main operand "result" and typingbuf are processed seperately here.
1820----------------------------------------------------------------------- */
1821static void typingProcess(void){
1822 switch( CAL_BUTTON ){
1823 case btn_sign:
1824 if (calStatus == cal_typing ||
1825 calStatus == cal_dotted)
1826 typingbuf[0] = (typingbuf[0]=='-')?' ':'-';
1827 result = -result;
1828 break;
1829 case btn_dot:
1830 operInputted = false;
1831 switch(calStatus){
1832 case cal_normal:
1833 clearInput();
1834 *typingbufPointer = '0';
1835 typingbufPointer++;
1836 /* Fallthrough */
1837 case cal_typing:
1838 calStatus = cal_dotted;
1839 *typingbufPointer = '.';
1840 if (typingbufPointer != typingbuf+DIGITLEN+1)
1841 typingbufPointer++;
1842 break;
1843 default: /* cal_dotted */
1844 break;
1845 }
1846 break;
1847 default: /* 0-9 */
1848 operInputted = false;
1849 /* normal,0; normal,1-9; typing,0; typing,1-9 */
1850 switch(calStatus){
1851 case cal_normal:
1852 if(CAL_BUTTON == btn_0 )
1853 break; /* first input is 0, ignore */
1854 clearInput();
1855 /*no operator means start a new calculation*/
1856 if (oper ==' ')
1857 clearOperand();
1858 calStatus = cal_typing;
1859 /* go on typing, no break */
1860 /* Intentional fallthrough */
1861 case cal_typing:
1862 case cal_dotted:
1863 switch(CAL_BUTTON){
1864 case btn_0:
1865 *typingbufPointer = '0';
1866 break;
1867 default:
1868 *typingbufPointer=(7+btn_col-3*(btn_row-1))+ '0';
1869 break;
1870 }
1871 if (typingbufPointer!=typingbuf+DIGITLEN+1){
1872 typingbufPointer++;
1873
1874 {/* result processing */
1875 if (calStatus == cal_typing) power++;
1876 if (CAL_BUTTON != btn_0)
1877 result= result +
1878 SIGN(result)*
1879 (7+btn_col-3*(btn_row-1))*modifier;
1880 modifier /= 10;
1881 }
1882 }
1883 else /* last byte always '\0' */
1884 *typingbufPointer = 0;
1885 break;
1886 default: /* cal_error, cal_exit */
1887 break;
1888 }
1889 break; /* default, 0-9 */
1890 } /* switch( CAL_BUTTON ) */
1891}
1892
1893/* -----------------------------------------------------------------------
1894Handle delete operation
1895main operand "result" and typingbuf are processed seperately here.
1896----------------------------------------------------------------------- */
1897#ifdef CALCULATOR_CLEAR
1898static void doDelete(void){
1899 deleteAnimation(18);
1900 switch(calStatus){
1901 case cal_dotted:
1902 if (*(typingbufPointer-1) == '.'){
1903 /* if dotted and deleting '.',
1904 change status and delete '.' below */
1905 calStatus = cal_typing;
1906 }
1907 else{ /* if dotted and not deleting '.',
1908 power stays */
1909 power++; /* counter "power--;" below */
1910 }
1911 case cal_typing:
1912 typingbufPointer--;
1913
1914 {/* result processing */ /* 0-9, '.' */
1915 /* if deleting '.', do nothing */
1916 if ( *typingbufPointer != '.'){
1917 power--;
1918 modifier *= 10;
1919 result = result - SIGN(result)*
1920 ((*typingbufPointer)- '0')*modifier;
1921 }
1922 }
1923
1924 *typingbufPointer = 0;
1925
1926 /* if (only one digit left and it's 0)
1927 or no digit left, change status*/
1928 if ( typingbufPointer == typingbuf+1 ||
1929 ( typingbufPointer == typingbuf+2 &&
1930 *(typingbufPointer-1) == '0' ))
1931 calStatus = cal_normal;
1932 break;
1933 default: /* normal, error, exit */
1934 break;
1935 }
1936}
1937#endif
1938/* -----------------------------------------------------------------------
1939Handle buttons on basic screen
1940----------------------------------------------------------------------- */
1941static void basicButtonsProcess(void){
1942 switch (btn) {
1943 case CALCULATOR_INPUT:
1944 if (calStatus == cal_error && (CAL_BUTTON != btn_C) ) break;
1945 flashButton();
1946 switch( CAL_BUTTON ){
1947 case btn_MR:
1948 operInputted = false;
1949 result = memTemp; power = memTempPower;
1950 calStatus = cal_normal;
1951 break;
1952 case btn_M:
1953 formatResult();
1954 if (memTemp > MINIMUM)
1955 doAdd(&memTemp, &memTempPower, result, power);
1956 else {
1957 /* if result is too small and memTemp = 0,
1958 doAdd will not add */
1959 memTemp = result;
1960 memTempPower = power;
1961 }
1962 calStatus = cal_normal;
1963 break;
1964
1965 case btn_C: clearMem(); break;
1966 case btn_CE: clearInput(); break;
1967
1968 case btn_bas:
1969 buttonGroup = sciButtons;
1970 printButtonGroups(buttonGroup);
1971 break;
1972
1973 /* one operand calculation, may be changed to
1974 like sin, cos, log, etc */
1975 case btn_sqr:
1976 case btn_square:
1977 case btn_rec:
1978 formatResult(); /* not necessary, just for safty */
1979 oneOperand();
1980 break;
1981
1982 case_btn_equal: /* F3 shortkey entrance */
1983 case btn_equal:
1984 formatResult();
1985 calStatus = cal_normal;
1986 operInputted = false;
1987 if (oper != ' ') twoOperands();
1988 break;
1989
1990 case btn_div:
1991 case btn_time:
1992 case btn_minus:
1993 case btn_add:
1994 if(!operInputted) {twoOperands(); operInputted = true;}
1995 oper = buttonChar[basicButtons][btn_row][btn_col][0];
1996#ifdef CALCULATOR_OPERATORS
1997 case_cycle_operators: /* F2 shortkey entrance */
1998#endif
1999 if (calStatus == cal_typing ||
2000 calStatus == cal_dotted)
2001 calStatus = cal_normal;
2002 formatResult();
2003 operand = result;
2004 operandPower = power;
2005
2006 break;
2007
2008 case btn_sign:
2009 case btn_dot:
2010 default: /* 0-9 */
2011 typingProcess();
2012 break;
2013 } /* switch (CAL_BUTTON) */
2014 break;
2015
2016#ifdef CALCULATOR_OPERATORS
2017 case CALCULATOR_OPERATORS:
2018 if (calStatus == cal_error) break;
2019 if (!operInputted) {twoOperands(); operInputted = true;}
2020 switch (oper){
2021 case ' ':
2022 case '/': oper = '+'; flashButton(); break;
2023 case '+': oper = '-'; flashButton(); break;
2024 case '-': oper = '*'; flashButton(); break;
2025 case '*': oper = '/'; flashButton(); break;
2026 }
2027 goto case_cycle_operators;
2028 break;
2029#endif
2030
2031 case CALCULATOR_CALC:
2032 if (calStatus == cal_error) break;
2033 flashButton();
2034 goto case_btn_equal;
2035 break;
2036 default: break;
2037 }
2038 printResult();
2039}
2040
2041/* -----------------------------------------------------------------------
2042Handle buttons on scientific screen
2043----------------------------------------------------------------------- */
2044static void sciButtonsProcess(void){
2045 switch (btn) {
2046 case CALCULATOR_INPUT:
2047 if (calStatus == cal_error && (CAL_BUTTON != sci_sci) ) break;
2048 flashButton();
2049 switch( CAL_BUTTON ){
2050
2051 case sci_pi:
2052 result = M_PI; power = 0;
2053 calStatus = cal_normal;
2054 break;
2055
2056 case sci_xy:
2057 if(!operInputted) {twoOperands(); operInputted = true;}
2058 oper = '^';
2059 if (calStatus == cal_typing ||
2060 calStatus == cal_dotted)
2061 calStatus = cal_normal;
2062 formatResult();
2063 operand = result;
2064 operandPower = power;
2065 break;
2066
2067 case sci_sci:
2068 buttonGroup = basicButtons;
2069 printButtonGroups(basicButtons);
2070 break;
2071
2072 case sci_fac:
2073 case sci_sin:
2074 case sci_asin:
2075 case sci_cos:
2076 case sci_acos:
2077 case sci_tan:
2078 case sci_atan:
2079 case sci_ln:
2080 case sci_exp:
2081 case sci_log:
2082 formatResult(); /* not necessary, just for safty */
2083 oneOperand();
2084 break;
2085
2086 case btn_sign:
2087 case btn_dot:
2088 default: /* 0-9 */
2089 typingProcess();
2090 break;
2091 } /* switch (CAL_BUTTON) */
2092 break;
2093
2094#ifdef CALCULATOR_OPERATORS
2095 case CALCULATOR_OPERATORS:
2096 if (calStatus == cal_error) break;
2097 if (!operInputted) {twoOperands(); operInputted = true;}
2098 switch (oper){
2099 case ' ': oper = '+'; break;
2100 case '/': oper = '+'; deleteAnimation(1); break;
2101 case '+': oper = '-'; deleteAnimation(1); break;
2102 case '-': oper = '*'; deleteAnimation(1); break;
2103 case '*': oper = '/'; deleteAnimation(1); break;
2104 }
2105 calStatus = cal_normal;
2106 formatResult();
2107 operand = result;
2108 operandPower = power;
2109 break;
2110#endif
2111
2112 case CALCULATOR_CALC:
2113 if (calStatus == cal_error) break;
2114 formatResult();
2115 calStatus = cal_normal;
2116 operInputted = false;
2117 if (oper != ' ') twoOperands();
2118 break;
2119 default: break;
2120 }
2121 printResult();
2122}
2123
2124/* -----------------------------------------------------------------------
2125move button index
2126Invert display new button, invert back previous button
2127----------------------------------------------------------------------- */
2128static int handleButton(int button){
2129 switch(button)
2130 {
2131 case CALCULATOR_INPUT:
2132 case CALCULATOR_CALC:
2133#ifdef CALCULATOR_INPUT_CALC_PRE
2134 if (lastbtn != CALCULATOR_INPUT_CALC_PRE)
2135 break;
2136 /* no unconditional break; here! */
2137#endif
2138#ifdef CALCULATOR_OPERATORS
2139 case CALCULATOR_OPERATORS:
2140#endif
2141 switch(buttonGroup){
2142 case basicButtons:
2143 basicButtonsProcess();
2144 break;
2145 case sciButtons:
2146 sciButtonsProcess();
2147 break;
2148 }
2149 break;
2150
2151#ifdef CALCULATOR_CLEAR
2152 case CALCULATOR_CLEAR:
2153 switch(calStatus){
2154 case cal_typing:
2155 case cal_dotted:
2156 doDelete();
2157 break;
2158 default: /* cal_normal, cal_error, cal_exit */
2159 clearMem();
2160 break;
2161 }
2162 printResult();
2163 break;
2164#endif
2165 case CALCULATOR_LEFT:
2166 case CALCULATOR_LEFT | BUTTON_REPEAT:
2167 move_with_wrap_and_shift(
2168 &btn_col, -1, BUTTON_COLS,
2169 &btn_row, 0, BUTTON_ROWS);
2170 break;
2171
2172 case CALCULATOR_RIGHT:
2173 case CALCULATOR_RIGHT | BUTTON_REPEAT:
2174 move_with_wrap_and_shift(
2175 &btn_col, 1, BUTTON_COLS,
2176 &btn_row, 0, BUTTON_ROWS);
2177 break;
2178
2179#ifdef CALCULATOR_UP
2180 case CALCULATOR_UP:
2181 case CALCULATOR_UP | BUTTON_REPEAT:
2182 move_with_wrap_and_shift(
2183 &btn_row, -1, BUTTON_ROWS,
2184 &btn_col, 0, BUTTON_COLS);
2185 break;
2186#endif
2187#ifdef CALCULATOR_DOWN
2188 case CALCULATOR_DOWN:
2189 case CALCULATOR_DOWN | BUTTON_REPEAT:
2190 move_with_wrap_and_shift(
2191 &btn_row, 1, BUTTON_ROWS,
2192 &btn_col, 0, BUTTON_COLS);
2193 break;
2194#endif
2195
2196#ifdef CALCULATOR_UP_W_SHIFT
2197 case CALCULATOR_UP_W_SHIFT:
2198 case CALCULATOR_UP_W_SHIFT | BUTTON_REPEAT:
2199 move_with_wrap_and_shift(
2200 &btn_row, -1, BUTTON_ROWS,
2201 &btn_col, -1, BUTTON_COLS);
2202 break;
2203#endif
2204#ifdef CALCULATOR_DOWN_W_SHIFT
2205 case CALCULATOR_DOWN_W_SHIFT:
2206 case CALCULATOR_DOWN_W_SHIFT | BUTTON_REPEAT:
2207 move_with_wrap_and_shift(
2208 &btn_row, 1, BUTTON_ROWS,
2209 &btn_col, 1, BUTTON_COLS);
2210 break;
2211#endif
2212#ifdef CALCULATOR_LEFT_W_SHIFT
2213 case CALCULATOR_LEFT_W_SHIFT:
2214 case CALCULATOR_LEFT_W_SHIFT | BUTTON_REPEAT:
2215 move_with_wrap_and_shift(
2216 &btn_col, -1, BUTTON_COLS,
2217 &btn_row, -1, BUTTON_ROWS);
2218 break;
2219#endif
2220#ifdef CALCULATOR_RIGHT_W_SHIFT
2221 case CALCULATOR_RIGHT_W_SHIFT:
2222 case CALCULATOR_RIGHT_W_SHIFT | BUTTON_REPEAT:
2223 move_with_wrap_and_shift(
2224 &btn_col, 1, BUTTON_COLS,
2225 &btn_row, 1, BUTTON_ROWS);
2226 break;
2227#endif
2228#ifdef CALCULATOR_RC_QUIT
2229 case CALCULATOR_RC_QUIT:
2230#endif
2231 case CALCULATOR_QUIT:
2232 return -1;
2233 }
2234
2235 return 0;
2236}
2237
2238/* -----------------------------------------------------------------------
2239Main();
2240----------------------------------------------------------------------- */
2241enum plugin_status plugin_start(const void* parameter)
2242{
2243 (void)parameter;
2244
2245 /* now go ahead and have fun! */
2246
2247#ifdef HAVE_TOUCHSCREEN
2248 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
2249#endif
2250
2251 cal_initial();
2252
2253 while (calStatus != cal_exit ) {
2254 btn = rb->button_get_w_tmo(HZ/2);
2255#ifdef HAVE_TOUCHSCREEN
2256 if(btn & BUTTON_TOUCHSCREEN)
2257 {
2258 struct ts_raster_result res;
2259 if(touchscreen_map_raster(&calc_raster, rb->button_get_data() >> 16,
2260 rb->button_get_data() & 0xffff, &res) == 1)
2261 {
2262 btn_row = res.y;
2263 btn_col = res.x;
2264 drawButtons(buttonGroup);
2265 drawLines();
2266
2267 rb->lcd_update();
2268
2269 prev_btn_row = btn_row;
2270 prev_btn_col = btn_col;
2271 if(btn & BUTTON_REL)
2272 {
2273 btn = CALCULATOR_INPUT;
2274 switch(buttonGroup){
2275 case basicButtons:
2276 basicButtonsProcess();
2277 break;
2278 case sciButtons:
2279 sciButtonsProcess();
2280 break;
2281 }
2282 btn = BUTTON_TOUCHSCREEN;
2283 }
2284 }
2285 }
2286#endif
2287 if (handleButton(btn) == -1)
2288 {
2289 calStatus = cal_exit;
2290 printResult();
2291 }
2292 else
2293 {
2294 drawButtons(buttonGroup);
2295 drawLines();
2296 }
2297
2298 rb->lcd_update();
2299
2300 if(rb->default_event_handler(btn) == SYS_USB_CONNECTED)
2301 return PLUGIN_USB_CONNECTED;
2302
2303 if (btn != BUTTON_NONE)
2304 lastbtn = btn;
2305 } /* while (calStatus != cal_exit ) */
2306
2307 rb->button_clear_queue();
2308 return PLUGIN_OK;
2309}