Bump version numbers for 3.13
[maemo-rb.git] / apps / plugins / calculator.c
blob1e07d23a2e2fe92763b048c3faa0b3994728a6c6
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2004 Pengxuan Liu (Isaac)
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 00 01 21 22 23 43 44 45 65 66 67 87 88 89 109110111
24 00 |-----------|-----------|-----------|-----------|-----------|
25 01 | | | | | |
26 |***********|***********|***********|***********|***********|
27 |***********|***********|***********|***********|***********|
28 11 | | | | | |
29 12 |-----------|-----------|-----------|-----------|-----------|
30 13 |-----------|-----------|-----------|-----------|-----------| y1
31 14 | | | | | |
32 | | | | | |
33 22 | | | | | |
34 23 |-----------|-----------|-----------|-----------|-----------| y2
35 24 | | | | | |
36 | | | | | |
37 32 | | | | | |
38 33 |-----------|-----------|-----------|-----------|-----------| y3
39 34 | | | | | |
40 | | | | | |
41 42 | | | | | |
42 43 |-----------|-----------|-----------|-----------|-----------| y4
43 44 | | | | | |
44 | | | | | |
45 52 | | | | | |
46 53 |-----------|-----------|-----------|-----------|-----------| y5
47 54 | | | | | |
48 | | | | | |
49 62 | | | | | |
50 63 |-----------|-----------|-----------|-----------|-----------| y6
51 x0 x1 x2 x3 x4 x5
54 /*---------------------------------------------------------------------------
55 Features:
56 - Scientific number format core code. Support range 10^-999 ~ 10^999
57 - Number of significant figures up to 10
59 Limitations:
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
64 - "*,/" have no priority. Actually you can't input 3+5*2 yet.
66 User Instructions:
67 use arrow button to move cursor, "play" button to select, "off" button to exit
68 F1: if typing numbers, it's equal to "Del"; otherwise, equal to "C"
69 F2: circle input "+, -, *, /"
70 F3: equal to "="
72 "MR" : load temp memory
73 "M+" : add currently display to temp memory
74 "C" : reset calculator
75 ---------------------------------------------------------------------------*/
77 #include "plugin.h"
79 #include "math.h"
84 #define M_TWOPI (M_PI * 2.0)
86 #define BUTTON_ROWS 5
87 #define BUTTON_COLS 5
89 #define REC_HEIGHT (int)(LCD_HEIGHT / (BUTTON_ROWS + 1))
90 #define REC_WIDTH (int)(LCD_WIDTH / BUTTON_COLS)
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 */
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 */
107 #define SIGN(x) ((x)<0?-1:1)
108 #ifndef ABS
109 #define ABS(a) (((a) < 0) ? -(a) : (a))
110 #endif
112 /* variable button definitions */
113 #if CONFIG_KEYPAD == RECORDER_PAD
114 #define CALCULATOR_LEFT BUTTON_LEFT
115 #define CALCULATOR_RIGHT BUTTON_RIGHT
116 #define CALCULATOR_UP BUTTON_UP
117 #define CALCULATOR_DOWN BUTTON_DOWN
118 #define CALCULATOR_QUIT BUTTON_OFF
119 #define CALCULATOR_INPUT BUTTON_PLAY
120 #define CALCULATOR_CALC BUTTON_F3
121 #define CALCULATOR_OPERATORS BUTTON_F2
122 #define CALCULATOR_CLEAR BUTTON_F1
124 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
125 #define CALCULATOR_LEFT BUTTON_LEFT
126 #define CALCULATOR_RIGHT BUTTON_RIGHT
127 #define CALCULATOR_UP BUTTON_UP
128 #define CALCULATOR_DOWN BUTTON_DOWN
129 #define CALCULATOR_QUIT BUTTON_OFF
130 #define CALCULATOR_INPUT BUTTON_SELECT
131 #define CALCULATOR_CALC BUTTON_F3
132 #define CALCULATOR_OPERATORS BUTTON_F2
133 #define CALCULATOR_CLEAR BUTTON_F1
135 #elif CONFIG_KEYPAD == ONDIO_PAD
136 #define CALCULATOR_LEFT BUTTON_LEFT
137 #define CALCULATOR_RIGHT BUTTON_RIGHT
138 #define CALCULATOR_UP BUTTON_UP
139 #define CALCULATOR_DOWN BUTTON_DOWN
140 #define CALCULATOR_QUIT BUTTON_OFF
141 #define CALCULATOR_INPUT_CALC_PRE BUTTON_MENU
142 #define CALCULATOR_INPUT (BUTTON_MENU | BUTTON_REL)
143 #define CALCULATOR_CALC (BUTTON_MENU | BUTTON_REPEAT)
145 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
146 (CONFIG_KEYPAD == IRIVER_H300_PAD)
147 #define CALCULATOR_LEFT BUTTON_LEFT
148 #define CALCULATOR_RIGHT BUTTON_RIGHT
149 #define CALCULATOR_UP BUTTON_UP
150 #define CALCULATOR_DOWN BUTTON_DOWN
151 #define CALCULATOR_QUIT BUTTON_OFF
152 #define CALCULATOR_INPUT BUTTON_SELECT
153 #define CALCULATOR_CALC BUTTON_ON
154 #define CALCULATOR_OPERATORS BUTTON_MODE
155 #define CALCULATOR_CLEAR BUTTON_REC
157 #define CALCULATOR_RC_QUIT BUTTON_RC_STOP
159 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
160 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
161 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
163 #define CALCULATOR_LEFT BUTTON_LEFT
164 #define CALCULATOR_RIGHT BUTTON_RIGHT
165 #define CALCULATOR_UP_W_SHIFT BUTTON_SCROLL_BACK
166 #define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
167 #define CALCULATOR_QUIT BUTTON_MENU
168 #define CALCULATOR_INPUT BUTTON_SELECT
169 #define CALCULATOR_CALC BUTTON_PLAY
171 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
173 #define CALCULATOR_LEFT BUTTON_LEFT
174 #define CALCULATOR_RIGHT BUTTON_RIGHT
175 #define CALCULATOR_UP BUTTON_UP
176 #define CALCULATOR_DOWN BUTTON_DOWN
177 #define CALCULATOR_QUIT BUTTON_POWER
178 #define CALCULATOR_INPUT BUTTON_SELECT
179 #define CALCULATOR_CALC BUTTON_PLAY
180 #define CALCULATOR_CLEAR BUTTON_REC
182 #elif (CONFIG_KEYPAD == GIGABEAT_PAD)
184 #define CALCULATOR_LEFT BUTTON_LEFT
185 #define CALCULATOR_RIGHT BUTTON_RIGHT
186 #define CALCULATOR_UP BUTTON_UP
187 #define CALCULATOR_DOWN BUTTON_DOWN
188 #define CALCULATOR_QUIT BUTTON_POWER
189 #define CALCULATOR_INPUT BUTTON_SELECT
190 #define CALCULATOR_CALC BUTTON_MENU
191 #define CALCULATOR_CLEAR BUTTON_A
193 #elif (CONFIG_KEYPAD == SANSA_E200_PAD)
194 #define CALCULATOR_LEFT BUTTON_LEFT
195 #define CALCULATOR_RIGHT BUTTON_RIGHT
196 #define CALCULATOR_UP BUTTON_UP
197 #define CALCULATOR_DOWN BUTTON_DOWN
198 #define CALCULATOR_UP_W_SHIFT BUTTON_SCROLL_BACK
199 #define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
200 #define CALCULATOR_QUIT BUTTON_POWER
201 #define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
202 #define CALCULATOR_INPUT (BUTTON_SELECT|BUTTON_REL)
203 #define CALCULATOR_CALC (BUTTON_SELECT|BUTTON_REPEAT)
204 #define CALCULATOR_CLEAR BUTTON_REC
206 #elif (CONFIG_KEYPAD == SANSA_C200_PAD)
207 #define CALCULATOR_LEFT BUTTON_LEFT
208 #define CALCULATOR_RIGHT BUTTON_RIGHT
209 #define CALCULATOR_UP BUTTON_UP
210 #define CALCULATOR_DOWN BUTTON_DOWN
211 #define CALCULATOR_QUIT BUTTON_POWER
212 #define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
213 #define CALCULATOR_INPUT (BUTTON_SELECT|BUTTON_REL)
214 #define CALCULATOR_CALC (BUTTON_SELECT|BUTTON_REPEAT)
216 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
217 #define CALCULATOR_LEFT BUTTON_LEFT
218 #define CALCULATOR_RIGHT BUTTON_RIGHT
219 #define CALCULATOR_UP BUTTON_UP
220 #define CALCULATOR_DOWN BUTTON_DOWN
221 #define CALCULATOR_UP_W_SHIFT BUTTON_SCROLL_BACK
222 #define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
223 #define CALCULATOR_QUIT (BUTTON_HOME|BUTTON_REPEAT)
224 #define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
225 #define CALCULATOR_INPUT (BUTTON_SELECT|BUTTON_REL)
226 #define CALCULATOR_CALC (BUTTON_SELECT|BUTTON_REPEAT)
227 #define CALCULATOR_CLEAR BUTTON_HOME
230 #elif (CONFIG_KEYPAD == SANSA_CLIP_PAD)
231 #define CALCULATOR_LEFT BUTTON_LEFT
232 #define CALCULATOR_RIGHT BUTTON_RIGHT
233 #define CALCULATOR_UP BUTTON_UP
234 #define CALCULATOR_DOWN BUTTON_DOWN
235 #define CALCULATOR_QUIT BUTTON_POWER
236 #define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
237 #define CALCULATOR_INPUT (BUTTON_SELECT|BUTTON_REL)
238 #define CALCULATOR_CALC (BUTTON_SELECT|BUTTON_REPEAT)
239 #define CALCULATOR_CLEAR BUTTON_HOME
241 #elif (CONFIG_KEYPAD == SANSA_M200_PAD)
242 #define CALCULATOR_LEFT BUTTON_LEFT
243 #define CALCULATOR_RIGHT BUTTON_RIGHT
244 #define CALCULATOR_UP BUTTON_UP
245 #define CALCULATOR_DOWN BUTTON_DOWN
246 #define CALCULATOR_QUIT BUTTON_POWER
247 #define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
248 #define CALCULATOR_INPUT (BUTTON_SELECT|BUTTON_REL)
249 #define CALCULATOR_CALC (BUTTON_SELECT|BUTTON_REPEAT)
250 #define CALCULATOR_CLEAR (BUTTON_SELECT|BUTTON_UP)
252 #elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
254 #define CALCULATOR_LEFT BUTTON_LEFT
255 #define CALCULATOR_RIGHT BUTTON_RIGHT
256 #define CALCULATOR_UP BUTTON_SCROLL_UP
257 #define CALCULATOR_DOWN BUTTON_SCROLL_DOWN
258 #define CALCULATOR_QUIT BUTTON_POWER
259 #define CALCULATOR_INPUT_CALC_PRE BUTTON_PLAY
260 #define CALCULATOR_INPUT (BUTTON_PLAY | BUTTON_REL)
261 #define CALCULATOR_CALC (BUTTON_PLAY | BUTTON_REPEAT)
262 #define CALCULATOR_CLEAR BUTTON_REW
264 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
266 #define CALCULATOR_LEFT BUTTON_LEFT
267 #define CALCULATOR_RIGHT BUTTON_RIGHT
268 #define CALCULATOR_UP BUTTON_UP
269 #define CALCULATOR_DOWN BUTTON_DOWN
270 #define CALCULATOR_QUIT BUTTON_BACK
271 #define CALCULATOR_INPUT BUTTON_SELECT
272 #define CALCULATOR_CALC BUTTON_MENU
273 #define CALCULATOR_CLEAR BUTTON_PLAY
275 #elif (CONFIG_KEYPAD == MROBE100_PAD)
277 #define CALCULATOR_LEFT BUTTON_LEFT
278 #define CALCULATOR_RIGHT BUTTON_RIGHT
279 #define CALCULATOR_UP BUTTON_UP
280 #define CALCULATOR_DOWN BUTTON_DOWN
281 #define CALCULATOR_QUIT BUTTON_POWER
282 #define CALCULATOR_INPUT BUTTON_SELECT
283 #define CALCULATOR_CALC BUTTON_MENU
284 #define CALCULATOR_CLEAR BUTTON_DISPLAY
286 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
288 #define CALCULATOR_LEFT BUTTON_RC_REW
289 #define CALCULATOR_RIGHT BUTTON_RC_FF
290 #define CALCULATOR_UP BUTTON_RC_VOL_UP
291 #define CALCULATOR_DOWN BUTTON_RC_VOL_DOWN
292 #define CALCULATOR_QUIT BUTTON_RC_REC
293 #define CALCULATOR_INPUT BUTTON_RC_PLAY
294 #define CALCULATOR_CALC BUTTON_RC_MODE
295 #define CALCULATOR_CLEAR BUTTON_RC_MENU
297 #define CALCULATOR_RC_QUIT BUTTON_REC
299 #elif (CONFIG_KEYPAD == COWON_D2_PAD)
301 #define CALCULATOR_QUIT BUTTON_POWER
302 #define CALCULATOR_CLEAR BUTTON_MENU
304 #elif CONFIG_KEYPAD == IAUDIO67_PAD
306 #define CALCULATOR_LEFT BUTTON_LEFT
307 #define CALCULATOR_RIGHT BUTTON_RIGHT
308 #define CALCULATOR_UP BUTTON_VOLUP
309 #define CALCULATOR_DOWN BUTTON_VOLDOWN
310 #define CALCULATOR_QUIT BUTTON_POWER
311 #define CALCULATOR_INPUT BUTTON_PLAY
312 #define CALCULATOR_CALC BUTTON_MENU
313 #define CALCULATOR_CLEAR BUTTON_STOP
315 #define CALCULATOR_RC_QUIT (BUTTON_MENU|BUTTON_PLAY)
317 #elif (CONFIG_KEYPAD == CREATIVEZVM_PAD)
319 #define CALCULATOR_LEFT BUTTON_LEFT
320 #define CALCULATOR_RIGHT BUTTON_RIGHT
321 #define CALCULATOR_UP BUTTON_UP
322 #define CALCULATOR_DOWN BUTTON_DOWN
323 #define CALCULATOR_QUIT BUTTON_BACK
324 #define CALCULATOR_INPUT BUTTON_SELECT
325 #define CALCULATOR_CALC BUTTON_MENU
326 #define CALCULATOR_CLEAR BUTTON_PLAY
328 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
330 #define CALCULATOR_LEFT BUTTON_LEFT
331 #define CALCULATOR_RIGHT BUTTON_RIGHT
332 #define CALCULATOR_UP BUTTON_UP
333 #define CALCULATOR_DOWN BUTTON_DOWN
334 #define CALCULATOR_QUIT BUTTON_POWER
335 #define CALCULATOR_INPUT BUTTON_SELECT
336 #define CALCULATOR_CALC BUTTON_MENU
337 #define CALCULATOR_CLEAR BUTTON_VIEW
339 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
341 #define CALCULATOR_LEFT BUTTON_PREV
342 #define CALCULATOR_RIGHT BUTTON_NEXT
343 #define CALCULATOR_UP BUTTON_UP
344 #define CALCULATOR_DOWN BUTTON_DOWN
345 #define CALCULATOR_QUIT BUTTON_POWER
346 #define CALCULATOR_INPUT BUTTON_PLAY
347 #define CALCULATOR_CALC BUTTON_MENU
348 #define CALCULATOR_CLEAR BUTTON_RIGHT
350 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
352 #define CALCULATOR_LEFT BUTTON_PREV
353 #define CALCULATOR_RIGHT BUTTON_NEXT
354 #define CALCULATOR_UP BUTTON_UP
355 #define CALCULATOR_DOWN BUTTON_DOWN
356 #define CALCULATOR_QUIT BUTTON_POWER
357 #define CALCULATOR_INPUT BUTTON_PLAY
358 #define CALCULATOR_CALC BUTTON_MENU
359 #define CALCULATOR_CLEAR BUTTON_RIGHT
361 #elif (CONFIG_KEYPAD == ONDAVX747_PAD)
363 #define CALCULATOR_QUIT BUTTON_POWER
364 #define CALCULATOR_CLEAR BUTTON_MENU
366 #elif (CONFIG_KEYPAD == ONDAVX777_PAD)
367 #define CALCULATOR_QUIT BUTTON_POWER
369 #elif CONFIG_KEYPAD == MROBE500_PAD
370 #define CALCULATOR_QUIT BUTTON_POWER
372 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
374 #define CALCULATOR_LEFT BUTTON_LEFT
375 #define CALCULATOR_RIGHT BUTTON_RIGHT
376 #define CALCULATOR_UP BUTTON_UP
377 #define CALCULATOR_DOWN BUTTON_DOWN
378 #define CALCULATOR_QUIT BUTTON_REC
379 #define CALCULATOR_INPUT BUTTON_PLAY
380 #define CALCULATOR_CALC BUTTON_FFWD
381 #define CALCULATOR_CLEAR BUTTON_REW
383 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
385 #define CALCULATOR_LEFT BUTTON_PREV
386 #define CALCULATOR_RIGHT BUTTON_NEXT
387 #define CALCULATOR_UP BUTTON_UP
388 #define CALCULATOR_DOWN BUTTON_DOWN
389 #define CALCULATOR_QUIT BUTTON_REC
390 #define CALCULATOR_INPUT BUTTON_OK
391 #define CALCULATOR_CALC BUTTON_PLAY
392 #define CALCULATOR_CLEAR BUTTON_CANCEL
394 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
395 #define CALCULATOR_LEFT BUTTON_REW
396 #define CALCULATOR_RIGHT BUTTON_FF
397 #define CALCULATOR_QUIT (BUTTON_REC|BUTTON_PLAY)
398 #define CALCULATOR_INPUT BUTTON_FUNC
399 #define CALCULATOR_CALC BUTTON_PLAY
400 #define CALCULATOR_CLEAR BUTTON_REC
402 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
403 #define CALCULATOR_LEFT BUTTON_REW
404 #define CALCULATOR_RIGHT BUTTON_FF
405 #define CALCULATOR_UP BUTTON_UP
406 #define CALCULATOR_DOWN BUTTON_DOWN
407 #define CALCULATOR_QUIT (BUTTON_MENU|BUTTON_REPEAT)
408 #define CALCULATOR_INPUT BUTTON_ENTER
409 #define CALCULATOR_CALC BUTTON_PLAY
410 #define CALCULATOR_CLEAR BUTTON_MENU
412 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
413 #define CALCULATOR_LEFT BUTTON_LEFT
414 #define CALCULATOR_RIGHT BUTTON_RIGHT
415 #define CALCULATOR_UP BUTTON_UP
416 #define CALCULATOR_DOWN BUTTON_DOWN
417 #define CALCULATOR_QUIT BUTTON_POWER
418 #define CALCULATOR_INPUT BUTTON_SELECT
419 #define CALCULATOR_CALC BUTTON_PLAYPAUSE
420 #define CALCULATOR_CLEAR BUTTON_BACK
422 #elif (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
423 #define CALCULATOR_LEFT BUTTON_LEFT
424 #define CALCULATOR_RIGHT BUTTON_RIGHT
425 #define CALCULATOR_UP BUTTON_UP
426 #define CALCULATOR_DOWN BUTTON_DOWN
427 #define CALCULATOR_UP_W_SHIFT BUTTON_SCROLL_BACK
428 #define CALCULATOR_DOWN_W_SHIFT BUTTON_SCROLL_FWD
429 #define CALCULATOR_QUIT BUTTON_POWER
430 #define CALCULATOR_INPUT_CALC_PRE BUTTON_SELECT
431 #define CALCULATOR_INPUT (BUTTON_SELECT|BUTTON_REL)
432 #define CALCULATOR_CALC BUTTON_NEXT
433 #define CALCULATOR_CLEAR BUTTON_PREV
435 #elif (CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
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_BACK
442 #define CALCULATOR_INPUT BUTTON_SELECT
443 #define CALCULATOR_CALC BUTTON_MENU
444 #define CALCULATOR_CLEAR BUTTON_USER
446 #elif (CONFIG_KEYPAD == HM60X_PAD)
448 #define CALCULATOR_LEFT BUTTON_LEFT
449 #define CALCULATOR_RIGHT BUTTON_RIGHT
450 #define CALCULATOR_UP BUTTON_UP
451 #define CALCULATOR_DOWN BUTTON_DOWN
452 #define CALCULATOR_QUIT BUTTON_POWER
453 #define CALCULATOR_INPUT BUTTON_SELECT
454 #define CALCULATOR_CALC (BUTTON_UP|BUTTON_POWER)
455 #define CALCULATOR_CLEAR (BUTTON_DOWN|BUTTON_POWER)
457 #elif (CONFIG_KEYPAD == HM801_PAD)
459 #define CALCULATOR_LEFT BUTTON_LEFT
460 #define CALCULATOR_RIGHT BUTTON_RIGHT
461 #define CALCULATOR_UP BUTTON_UP
462 #define CALCULATOR_DOWN BUTTON_DOWN
463 #define CALCULATOR_QUIT BUTTON_POWER
464 #define CALCULATOR_INPUT BUTTON_SELECT
465 #define CALCULATOR_CALC BUTTON_PLAY
466 #define CALCULATOR_CLEAR BUTTON_PREV
468 #else
469 #error No keymap defined!
470 #endif
472 #ifdef HAVE_TOUCHSCREEN
473 #ifndef CALCULATOR_LEFT
474 #define CALCULATOR_LEFT BUTTON_MIDLEFT
475 #endif
476 #ifndef CALCULATOR_RIGHT
477 #define CALCULATOR_RIGHT BUTTON_MIDRIGHT
478 #endif
479 #ifndef CALCULATOR_UP
480 #define CALCULATOR_UP BUTTON_TOPMIDDLE
481 #endif
482 #ifndef CALCULATOR_DOWN
483 #define CALCULATOR_DOWN BUTTON_BOTTOMMIDDLE
484 #endif
485 #ifndef CALCULATOR_CALC
486 #define CALCULATOR_CALC BUTTON_BOTTOMRIGHT
487 #endif
488 #ifndef CALCULATOR_INPUT
489 #define CALCULATOR_INPUT BUTTON_CENTER
490 #endif
491 #ifndef CALCULATOR_CLEAR
492 #define CALCULATOR_CLEAR BUTTON_TOPRIGHT
493 #endif
495 #include "lib/pluginlib_touchscreen.h"
496 static struct ts_raster calc_raster = { X_0_POS, Y_1_POS,
497 BUTTON_COLS*REC_WIDTH, BUTTON_ROWS*REC_HEIGHT, REC_WIDTH, REC_HEIGHT };
498 #endif
500 enum {
501 basicButtons,
502 sciButtons
503 } buttonGroup;
505 unsigned char* buttonChar[2][5][5] = {
506 { { "MR" , "M+" , "2nd" , "CE" , "C" },
507 { "7" , "8" , "9" , "/" , "sqr" },
508 { "4" , "5" , "6" , "*" , "x^2" },
509 { "1" , "2" , "3" , "-" , "1/x" },
510 { "0" , "+/-", "." , "+" , "=" } },
512 { { "n!" , "PI" , "1st" , "sin" , "asi" },
513 { "7" , "8" , "9" , "cos" , "aco" },
514 { "4" , "5" , "6" , "tan" , "ata" },
515 { "1" , "2" , "3" , "ln" , "e^x" },
516 { "0" , "+/-", "." , "log" , "x^y" } }
519 enum { btn_MR , btn_M , btn_bas , btn_CE , btn_C ,
520 btn_7 , btn_8 , btn_9 , btn_div , btn_sqr ,
521 btn_4 , btn_5 , btn_6 , btn_time , btn_square ,
522 btn_1 , btn_2 , btn_3 , btn_minus , btn_rec ,
523 btn_0 , btn_sign , btn_dot , btn_add , btn_equal
526 enum { sci_fac, sci_pi , sci_sci , sci_sin , sci_asin ,
527 sci_7 , sci_8 , sci_9 , sci_cos , sci_acos ,
528 sci_4 , sci_5 , sci_6 , sci_tan , sci_atan ,
529 sci_1 , sci_2 , sci_3 , sci_ln , sci_exp ,
530 sci_0 , sci_sign , sci_dot , sci_log , sci_xy
533 #define MINIMUM 0.000000000001 /* e-12 */
534 /* ^ ^ ^ ^ */
535 /* 123456789abcdef */
537 #define DIGITLEN 10 /* must <= 10 */
538 #define SCIENTIFIC_FORMAT ( power < -(DIGITLEN-3) || power > (DIGITLEN))
539 /* 0.000 00000 0001 */
540 /* ^ ^ ^ ^ ^ ^ */
541 /* DIGITLEN 12345 6789a bcdef */
542 /* power 12 34567 89abc def */
543 /* 10^- 123 45678 9abcd ef */
545 unsigned char buf[19];/* 18 bytes of output line,
546 buf[0] is operator
547 buf[1] = 'M' if memTemp is not 0
548 buf[2] = ' '
550 if SCIENTIFIC_FORMAT
551 buf[2]-buf[12] or buf[3]-buf[13] = result;
552 format X.XXXXXXXX
553 buf[13] or buf[14] -buf[17] = power;
554 format eXXX or e-XXX
555 else
556 buf[3]-buf[6] = ' ';
557 buf[7]-buf[17] = result;
559 buf[18] = '\0' */
561 unsigned char typingbuf[DIGITLEN+2];/* byte 0 is sign or ' ',
562 byte 1~DIGITLEN are num and '.'
563 byte (DIGITLEN+1) is '\0' */
564 unsigned char* typingbufPointer = typingbuf;
566 double result = 0; /* main operand, format 0.xxxxx */
567 int power = 0; /* 10^power */
568 double modifier = 0.1; /* position of next input */
569 double operand = 0; /* second operand, format 0.xxxxx */
570 int operandPower = 0; /* 10^power of second operand */
571 char oper = ' '; /* operators: + - * / */
572 bool operInputted = false; /* false: do calculation first and
573 replace current oper
574 true: just replace current oper */
576 double memTemp = 0; /* temp memory */
577 int memTempPower = 0; /* 10^^power of memTemp */
579 int btn_row, btn_col; /* current position index for button */
580 int prev_btn_row, prev_btn_col; /* previous cursor position */
581 #define CAL_BUTTON (btn_row*5+btn_col)
583 int btn = BUTTON_NONE;
584 int lastbtn = BUTTON_NONE;
586 /* Status of calculator */
587 enum {cal_normal, /* 0, normal status, display result */
588 cal_typing, /* 1, currently typing, dot hasn't been typed */
589 cal_dotted, /* 2, currently typing, dot already has been typed. */
590 cal_error,
591 cal_exit,
592 cal_toDo
593 } calStatus;
595 /* constant table for CORDIC algorithm */
596 static const double cordicTable[51][2]= {
597 /* pow(2,0) - pow(2,-50) atan(pow(2,0) - atan(pow(2,-50) */
598 {1e+00, 7.853981633974483e-01},
599 {5e-01, 4.636476090008061e-01},
600 {2.5e-01, 2.449786631268641e-01},
601 {1.25e-01, 1.243549945467614e-01},
602 {6.25e-02, 6.241880999595735e-02},
603 {3.125e-02, 3.123983343026828e-02},
604 {1.5625e-02, 1.562372862047683e-02},
605 {7.8125e-03, 7.812341060101111e-03},
606 {3.90625e-03, 3.906230131966972e-03},
607 {1.953125e-03, 1.953122516478819e-03},
608 {9.765625e-04, 9.765621895593195e-04},
609 {4.8828125e-04, 4.882812111948983e-04},
610 {2.44140625e-04, 2.441406201493618e-04},
611 {1.220703125e-04, 1.220703118936702e-04},
612 {6.103515625e-05, 6.103515617420877e-05},
613 {3.0517578125e-05, 3.051757811552610e-05},
614 {1.52587890625e-05, 1.525878906131576e-05},
615 {7.62939453125e-06, 7.629394531101970e-06},
616 {3.814697265625e-06, 3.814697265606496e-06},
617 {1.9073486328125e-06, 1.907348632810187e-06},
618 {9.5367431640625e-07, 9.536743164059608e-07},
619 {4.76837158203125e-07, 4.768371582030888e-07},
620 {2.384185791015625e-07, 2.384185791015580e-07},
621 {1.1920928955078125e-07, 1.192092895507807e-07},
622 {5.9604644775390625e-08, 5.960464477539055e-08},
623 {2.98023223876953125e-08, 2.980232238769530e-08},
624 {1.490116119384765625e-08, 1.490116119384765e-08},
625 {7.450580596923828125e-09, 7.450580596923828e-09},
626 {3.7252902984619140625e-09, 3.725290298461914e-09},
627 {1.86264514923095703125e-09, 1.862645149230957e-09},
628 {9.31322574615478515625e-10, 9.313225746154785e-10},
629 {4.656612873077392578125e-10, 4.656612873077393e-10},
630 {2.3283064365386962890625e-10, 2.328306436538696e-10},
631 {1.16415321826934814453125e-10, 1.164153218269348e-10},
632 {5.82076609134674072265625e-11, 5.820766091346741e-11},
633 {2.910383045673370361328125e-11, 2.910383045673370e-11},
634 {1.4551915228366851806640625e-11, 1.455191522836685e-11},
635 {7.2759576141834259033203125e-12, 7.275957614183426e-12},
636 {3.63797880709171295166015625e-12, 3.637978807091713e-12},
637 {1.818989403545856475830078125e-12, 1.818989403545856e-12},
638 {9.094947017729282379150390625e-13, 9.094947017729282e-13},
639 {4.5474735088646411895751953125e-13, 4.547473508864641e-13},
640 {2.27373675443232059478759765625e-13, 2.273736754432321e-13},
641 {1.136868377216160297393798828125e-13, 1.136868377216160e-13},
642 {5.684341886080801486968994140625e-14, 5.684341886080801e-14},
643 {2.8421709430404007434844970703125e-14, 2.842170943040401e-14},
644 {1.42108547152020037174224853515625e-14, 1.421085471520200e-14},
645 {7.10542735760100185871124267578125e-15, 7.105427357601002e-15},
646 {3.552713678800500929355621337890625e-15, 3.552713678800501e-15},
647 {1.7763568394002504646778106689453125e-15, 1.776356839400250e-15},
648 {8.8817841970012523233890533447265625e-16, 8.881784197001252e-16}
651 static void doMultiple(double* operandOne, int* powerOne,
652 double operandTwo, int powerTwo);
653 static void doAdd (double* operandOne, int* powerOne,
654 double operandTwo, int powerTwo);
655 static void printResult(void);
656 static void formatResult(void);
657 static void oneOperand(void);
659 static void drawLines(void);
660 static void drawButtons(int group);
662 /* -----------------------------------------------------------------------
663 Handy functions
664 ----------------------------------------------------------------------- */
665 static void cleartypingbuf(void)
667 int k;
668 for( k=1; k<=(DIGITLEN+1); k++)
669 typingbuf[k] = 0;
670 typingbuf[0] = ' ';
671 typingbufPointer = typingbuf+1;
673 static void clearbuf(void)
675 int k;
676 for(k=0;k<18;k++)
677 buf[k]=' ';
678 buf[18] = 0;
680 static void clearResult(void)
682 result = 0;
683 power = 0;
684 modifier = 0.1;
687 static void clearInput(void)
689 calStatus = cal_normal;
690 clearResult();
691 cleartypingbuf();
692 rb->lcd_clear_display();
693 drawButtons(buttonGroup);
694 drawLines();
697 static void clearOperand(void)
699 operand = 0;
700 operandPower = 0;
703 static void clearMemTemp(void)
705 memTemp = 0;
706 memTempPower = 0;
709 static void clearOper(void)
711 oper = ' ';
712 operInputted = false;
715 static void clearMem(void)
717 clearInput();
718 clearMemTemp();
719 clearOperand();
720 clearOper();
721 btn = BUTTON_NONE;
724 static void switchOperands(void)
726 double tempr = operand;
727 int tempp = operandPower;
728 operand = result;
729 operandPower = power;
730 result = tempr;
731 power = tempp;
734 static void drawLines(void)
736 int i;
737 rb->lcd_hline(0, LCD_WIDTH, Y_1_POS-1);
738 for (i = 0; i < 5 ; i++)
739 rb->lcd_hline(0, LCD_WIDTH, Y_1_POS+i*REC_HEIGHT);
740 for (i = 0; i < 4 ; i++)
741 rb->lcd_vline(X_1_POS+i*REC_WIDTH, Y_1_POS, LCD_HEIGHT);
744 static void drawButtons(int group)
746 int i, j, w, h;
747 for (i = 0; i <= 4; i++){
748 for (j = 0; j <= 4; j++){
749 rb->lcd_getstringsize( buttonChar[group][i][j],&w,&h);
750 if (i == btn_row && j == btn_col) /* selected item */
751 rb->lcd_set_drawmode(DRMODE_SOLID);
752 else
753 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
754 rb->lcd_fillrect( X_0_POS + j*REC_WIDTH,
755 Y_1_POS + i*REC_HEIGHT,
756 REC_WIDTH, REC_HEIGHT+1);
757 if (i == btn_row && j == btn_col) /* selected item */
758 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
759 else
760 rb->lcd_set_drawmode(DRMODE_SOLID);
761 rb->lcd_putsxy( X_0_POS + j*REC_WIDTH + (REC_WIDTH - w)/2,
762 Y_1_POS + i*REC_HEIGHT + (REC_HEIGHT - h)/2 + 1,
763 buttonChar[group][i][j] );
766 rb->lcd_set_drawmode(DRMODE_SOLID);
769 /* -----------------------------------------------------------------------
770 Initiate calculator
771 ----------------------------------------------------------------------- */
772 static void cal_initial (void)
774 int w,h;
776 rb->lcd_getstringsize("2nd",&w,&h);
777 if (w > REC_WIDTH || h > REC_HEIGHT)
778 rb->lcd_setfont(FONT_SYSFIXED);
780 rb->lcd_clear_display();
782 #ifdef CALCULATOR_OPERATORS
783 /* basic operators are available through separate button */
784 buttonGroup = sciButtons;
785 #else
786 buttonGroup = basicButtons;
787 #endif
789 /* initially, invert button "5" */
790 btn_row = 2;
791 btn_col = 1;
792 prev_btn_row = btn_row;
793 prev_btn_col = btn_col;
794 drawButtons(buttonGroup);
795 drawLines();
796 rb->lcd_update();
798 /* initial mem and output display*/
799 clearMem();
800 printResult();
802 /* clear button queue */
803 rb->button_clear_queue();
806 /* -----------------------------------------------------------------------
807 mySqrt uses Heron's algorithm, which is the Newtone-Raphson algorhitm
808 in it's private case for sqrt.
809 Thanks BlueChip for his intro text and Dave Straayer for the actual name.
810 ----------------------------------------------------------------------- */
811 static double mySqrt(double square)
813 int k = 0;
814 double temp = 0;
815 double root= ABS(square+1)/2;
817 while( ABS(root - temp) > MINIMUM ){
818 temp = root;
819 root = (square/temp + temp)/2;
820 k++;
821 if (k>10000) return 0;
824 return root;
827 /*Uses the sequence sum(x^k/k!) that tends to exp(x)*/
828 static double myExp (double x) {
829 unsigned int k=0;
830 double res=0, xPow=1,fact=1,toAdd;
832 do {
833 toAdd = xPow/fact;
834 res += toAdd;
835 xPow *= x; //xPow = x^k
836 k++;
837 fact*=k; //fact = k!
838 } while (ABS(toAdd) > MINIMUM && xPow<1e302);
839 return res;
842 /*myLn : uses the series ln⁡(a) = 2 * ∑(1/(2n+1) * ((a-1)/(a+1))^(2k+1) )*/
843 static double myLn (double a) {
844 unsigned int k=1;
845 double res=0,xPow,xSquare,fract=1,toAdd;
847 xPow = (a-1)/(a+1);
848 xSquare = xPow*xPow;
850 do {
851 toAdd = fract*xPow;
852 res += toAdd;
853 xPow *= xSquare; // ((a-1)/(a+1))^k
854 k+=2;
855 fract=1./k;
856 } while (ABS(toAdd) > MINIMUM);
857 return res * 2;
861 /* -----------------------------------------------------------------------
862 transcendFunc uses CORDIC (COordinate Rotation DIgital Computer) method
863 transcendFunc can do sin,cos,log,exp
864 input parameter is angle
865 ----------------------------------------------------------------------- */
866 static void transcendFunc(char* func, double* tt, int* ttPower)
868 double t = (*tt)*M_PI/180; int tPower = *ttPower;
869 int sign = 1;
870 int n = 50; /* n <=50, tables are all <= 50 */
871 int j;
872 double x,y,z,xt,yt,zt;
874 if (tPower < -998) {
875 calStatus = cal_normal;
876 return;
878 if (tPower > 8) {
879 calStatus = cal_error;
880 return;
882 *ttPower = 0;
883 calStatus = cal_normal;
885 if( func[0] =='s' || func[0] =='S'|| func[0] =='t' || func[0] =='T')
886 sign = SIGN(t);
887 else {
888 /* if( func[0] =='c' || func[0] =='C') */
889 sign = 1;
891 t = ABS(t);
893 while (tPower > 0){
894 t *= 10;
895 tPower--;
897 while (tPower < 0) {
898 t /= 10;
899 tPower++;
901 j = 0;
902 while (t > j*M_TWOPI) {j++;}
903 t -= (j-1)*M_TWOPI;
904 if (M_PI_2 < t && t < 3*M_PI_2){
905 t = M_PI - t;
906 if (func[0] =='c' || func[0] =='C')
907 sign = -1;
908 else if (func[0] =='t' || func[0] =='T')
909 t*=-1;
911 else if ( 3*M_PI_2 <= t && t <= M_TWOPI)
912 t -= M_TWOPI;
914 x = 0.60725293500888; y = 0; z = t;
915 for (j=1;j<n+2;j++){
916 xt = x - SIGN(z) * y*cordicTable[j-1][0];
917 yt = y + SIGN(z) * x*cordicTable[j-1][0];
918 zt = z - SIGN(z) * cordicTable[j-1][1];
919 x = xt;
920 y=yt;
921 z=zt;
923 if( func[0] =='s' || func[0] =='S') {
924 *tt = sign*y;
925 return;
927 else if( func[0] =='c' || func[0] =='C') {
928 *tt = sign*x;
929 return;
931 else /*if( func[0] =='t' || func[0] =='T')*/ {
932 if(t==M_PI_2||t==-M_PI_2){
933 calStatus = cal_error;
934 return;
936 else{
937 *tt = sign*(y/x);
938 return;
943 /* -----------------------------------------------------------------------
944 add in scientific number format
945 ----------------------------------------------------------------------- */
946 static void doAdd (double* operandOne, int* powerOne,
947 double operandTwo, int powerTwo)
949 if ( *powerOne >= powerTwo ){
950 if (*powerOne - powerTwo <= DIGITLEN+1){
951 while (powerTwo < *powerOne){
952 operandTwo /=10;
953 powerTwo++;
955 *operandOne += operandTwo;
957 /*do nothing if operandTwo is too small*/
959 else{
960 if (powerTwo - *powerOne <= DIGITLEN+1){
961 while(powerTwo > *powerOne){
962 *operandOne /=10;
963 (*powerOne)++;
965 (*operandOne) += operandTwo;
967 else{/* simply copy operandTwo if operandOne is too small */
968 *operandOne = operandTwo;
969 *powerOne = powerTwo;
973 /* -----------------------------------------------------------------------
974 multiple in scientific number format
975 ----------------------------------------------------------------------- */
976 static void doMultiple(double* operandOne, int* powerOne,
977 double operandTwo, int powerTwo)
979 (*operandOne) *= operandTwo;
980 (*powerOne) += powerTwo;
983 /* -----------------------------------------------------------------------
984 Handles all one operand calculations
985 ----------------------------------------------------------------------- */
986 static void oneOperand(void)
988 int k = 0;
990 if (buttonGroup == basicButtons){
991 switch(CAL_BUTTON){
992 case btn_sqr:
993 if (result<0)
994 calStatus = cal_error;
995 else{
996 if (power%2 == 1){
997 result = (mySqrt(result*10))/10;
998 power = (power+1) / 2;
1000 else{
1001 result = mySqrt(result);
1002 power = power / 2;
1004 calStatus = cal_normal;
1006 break;
1007 case btn_square:
1008 power *= 2;
1009 result *= result;
1010 calStatus = cal_normal;
1011 break;
1013 case btn_rec:
1014 if (result==0)
1015 calStatus = cal_error;
1016 else{
1017 power = -power;
1018 result = 1/result;
1019 calStatus = cal_normal;
1021 break;
1022 default:
1023 calStatus = cal_toDo;
1024 break; /* just for the safety */
1027 else{ /* sciButtons */
1028 switch(CAL_BUTTON){
1029 case sci_sin:
1030 transcendFunc("sin", &result, &power);
1031 break;
1032 case sci_cos:
1033 transcendFunc("cos", &result, &power);
1034 break;
1035 case sci_tan:
1036 transcendFunc("tan", &result, &power);
1037 break;
1038 case sci_fac:
1039 if (power<0 || power>8 || result<0 )
1040 calStatus = cal_error;
1041 else if(result == 0) {
1042 result = 1;
1043 power = 0;
1045 else{
1046 while(power > 0) {
1047 result *= 10;
1048 power--;
1050 if ( ( result - (int)result) > MINIMUM )
1051 calStatus = cal_error;
1052 else {
1053 k = result; result = 1;
1054 while (k > 1){
1055 doMultiple(&result, &power, k, 0);
1056 formatResult();
1057 k--;
1059 calStatus = cal_normal;
1062 break;
1063 case sci_exp:
1064 /*Uses the sequence (1+a/n)^n -> exp(a) */
1065 if (power>3 || result > 1e3) calStatus = cal_error;
1066 else {
1067 while(power < 0) {
1068 result /= 10;
1069 power++;
1071 while (power > 0){
1072 power--;
1073 result*=10;
1075 result = myExp(result);
1076 calStatus = cal_normal;
1078 break;
1079 case sci_ln:
1080 if (result<=0) calStatus = cal_error;
1081 else {
1082 //ln(a*10^n) = ln(a) + n*ln(10), with ln(10) ≈ 2.30
1083 result = myLn(result) + power * 2.302585092994046;
1084 power=0;
1085 calStatus = cal_normal;
1087 break;
1088 case sci_log:
1089 if (result<=0) calStatus = cal_error;
1090 else {
1091 //log10(a+10^n) = ln(a)/ln(10) + n, with ln(10) ≈ 2.30
1092 result = myLn(result)/2.302585092994046 + power;
1093 power=0;
1094 calStatus = cal_normal;
1096 break;
1097 default:
1098 calStatus = cal_toDo;
1099 break; /* just for the safety */
1105 /* -----------------------------------------------------------------------
1106 Handles all two operands calculations
1107 ----------------------------------------------------------------------- */
1108 static void twoOperands(void)
1110 switch(oper){
1111 case '-':
1112 doAdd(&operand, &operandPower, -result, power);
1113 break;
1114 case '+':
1115 doAdd(&operand, &operandPower, result, power);
1116 break;
1117 case '*':
1118 doMultiple(&operand, &operandPower, result, power);
1119 break;
1120 case '/':
1121 if ( ABS(result) > MINIMUM ){
1122 doMultiple(&operand, &operandPower, 1/result, -power);
1124 else
1125 calStatus = cal_error;
1126 break;
1127 default: /* ' ' */
1128 switchOperands(); /* counter switchOperands() below */
1129 break;
1130 } /* switch(oper) */
1131 switchOperands();
1132 clearOper();
1135 /* First, increases *dimen1 by dimen1_delta modulo dimen1_modulo.
1136 If dimen1 wraps, increases *dimen2 by dimen2_delta modulo dimen2_modulo.
1138 static void move_with_wrap_and_shift(
1139 int *dimen1, int dimen1_delta, int dimen1_modulo,
1140 int *dimen2, int dimen2_delta, int dimen2_modulo)
1142 bool wrapped = false;
1144 *dimen1 += dimen1_delta;
1145 if (*dimen1 < 0)
1147 *dimen1 = dimen1_modulo - 1;
1148 wrapped = true;
1150 else if (*dimen1 >= dimen1_modulo)
1152 *dimen1 = 0;
1153 wrapped = true;
1156 if (wrapped)
1158 /* Make the dividend always positive to be sure about the result.
1159 Adding dimen2_modulo does not change it since we do it modulo. */
1160 *dimen2 = (*dimen2 + dimen2_modulo + dimen2_delta) % dimen2_modulo;
1164 /* -----------------------------------------------------------------------
1165 Print buttons when switching 1st and 2nd
1166 int group = {basicButtons, sciButtons}
1167 ----------------------------------------------------------------------- */
1168 static void printButtonGroups(int group)
1170 drawButtons(group);
1171 drawLines();
1172 rb->lcd_update();
1174 /* -----------------------------------------------------------------------
1175 flash the currently marked button
1176 ----------------------------------------------------------------------- */
1177 static void flashButton(void)
1179 int k, w, h;
1180 for (k=2;k>0;k--)
1182 rb->lcd_getstringsize( buttonChar[buttonGroup][btn_row][btn_col],&w,&h);
1183 rb->lcd_set_drawmode(DRMODE_SOLID|(k==1) ? 0 : DRMODE_INVERSEVID);
1184 rb->lcd_fillrect( X_0_POS + btn_col*REC_WIDTH + 1,
1185 Y_1_POS + btn_row*REC_HEIGHT + 1,
1186 REC_WIDTH - 1, REC_HEIGHT - 1);
1187 rb->lcd_putsxy( X_0_POS + btn_col*REC_WIDTH + (REC_WIDTH - w)/2,
1188 Y_1_POS + btn_row*REC_HEIGHT + (REC_HEIGHT - h)/2 +1,
1189 buttonChar[buttonGroup][btn_row][btn_col] );
1190 rb->lcd_update_rect( X_0_POS + btn_col*REC_WIDTH + 1,
1191 Y_1_POS + btn_row*REC_HEIGHT + 1,
1192 REC_WIDTH - 1, REC_HEIGHT - 1);
1194 if (k!= 1)
1195 rb->sleep(HZ/22);
1200 /* -----------------------------------------------------------------------
1201 pos is the position that needs animation. pos = [1~18]
1202 ----------------------------------------------------------------------- */
1203 #if defined(CALCULATOR_CLEAR) || defined(CALCULATOR_OPERATORS)
1204 static void deleteAnimation(int pos)
1206 int k, w, h, x;
1207 if (pos<1 || pos >18)
1208 return;
1210 rb->lcd_getstringsize("0", &w, &h);
1211 x = (pos==1? 4: LCD_WIDTH - 4 - w);
1213 for (k=0;k<4;k++){
1214 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1215 rb->lcd_fillrect(x, Y_1_POS - h -1, w, h);
1216 rb->lcd_set_drawmode(DRMODE_SOLID);
1217 rb->lcd_fillrect(x + (w*k)/8, Y_1_POS - h -1 + (h*k)/8,
1218 (w*(4-k))/4, (h*(4-k))/4);
1219 rb->lcd_update_rect(x, Y_1_POS - h -1, w, h);
1220 rb->sleep(HZ/32);
1223 #endif
1225 /* -----------------------------------------------------------------------
1226 result may be one of these formats:
1228 xxxx.xxxx
1229 0.xxxx
1230 0.0000xxxx
1232 formatResult() change result to standard format: 0.xxxx
1233 if result is close to 0, let it be 0;
1234 if result is close to 1, let it be 0.1 and power++;
1235 ----------------------------------------------------------------------- */
1236 static void formatResult(void)
1238 int resultsign = SIGN(result);
1239 result = ABS(result);
1240 if(result > MINIMUM ){ /* doesn't check power, might have problem
1241 input wouldn't,
1242 + - * / of two formatted number wouldn't.
1243 only a calculation that makes a formatted
1244 number (0.xxxx) less than MINIMUM in only
1245 one operation */
1247 if (result<1){
1248 while( (int)(result*10) == 0 ){
1249 result *= 10;
1250 power--;
1251 modifier *= 10;
1254 else{ /* result >= 1 */
1255 while( (int)result != 0 ){
1256 result /= 10;
1257 power++;
1258 modifier /= 10;
1260 } /* if result<1 */
1262 if (result > (1-MINIMUM)){
1263 result = 0.1;
1264 power++;
1265 modifier /= 10;
1267 result *= resultsign;
1269 else {
1270 result = 0;
1271 power = 0;
1272 modifier = 0.1;
1276 /* -----------------------------------------------------------------------
1277 result2typingbuf() outputs standard format result to typingbuf.
1278 case SCIENTIFIC_FORMAT, let temppower = 1;
1279 case temppower > 0: print '.' in the middle
1280 case temppower <= 0: print '.' in the begining
1281 ----------------------------------------------------------------------- */
1282 static void result2typingbuf(void)
1284 bool haveDot = false;
1285 char tempchar = 0;
1286 int k;
1287 double tempresult = ABS(result); /* positive num makes things simple */
1289 int temppower;
1290 double tempmodifier = 1;
1291 int count;
1293 if(SCIENTIFIC_FORMAT)
1294 temppower = 1; /* output x.xxxx format */
1295 else
1296 temppower = power;
1298 cleartypingbuf();
1300 if(tempresult < MINIMUM){ /* if 0,faster display and avoid complication*/
1301 typingbuf[0] = ' ';
1302 typingbuf[1] = '0';
1304 else{ /* tempresult > 0 */
1305 typingbuf[0] = (SIGN(result)<0)?'-':' ';
1307 typingbufPointer = typingbuf;
1308 if(temppower > 0){
1309 for (k = 0; k<DIGITLEN+1 ; k++){
1310 typingbufPointer++;
1311 if(temppower || *(typingbufPointer-1) == '.'){
1312 count = 0;
1313 tempmodifier = tempmodifier/10;
1314 while( (tempresult-tempmodifier*count) >
1315 (tempmodifier-MINIMUM)){
1316 count++;
1318 tempresult -= tempmodifier*count;
1319 tempresult = ABS(tempresult);
1320 temppower-- ;
1321 *typingbufPointer = count + '0';
1323 else{ /* temppower == 0 */
1324 *typingbufPointer = '.';
1325 haveDot = true;
1327 } /* for */
1329 else{
1330 haveDot = true;
1331 typingbufPointer++; *typingbufPointer = '0';
1332 typingbufPointer++; *typingbufPointer = '.';
1333 for (k = 2; k<DIGITLEN+1 ; k++){
1334 typingbufPointer++;
1335 count = 0;
1336 if ( (-temppower) < (k-1)){
1337 tempmodifier = tempmodifier/10;
1338 while((tempresult-tempmodifier*count)>(tempmodifier-MINIMUM)){
1339 count++;
1342 tempresult -= tempmodifier*count;
1343 tempresult = ABS(tempresult);
1344 temppower-- ;
1346 *typingbufPointer = count + '0';
1349 /* now, typingbufPointer = typingbuf + 16 */
1350 /* backward strip off 0 and '.' */
1351 if (haveDot){
1352 while( (*typingbufPointer == '0') || (*typingbufPointer == '.')){
1353 tempchar = *typingbufPointer;
1354 *typingbufPointer = 0;
1355 typingbufPointer--;
1356 if (tempchar == '.') break;
1359 typingbuf[DIGITLEN+1] = 0;
1360 } /* else tempresult > 0 */
1363 /* -----------------------------------------------------------------------
1364 printResult() generates LCD display.
1365 ----------------------------------------------------------------------- */
1366 static void printResult(void)
1368 int k, w, h;
1370 char operbuf[3] = {0, 0, 0};
1372 switch_Status:
1373 switch(calStatus){
1374 case cal_exit:
1375 rb->lcd_clear_display();
1376 rb->splash(HZ/3, "Bye now!");
1377 break;
1378 case cal_error:
1379 clearbuf();
1380 rb->snprintf(buf, 19, "%18s","Error");
1381 break;
1382 case cal_toDo:
1383 clearbuf();
1384 rb->snprintf(buf, 19, "%18s","Coming soon ^_* ");
1385 break;
1387 case cal_normal:
1388 formatResult();
1390 if( power > 1000 ){ /* power -1 > 999 */
1391 calStatus = cal_error;
1392 goto switch_Status;
1394 if (power < -998 ) /* power -1 < -999 */
1395 clearResult(); /* too small, let it be 0 */
1397 result2typingbuf();
1398 clearbuf();
1400 operbuf[0] = oper;
1401 operbuf[1] = ( ABS(memTemp) > MINIMUM )?'M':' ';
1402 operbuf[2] = '\0';
1404 if(SCIENTIFIC_FORMAT){
1405 /* output format: X.XXXX eXXX */
1406 if(power > -98){ /* power-1 >= -99, eXXX or e-XX */
1407 rb->snprintf(buf, 12, "%11s",typingbuf);
1408 for(k=11;k<=14;k++) buf[k] = ' ';
1409 cleartypingbuf();
1410 rb->snprintf(typingbuf, 5, "e%d",power-1);
1411 rb->snprintf(buf+11, 5, "%4s",typingbuf);
1413 else{ /* power-1 <= -100, e-XXX */
1414 rb->snprintf(buf, 12, "%11s",typingbuf);
1415 rb->snprintf(buf+11, 6, "e%d",power-1);
1418 else{
1419 rb->snprintf(buf, 12, "%11s",typingbuf);
1420 } /* if SCIENTIFIC_FORMAT */
1421 break;
1422 case cal_typing:
1423 case cal_dotted:
1424 clearbuf();
1425 operbuf[0] = oper;
1426 operbuf[1] = ( ABS(memTemp) > MINIMUM )?'M':' ';
1427 rb->snprintf(buf, 12, "%11s",typingbuf);
1428 break;
1432 rb->lcd_getstringsize(buf, &w, &h);
1433 rb->screen_clear_area(rb->screens[0], 0, 0, LCD_WIDTH, Y_1_POS - 1);
1434 rb->lcd_putsxy(4, Y_1_POS - h -1, operbuf);
1435 rb->lcd_putsxy(LCD_WIDTH - w - 4, Y_1_POS - h -1, buf);
1436 rb->lcd_update_rect(0, 1, LCD_WIDTH, Y_1_POS);
1439 /* -----------------------------------------------------------------------
1440 Process typing buttons: 1-9, '.', sign
1441 main operand "result" and typingbuf are processed seperately here.
1442 ----------------------------------------------------------------------- */
1443 static void typingProcess(void){
1444 switch( CAL_BUTTON ){
1445 case btn_sign:
1446 if (calStatus == cal_typing ||
1447 calStatus == cal_dotted)
1448 typingbuf[0] = (typingbuf[0]=='-')?' ':'-';
1449 result = -result;
1450 break;
1451 case btn_dot:
1452 operInputted = false;
1453 switch(calStatus){
1454 case cal_normal:
1455 clearInput();
1456 *typingbufPointer = '0';
1457 typingbufPointer++;
1458 case cal_typing:
1459 calStatus = cal_dotted;
1460 *typingbufPointer = '.';
1461 if (typingbufPointer != typingbuf+DIGITLEN+1)
1462 typingbufPointer++;
1463 break;
1464 default: /* cal_dotted */
1465 break;
1467 break;
1468 default: /* 0-9 */
1469 operInputted = false;
1470 /* normal,0; normal,1-9; typing,0; typing,1-9 */
1471 switch(calStatus){
1472 case cal_normal:
1473 if(CAL_BUTTON == btn_0 )
1474 break; /* first input is 0, ignore */
1475 clearInput();
1476 /*no operator means start a new calculation*/
1477 if (oper ==' ')
1478 clearOperand();
1479 calStatus = cal_typing;
1480 /* go on typing, no break */
1481 case cal_typing:
1482 case cal_dotted:
1483 switch(CAL_BUTTON){
1484 case btn_0:
1485 *typingbufPointer = '0';
1486 break;
1487 default:
1488 *typingbufPointer=(7+btn_col-3*(btn_row-1))+ '0';
1489 break;
1491 if (typingbufPointer!=typingbuf+DIGITLEN+1){
1492 typingbufPointer++;
1494 {/* result processing */
1495 if (calStatus == cal_typing) power++;
1496 if (CAL_BUTTON != btn_0)
1497 result= result +
1498 SIGN(result)*
1499 (7+btn_col-3*(btn_row-1))*modifier;
1500 modifier /= 10;
1503 else /* last byte always '\0' */
1504 *typingbufPointer = 0;
1505 break;
1506 default: /* cal_error, cal_exit */
1507 break;
1509 break; /* default, 0-9 */
1510 } /* switch( CAL_BUTTON ) */
1513 /* -----------------------------------------------------------------------
1514 Handle delete operation
1515 main operand "result" and typingbuf are processed seperately here.
1516 ----------------------------------------------------------------------- */
1517 #ifdef CALCULATOR_CLEAR
1518 static void doDelete(void){
1519 deleteAnimation(18);
1520 switch(calStatus){
1521 case cal_dotted:
1522 if (*(typingbufPointer-1) == '.'){
1523 /* if dotted and deleting '.',
1524 change status and delete '.' below */
1525 calStatus = cal_typing;
1527 else{ /* if dotted and not deleting '.',
1528 power stays */
1529 power++; /* counter "power--;" below */
1531 case cal_typing:
1532 typingbufPointer--;
1534 {/* result processing */ /* 0-9, '.' */
1535 /* if deleting '.', do nothing */
1536 if ( *typingbufPointer != '.'){
1537 power--;
1538 modifier *= 10;
1539 result = result - SIGN(result)*
1540 ((*typingbufPointer)- '0')*modifier;
1544 *typingbufPointer = 0;
1546 /* if (only one digit left and it's 0)
1547 or no digit left, change status*/
1548 if ( typingbufPointer == typingbuf+1 ||
1549 ( typingbufPointer == typingbuf+2 &&
1550 *(typingbufPointer-1) == '0' ))
1551 calStatus = cal_normal;
1552 break;
1553 default: /* normal, error, exit */
1554 break;
1557 #endif
1558 /* -----------------------------------------------------------------------
1559 Handle buttons on basic screen
1560 ----------------------------------------------------------------------- */
1561 static void basicButtonsProcess(void){
1562 switch (btn) {
1563 case CALCULATOR_INPUT:
1564 if (calStatus == cal_error && (CAL_BUTTON != btn_C) ) break;
1565 flashButton();
1566 switch( CAL_BUTTON ){
1567 case btn_MR:
1568 operInputted = false;
1569 result = memTemp; power = memTempPower;
1570 calStatus = cal_normal;
1571 break;
1572 case btn_M:
1573 formatResult();
1574 if (memTemp > MINIMUM)
1575 doAdd(&memTemp, &memTempPower, result, power);
1576 else {
1577 /* if result is too small and memTemp = 0,
1578 doAdd will not add */
1579 memTemp = result;
1580 memTempPower = power;
1582 calStatus = cal_normal;
1583 break;
1585 case btn_C: clearMem(); break;
1586 case btn_CE: clearInput(); break;
1588 case btn_bas:
1589 buttonGroup = sciButtons;
1590 printButtonGroups(buttonGroup);
1591 break;
1593 /* one operand calculation, may be changed to
1594 like sin, cos, log, etc */
1595 case btn_sqr:
1596 case btn_square:
1597 case btn_rec:
1598 formatResult(); /* not necessary, just for safty */
1599 oneOperand();
1600 break;
1602 case_btn_equal: /* F3 shortkey entrance */
1603 case btn_equal:
1604 formatResult();
1605 calStatus = cal_normal;
1606 operInputted = false;
1607 if (oper != ' ') twoOperands();
1608 break;
1610 case btn_div:
1611 case btn_time:
1612 case btn_minus:
1613 case btn_add:
1614 if(!operInputted) {twoOperands(); operInputted = true;}
1615 oper = buttonChar[basicButtons][btn_row][btn_col][0];
1616 #ifdef CALCULATOR_OPERATORS
1617 case_cycle_operators: /* F2 shortkey entrance */
1618 #endif
1619 calStatus = cal_normal;
1620 formatResult();
1621 operand = result;
1622 operandPower = power;
1624 break;
1626 case btn_sign:
1627 case btn_dot:
1628 default: /* 0-9 */
1629 typingProcess();
1630 break;
1631 } /* switch (CAL_BUTTON) */
1632 break;
1634 #ifdef CALCULATOR_OPERATORS
1635 case CALCULATOR_OPERATORS:
1636 if (calStatus == cal_error) break;
1637 if (!operInputted) {twoOperands(); operInputted = true;}
1638 switch (oper){
1639 case ' ':
1640 case '/': oper = '+'; flashButton(); break;
1641 case '+': oper = '-'; flashButton(); break;
1642 case '-': oper = '*'; flashButton(); break;
1643 case '*': oper = '/'; flashButton(); break;
1645 goto case_cycle_operators;
1646 break;
1647 #endif
1649 case CALCULATOR_CALC:
1650 if (calStatus == cal_error) break;
1651 flashButton();
1652 goto case_btn_equal;
1653 break;
1654 default: break;
1656 printResult();
1659 /* -----------------------------------------------------------------------
1660 Handle buttons on scientific screen
1661 ----------------------------------------------------------------------- */
1662 static void sciButtonsProcess(void){
1663 switch (btn) {
1664 case CALCULATOR_INPUT:
1665 if (calStatus == cal_error && (CAL_BUTTON != sci_sci) ) break;
1666 flashButton();
1667 switch( CAL_BUTTON ){
1669 case sci_pi:
1670 result = M_PI; power = 0;
1671 calStatus = cal_normal;
1672 break;
1674 case sci_xy:
1675 /*Not implemented yet
1676 Maybe it could use x^y = exp(y*ln(x))*/
1677 break;
1679 case sci_sci:
1680 buttonGroup = basicButtons;
1681 printButtonGroups(basicButtons);
1682 break;
1684 case sci_fac:
1685 case sci_sin:
1686 case sci_asin:
1687 case sci_cos:
1688 case sci_acos:
1689 case sci_tan:
1690 case sci_atan:
1691 case sci_ln:
1692 case sci_exp:
1693 case sci_log:
1694 formatResult(); /* not necessary, just for safty */
1695 oneOperand();
1696 break;
1698 case btn_sign:
1699 case btn_dot:
1700 default: /* 0-9 */
1701 typingProcess();
1702 break;
1703 } /* switch (CAL_BUTTON) */
1704 break;
1706 #ifdef CALCULATOR_OPERATORS
1707 case CALCULATOR_OPERATORS:
1708 if (calStatus == cal_error) break;
1709 if (!operInputted) {twoOperands(); operInputted = true;}
1710 switch (oper){
1711 case ' ': oper = '+'; break;
1712 case '/': oper = '+'; deleteAnimation(1); break;
1713 case '+': oper = '-'; deleteAnimation(1); break;
1714 case '-': oper = '*'; deleteAnimation(1); break;
1715 case '*': oper = '/'; deleteAnimation(1); break;
1717 calStatus = cal_normal;
1718 formatResult();
1719 operand = result;
1720 operandPower = power;
1721 break;
1722 #endif
1724 case CALCULATOR_CALC:
1725 if (calStatus == cal_error) break;
1726 formatResult();
1727 calStatus = cal_normal;
1728 operInputted = false;
1729 if (oper != ' ') twoOperands();
1730 break;
1731 default: break;
1733 printResult();
1736 /* -----------------------------------------------------------------------
1737 move button index
1738 Invert display new button, invert back previous button
1739 ----------------------------------------------------------------------- */
1740 static int handleButton(int button){
1741 switch(button)
1743 case CALCULATOR_INPUT:
1744 case CALCULATOR_CALC:
1745 #ifdef CALCULATOR_INPUT_CALC_PRE
1746 if (lastbtn != CALCULATOR_INPUT_CALC_PRE)
1747 break;
1748 /* no unconditional break; here! */
1749 #endif
1750 #ifdef CALCULATOR_OPERATORS
1751 case CALCULATOR_OPERATORS:
1752 #endif
1753 switch(buttonGroup){
1754 case basicButtons:
1755 basicButtonsProcess();
1756 break;
1757 case sciButtons:
1758 sciButtonsProcess();
1759 break;
1761 break;
1763 #ifdef CALCULATOR_CLEAR
1764 case CALCULATOR_CLEAR:
1765 switch(calStatus){
1766 case cal_typing:
1767 case cal_dotted:
1768 doDelete();
1769 break;
1770 default: /* cal_normal, cal_error, cal_exit */
1771 clearMem();
1772 break;
1774 printResult();
1775 break;
1776 #endif
1777 case CALCULATOR_LEFT:
1778 case CALCULATOR_LEFT | BUTTON_REPEAT:
1779 move_with_wrap_and_shift(
1780 &btn_col, -1, BUTTON_COLS,
1781 &btn_row, 0, BUTTON_ROWS);
1782 break;
1784 case CALCULATOR_RIGHT:
1785 case CALCULATOR_RIGHT | BUTTON_REPEAT:
1786 move_with_wrap_and_shift(
1787 &btn_col, 1, BUTTON_COLS,
1788 &btn_row, 0, BUTTON_ROWS);
1789 break;
1791 #ifdef CALCULATOR_UP
1792 case CALCULATOR_UP:
1793 case CALCULATOR_UP | BUTTON_REPEAT:
1794 move_with_wrap_and_shift(
1795 &btn_row, -1, BUTTON_ROWS,
1796 &btn_col, 0, BUTTON_COLS);
1797 break;
1798 #endif
1799 #ifdef CALCULATOR_DOWN
1800 case CALCULATOR_DOWN:
1801 case CALCULATOR_DOWN | BUTTON_REPEAT:
1802 move_with_wrap_and_shift(
1803 &btn_row, 1, BUTTON_ROWS,
1804 &btn_col, 0, BUTTON_COLS);
1805 break;
1806 #endif
1808 #ifdef CALCULATOR_UP_W_SHIFT
1809 case CALCULATOR_UP_W_SHIFT:
1810 case CALCULATOR_UP_W_SHIFT | BUTTON_REPEAT:
1811 move_with_wrap_and_shift(
1812 &btn_row, -1, BUTTON_ROWS,
1813 &btn_col, -1, BUTTON_COLS);
1814 break;
1815 #endif
1816 #ifdef CALCULATOR_DOWN_W_SHIFT
1817 case CALCULATOR_DOWN_W_SHIFT:
1818 case CALCULATOR_DOWN_W_SHIFT | BUTTON_REPEAT:
1819 move_with_wrap_and_shift(
1820 &btn_row, 1, BUTTON_ROWS,
1821 &btn_col, 1, BUTTON_COLS);
1822 break;
1823 #endif
1824 #ifdef CALCULATOR_LEFT_W_SHIFT
1825 case CALCULATOR_LEFT_W_SHIFT:
1826 case CALCULATOR_LEFT_W_SHIFT | BUTTON_REPEAT:
1827 move_with_wrap_and_shift(
1828 &btn_col, -1, BUTTON_COLS,
1829 &btn_row, -1, BUTTON_ROWS);
1830 break;
1831 #endif
1832 #ifdef CALCULATOR_RIGHT_W_SHIFT
1833 case CALCULATOR_RIGHT_W_SHIFT:
1834 case CALCULATOR_RIGHT_W_SHIFT | BUTTON_REPEAT:
1835 move_with_wrap_and_shift(
1836 &btn_col, 1, BUTTON_COLS,
1837 &btn_row, 1, BUTTON_ROWS);
1838 break;
1839 #endif
1840 #ifdef CALCULATOR_RC_QUIT
1841 case CALCULATOR_RC_QUIT:
1842 #endif
1843 case CALCULATOR_QUIT:
1844 return -1;
1847 return 0;
1850 /* -----------------------------------------------------------------------
1851 Main();
1852 ----------------------------------------------------------------------- */
1853 enum plugin_status plugin_start(const void* parameter)
1855 (void)parameter;
1857 /* now go ahead and have fun! */
1859 #ifdef HAVE_TOUCHSCREEN
1860 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
1861 #endif
1863 cal_initial();
1865 while (calStatus != cal_exit ) {
1866 btn = rb->button_get_w_tmo(HZ/2);
1867 #ifdef HAVE_TOUCHSCREEN
1868 if(btn & BUTTON_TOUCHSCREEN)
1870 struct ts_raster_result res;
1871 if(touchscreen_map_raster(&calc_raster, rb->button_get_data() >> 16,
1872 rb->button_get_data() & 0xffff, &res) == 1)
1874 btn_row = res.y;
1875 btn_col = res.x;
1876 drawButtons(buttonGroup);
1877 drawLines();
1879 rb->lcd_update();
1881 prev_btn_row = btn_row;
1882 prev_btn_col = btn_col;
1883 if(btn & BUTTON_REL)
1885 btn = CALCULATOR_INPUT;
1886 switch(buttonGroup){
1887 case basicButtons:
1888 basicButtonsProcess();
1889 break;
1890 case sciButtons:
1891 sciButtonsProcess();
1892 break;
1894 btn = BUTTON_TOUCHSCREEN;
1898 #endif
1899 if (handleButton(btn) == -1)
1901 calStatus = cal_exit;
1902 printResult();
1904 else
1906 drawButtons(buttonGroup);
1907 drawLines();
1910 rb->lcd_update();
1912 if(rb->default_event_handler(btn) == SYS_USB_CONNECTED)
1913 return PLUGIN_USB_CONNECTED;
1915 if (btn != BUTTON_NONE)
1916 lastbtn = btn;
1917 } /* while (calStatus != cal_exit ) */
1919 rb->button_clear_queue();
1920 return PLUGIN_OK;