summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2004-05-19 09:19:02 +0000
committerDaniel Stenberg <daniel@haxx.se>2004-05-19 09:19:02 +0000
commit367aac95190e541b3fe71f3cd371c24d89aac844 (patch)
treed4b78efe571d786f546d49b31c689d8e75b7a702
parentb9c02e6851224cd1915016cb13da71f8ac2b905a (diff)
downloadrockbox-367aac95190e541b3fe71f3cd371c24d89aac844.tar.gz
rockbox-367aac95190e541b3fe71f3cd371c24d89aac844.zip
Isaac's calculator plugin
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4645 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugins/calculator.c1311
1 files changed, 1311 insertions, 0 deletions
diff --git a/apps/plugins/calculator.c b/apps/plugins/calculator.c
new file mode 100644
index 0000000000..f12710eb1b
--- /dev/null
+++ b/apps/plugins/calculator.c
@@ -0,0 +1,1311 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 Pengxuan(Isaac) <tinousus@yahoo.com>
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20/*
21 00 01 21 22 23 43 44 45 65 66 67 87 88 89 109110111
2200 |-----------|-----------|-----------|-----------|-----------|
2301 |
24 | | | | |
25 |
26***********|
27***********|
28***********|
29***********|
30***********|
31 |
32***********|
33***********|
34***********|
35***********|
36***********|
3711 |
38 | | | | |
3912 |-----------|-----------|-----------|-----------|-----------|
4013 |-----------|-----------|-----------|-----------|-----------| y1
4114 |
42 | | | | |
43
44 | | | | | |
4522 |
46 | | | | |
4723 |-----------|-----------|-----------|-----------|-----------| y2
4824 |
49 | | | | |
50
51 | | | | | |
5232 |
53 | | | | |
5433 |-----------|-----------|-----------|-----------|-----------| y3
5534 |
56 | | | | |
57
58 | | | | | |
5942 |
60 | | | | |
6143 |-----------|-----------|-----------|-----------|-----------| y4
6244 |
63 | | | | |
64
65 | | | | | |
6652 |
67 | | | | |
6853 |-----------|-----------|-----------|-----------|-----------| y5
6954 |
70 | | | | |
71
72 | | | | | |
7362 |
74 | | | | |
7563 |-----------|-----------|-----------|-----------|-----------| y6
76 x0 x1 x2 x3 x4 x5
77*/
78
79/*---------------------------------------------------------------------------
80Features:
81- Scientific number format core code. Support range 10^-999 ~ 10^999
82- Number of significant figures up to 10
83
84Limitations:
85- Right now, only accept "num, operator (+,-,*,/), num, =" input sequence.
86 Input "3, +, 5, -, 2, =", the calculator will only do 5-2 and result = 3
87 You have to input "3, +, 5, =, -, 2, =" to get 3+5-2 = 6
88
89- "*,/" have no priority. Actually you can't input 3+5*2 yet.
90
91User Instructions:
92use arrow button to move cursor, "play" button to select, "off" button to exit
93F1: if typing numbers, it's equal to "Del"; otherwise, equal to "C"
94F2: circle input "+, -, *, /"
95F3: equal to "="
96
97"MR" : load temp memory
98"M+" : add currently display to temp memory
99"C" : reset calculator
100---------------------------------------------------------------------------*/
101
102#include "plugin.h"
103#ifdef HAVE_LCD_BITMAP
104#include "math.h"
105
106#define REC_HEIGHT 10 /* blank height = 9 */
107#define REC_WIDTH 22 /* blank width = 21 */
108
109#define Y_6_POS (LCD_HEIGHT - 1) /* y6 = 63 */
110#define Y_5_POS (Y_6_POS - REC_HEIGHT) /* y5 = 53 */
111#define Y_4_POS (Y_5_POS - REC_HEIGHT) /* y4 = 43 */
112#define Y_3_POS (Y_4_POS - REC_HEIGHT) /* y3 = 33 */
113#define Y_2_POS (Y_3_POS - REC_HEIGHT) /* y2 = 23 */
114#define Y_1_POS (Y_2_POS - REC_HEIGHT) /* y1 = 13 */
115#define Y_0_POS 0 /* y0 = 0 */
116
117#define X_0_POS 0 /* x0 = 0 */
118#define X_1_POS (X_0_POS + REC_WIDTH) /* x1 = 22 */
119#define X_2_POS (X_1_POS + REC_WIDTH) /* x2 = 44 */
120#define X_3_POS (X_2_POS + REC_WIDTH) /* x3 = 66 */
121#define X_4_POS (X_3_POS + REC_WIDTH) /* x4 = 88 */
122#define X_5_POS (X_4_POS + REC_WIDTH) /* x5 = 110, column 111 left blank */
123
124#define TEXT_1_POS (Y_1_POS-10) /* y1 = 2 */ /* blank height = 12 */
125#define TEXT_2_POS (Y_2_POS-8) /* y2 = 15 */ /* blank height = 9 */
126#define TEXT_3_POS (Y_3_POS-8) /* y3 = 25 */
127#define TEXT_4_POS (Y_4_POS-8) /* y4 = 35 */
128#define TEXT_5_POS (Y_5_POS-8) /* y5 = 45 */
129#define TEXT_6_POS (Y_6_POS-8) /* y6 = 55 */
130
131#define SIGN(x) ((x)<0?-1:1)
132#define ABS(x) ((x)<0?-(x):(x))
133
134static struct plugin_api* rb;
135
136enum {basicButtons, sciButtons} buttonGroup;
137unsigned char* buttonChar[2][5][5] = {
138 { { "MR" , "M+" , "2nd" , "CE" , "C" },
139 { "7" , "8" , "9" , "/" , "sqr" },
140 { "4" , "5" , "6" , "*" , "x^2" },
141 { "1" , "2" , "3" , "-" , "1/x" },
142 { "0" , "+/-", "." , "+" , "=" } },
143
144 { { "n!" , "PI" , "1st" , "sin" , "asi" },
145 { "7" , "8" , "9" , "cos" , "aco" },
146 { "4" , "5" , "6" , "tan" , "ata" },
147 { "1" , "2" , "3" , "ln" , "e^x" },
148 { "0" , "+/-", "." , "log" , "x^y" } }
149 };
150enum { btn_MR , btn_M , btn_bas , btn_CE , btn_C ,
151 btn_7 , btn_8 , btn_9 , btn_div , btn_sqr ,
152 btn_4 , btn_5 , btn_6 , btn_time , btn_square ,
153 btn_1 , btn_2 , btn_3 , btn_minus , btn_rec ,
154 btn_0 , btn_sign , btn_dot , btn_add , btn_equal
155 };
156enum { sci_fac, sci_pi , sci_sci , sci_sin , sci_asin ,
157 sci_7 , sci_8 , sci_9 , sci_cos , sci_acos ,
158 sci_4 , sci_5 , sci_6 , sci_tan , sci_atan ,
159 sci_1 , sci_2 , sci_3 , sci_ln , sci_exp ,
160 sci_0 , sci_sign , sci_dot , sci_log , sci_xy
161 };
162
163#define PI 3.14159265358979323846
164#define MINIMUM 0.000000000001 /* e-12 */
165 /* ^ ^ ^ ^ */
166 /* 123456789abcdef */
167
168#define DIGITLEN 10 /* must <= 10 */
169#define SCIENTIFIC_FORMAT ( power < -(DIGITLEN-3) || power > (DIGITLEN))
170 /* 0.000 00000 0001 */
171 /* ^ ^ ^ ^ ^ ^ */
172 /* DIGITLEN 12345 6789a bcdef */
173 /* power 12 34567 89abc def */
174 /* 10^- 123 45678 9abcd ef */
175
176unsigned char buf[19];/* 18 bytes of output line,
177 buf[0] is operator
178 buf[1] = 'M' if memTemp is not 0
179 buf[2] = ' '
180
181 if SCIENTIFIC_FORMAT
182 buf[2]-buf[12] or buf[3]-buf[13] = result;
183 format X.XXXXXXXX
184 buf[13] or buf[14] -buf[17] = power;
185 format eXXX or e-XXX
186 else
187 buf[3]-buf[6] = ' ';
188 buf[7]-buf[17] = result;
189
190 buf[18] = '\0' */
191
192unsigned char typingbuf[DIGITLEN+2];/* byte 0 is sign or ' ',
193 byte 1~DIGITLEN are num and '.'
194 byte (DIGITLEN+1) is '\0' */
195unsigned char* typingbufPointer = typingbuf;
196
197double result = 0; /* main operand, format 0.xxxxx */
198int power = 0; /* 10^power */
199double modifier = 0.1; /* position of next input */
200double operand = 0; /* second operand, format 0.xxxxx */
201int operandPower = 0; /* 10^power of second operand */
202char oper = ' '; /* operators: + - * / */
203bool operInputted = false; /* false: do calculation first and
204 replace current oper
205 true: just replace current oper */
206
207double memTemp = 0; /* temp memory */
208int memTempPower = 0; /* 10^^power of memTemp */
209
210int m, n, prev_m, prev_n; /* position index for button */
211#define CAL_BUTTON (m*5+n)
212
213int btn = BUTTON_NONE;
214
215/* Status of calculator */
216enum {cal_normal, /* 0, normal status, display result */
217 cal_typing, /* 1, currently typing, dot hasn't been typed */
218 cal_dotted, /* 2, currently typing, dot already has been typed. */
219 cal_error,
220 cal_exit,
221 cal_toDo
222} calStatus;
223
224/* constant table for CORDIC algorithm */
225double cordicTable[51][2]= {
226 /* pow(2,0) - pow(2,-50) atan(pow(2,0) - atan(pow(2,-50) */
227 {1e+00,
228 7.853981633974483e-01},
229 {5e-01,
230 4.636476090008061e-01},
231 {2.5e-01,
232 2.449786631268641e-01},
233 {1.25e-01,
234 1.243549945467614e-01},
235 {6.25e-02,
236 6.241880999595735e-02},
237 {3.125e-02,
238 3.123983343026828e-02},
239 {1.5625e-02,
240 1.562372862047683e-02},
241 {7.8125e-03,
242 7.812341060101111e-03},
243 {3.90625e-03,
244 3.906230131966972e-03},
245 {1.953125e-03,
246 1.953122516478819e-03},
247 {9.765625e-04,
248 9.765621895593195e-04},
249 {4.8828125e-04,
250 4.882812111948983e-04},
251 {2.44140625e-04,
252 2.441406201493618e-04},
253 {1.220703125e-04,
254 1.220703118936702e-04},
255 {6.103515625e-05,
256 6.103515617420877e-05},
257 {3.0517578125e-05,
258 3.051757811552610e-05},
259 {1.52587890625e-05,
260 1.525878906131576e-05},
261 {7.62939453125e-06,
262 7.629394531101970e-06},
263 {3.814697265625e-06,
264 3.814697265606496e-06},
265 {1.9073486328125e-06,
266 1.907348632810187e-06},
267 {9.5367431640625e-07,
268 9.536743164059608e-07},
269 {4.76837158203125e-07,
270 4.768371582030888e-07},
271 {2.384185791015625e-07,
272 2.384185791015580e-07},
273 {1.1920928955078125e-07,
274 1.192092895507807e-07},
275 {5.9604644775390625e-08,
276 5.960464477539055e-08},
277 {2.98023223876953125e-08,
278 2.980232238769530e-08},
279 {1.490116119384765625e-08,
280 1.490116119384765e-08},
281 {7.450580596923828125e-09,
282 7.450580596923828e-09},
283 {3.7252902984619140625e-09,
284 3.725290298461914e-09},
285 {1.86264514923095703125e-09,
286 1.862645149230957e-09},
287 {9.31322574615478515625e-10,
288 9.313225746154785e-10},
289 {4.656612873077392578125e-10,
290 4.656612873077393e-10},
291 {2.3283064365386962890625e-10,
292 2.328306436538696e-10},
293 {1.16415321826934814453125e-10,
294 1.164153218269348e-10},
295 {5.82076609134674072265625e-11,
296 5.820766091346741e-11},
297 {2.910383045673370361328125e-11,
298 2.910383045673370e-11},
299 {1.4551915228366851806640625e-11,
300 1.455191522836685e-11},
301 {7.2759576141834259033203125e-12,
302 7.275957614183426e-12},
303 {3.63797880709171295166015625e-12,
304 3.637978807091713e-12},
305 {1.818989403545856475830078125e-12,
306 1.818989403545856e-12},
307 {9.094947017729282379150390625e-13,
308 9.094947017729282e-13},
309 {4.5474735088646411895751953125e-13,
310 4.547473508864641e-13},
311 {2.27373675443232059478759765625e-13,
312 2.273736754432321e-13},
313 {1.136868377216160297393798828125e-13,
314 1.136868377216160e-13},
315 {5.684341886080801486968994140625e-14,
316 5.684341886080801e-14},
317 {2.8421709430404007434844970703125e-14,
318 2.842170943040401e-14},
319 {1.42108547152020037174224853515625e-14,
320 1.421085471520200e-14},
321 {7.10542735760100185871124267578125e-15,
322 7.105427357601002e-15},
323 {3.552713678800500929355621337890625e-15,
324 3.552713678800501e-15},
325 {1.7763568394002504646778106689453125e-15,
326 1.776356839400250e-15},
327 {8.8817841970012523233890533447265625e-16, 8.881784197001252e-16}
328};
329
330void doMultiple(double* operandOne, int* powerOne,
331 double operandTwo, int powerTwo);
332void doAdd (double* operandOne, int* powerOne,
333 double operandTwo, int powerTwo);
334void printResult(void);
335void formatResult(void);
336void oneOperand(void);
337
338/* -----------------------------------------------------------------------
339Handy funtions
340----------------------------------------------------------------------- */
341void cleartypingbuf(void){
342 int k;
343 for( k=1; k<=(DIGITLEN+1); k++)
344 typingbuf[k] = 0;
345 typingbuf[0] = ' ';
346 typingbufPointer = typingbuf+1;
347}
348void clearbuf(void){
349 int k;
350 for(k=0;k<18;k++) buf[k]=' ';
351 buf[18] = 0;
352}
353void clearResult(void){
354 result = 0;
355 power = 0;
356 modifier = 0.1;
357}
358void clearInput(void){
359 calStatus = cal_normal;
360 clearResult();
361 cleartypingbuf();
362}
363void clearOperand(void){
364 operand = 0;
365 operandPower = 0;
366}
367void clearMemTemp(void){
368 memTemp = 0;
369 memTempPower = 0;
370}
371void clearOper(void){
372 oper = ' ';
373 operInputted = false;
374}
375void clearMem(void){
376 clearInput();
377 clearMemTemp();
378 clearOperand();
379 clearOper();
380 btn = BUTTON_NONE;
381}
382
383void switchOperands(void){
384 double tempr = operand;
385 int tempp = operandPower;
386 operand = result;
387 operandPower = power;
388 result = tempr;
389 power = tempp;
390}
391
392/* -----------------------------------------------------------------------
393Initiate calculator
394----------------------------------------------------------------------- */
395void cal_initial (void){
396 int i,j,w,h;
397 rb->lcd_setfont(FONT_SYSFIXED);
398 rb->lcd_clear_display();
399
400 /* draw lines */
401 rb->lcd_drawrect(X_0_POS, Y_0_POS, LCD_WIDTH-1, LCD_HEIGHT);
402 rb->lcd_drawline(X_0_POS, Y_1_POS-1, X_5_POS, Y_1_POS-1);
403 for (i = 0; i < 5 ; i++)
404 rb->lcd_drawline(X_0_POS, Y_1_POS+i*REC_HEIGHT,
405 X_5_POS, Y_1_POS+i*REC_HEIGHT);
406 for (i = 0; i < 4 ; i++)
407 rb->lcd_drawline(X_1_POS+i*REC_WIDTH, Y_1_POS,
408 X_1_POS+i*REC_WIDTH, Y_6_POS);
409
410 /* draw buttons */
411 buttonGroup = sciButtons;
412 for (i = 0; i < 5; i++){
413 for (j = 0; j < 5; j++){
414 rb->lcd_getstringsize( buttonChar[buttonGroup][i][j],&w,&h);
415 rb->lcd_putsxy( X_0_POS + j*REC_WIDTH + (REC_WIDTH - w)/2,
416 TEXT_2_POS + i*REC_HEIGHT,
417 buttonChar[buttonGroup][i][j] );
418 }
419 }
420
421 /* initially, invert button "5" */
422 m = 2; n = 1;
423 prev_m = m; prev_n = n;
424 rb->lcd_invertrect( X_0_POS + n*REC_WIDTH + 1,
425 Y_1_POS + m*REC_HEIGHT + 1,
426 REC_WIDTH - 1, REC_HEIGHT - 1);
427 rb->lcd_update();
428
429 /* initial mem and output display*/
430 clearMem();
431 printResult();
432
433 /* clear button queue */
434 while (rb->button_get(false));
435}
436
437/* -----------------------------------------------------------------------
438mySqrt uses Heron's algorithm, which is the Newtone-Raphson algorhitm
439in it's private case for sqrt.
440Thanks BlueChip for his intro text and Dave Straayer for the actual name.
441----------------------------------------------------------------------- */
442double mySqrt(double square){
443 int k = 0;
444 double temp = 0;
445 double root= ABS(square+1)/2;
446
447 while( ABS(root - temp) > MINIMUM ){
448 temp = root;
449 root = (square/temp + temp)/2;
450 k++;
451 if (k>10000) return 0;
452 }
453
454 return root;
455}
456/* -----------------------------------------------------------------------
457transcendFunc uses CORDIC (COordinate Rotation DIgital Computer) method
458transcendFunc can do sin,cos,log,exp
459input parameter is angle
460----------------------------------------------------------------------- */
461void transcendFunc(char* func, double* tt, int* ttPower){
462 double t = (*tt)*PI/180; int tPower = *ttPower;
463
464 if (tPower < -998) {calStatus = cal_normal; return;}
465 if (tPower > 8) {calStatus = cal_error; return;}
466 *ttPower = 0;
467 calStatus = cal_normal;
468
469 int sign = 1;
470 int n = 50; /* n <=50, tables are all <= 50 */
471 int j;
472 double x,y,z,xt,yt,zt;
473
474 if( func[0] =='s' || func[0] =='S') sign = SIGN(t);
475 else { /* if( func[0] =='c' || func[0] =='C') */ sign = 1; }
476 t = ABS(t);
477
478 while (tPower > 0){ t *= 10; tPower--; }
479 while (tPower < 0){ t /= 10; tPower++; }
480 j = 0;
481 while (t > j*2*PI) {j++;}
482 t -= (j-1)*2*PI;
483 if (PI/2 < t && t < 3*PI/2){
484 t = PI - t;
485 if (func[0] =='c' || func[0] =='C') sign = -1;
486 }
487 else if ( 3*PI/2 <= t && t <= 2*PI) t -= 2*PI;
488
489 x = 0.60725293500888; y = 0; z = t;
490 for (j=1;j<n+2;j++){
491 xt = x - SIGN(z) * y*cordicTable[j-1][0];
492 yt = y + SIGN(z) * x*cordicTable[j-1][0];
493
494 zt = z - SIGN(z) * cordicTable[j-1][1];
495 x = xt;y=yt;z=zt;
496 }
497 if( func[0] =='s' || func[0] =='S') {*tt = sign*y; return;}
498 else /* if( func[0] =='c' || func[0] =='C')*/ {*tt = sign*x; return;}
499
500}
501/* -----------------------------------------------------------------------
502add in scientific number format
503----------------------------------------------------------------------- */
504void doAdd (double* operandOne, int* powerOne,
505 double operandTwo, int powerTwo){
506
507 if ( *powerOne >= powerTwo ){
508 if (*powerOne - powerTwo <= DIGITLEN+1){
509 while (powerTwo < *powerOne){
510 operandTwo /=10;
511 powerTwo++;
512 }
513 *operandOne += operandTwo;
514 }
515 /*do nothing if operandTwo is too small*/
516 }
517 else{
518 if (powerTwo - *powerOne <= DIGITLEN+1){
519 while(powerTwo > *powerOne){
520 *operandOne /=10;
521 (*powerOne)++;
522 }
523 (*operandOne) += operandTwo;
524 }
525 else{/* simply copy operandTwo if operandOne is too small */
526 *operandOne = operandTwo;
527 *powerOne = powerTwo;
528 }
529 }
530}
531/* -----------------------------------------------------------------------
532multiple in scientific number format
533----------------------------------------------------------------------- */
534void doMultiple(double* operandOne, int* powerOne,
535 double operandTwo, int powerTwo){
536(*operandOne) *= operandTwo;
537(*powerOne) += powerTwo;
538}
539
540/* -----------------------------------------------------------------------
541Handles all one operand calculations
542----------------------------------------------------------------------- */
543void oneOperand(void){
544 int k = 0;
545 if (buttonGroup == basicButtons){
546 switch(CAL_BUTTON){
547 case btn_sqr:
548 if (result<0) calStatus = cal_error;
549 else{
550 if (power%2 == 1){
551 result = (mySqrt(result*10))/10;
552 power = (power+1) / 2;
553 }
554 else{
555 result = mySqrt(result);
556 power = power / 2;
557 }
558 calStatus = cal_normal;
559 }
560 break;
561 case btn_square:
562 power *= 2;
563 result *= result;
564 calStatus = cal_normal;
565 break;
566
567 case btn_rec:
568 if (result==0) calStatus = cal_error;
569 else{
570 power = -power;
571 result = 1/result;
572 calStatus = cal_normal;
573 }
574 break;
575 default:
576 calStatus = cal_toDo;
577 break; /* just for the safety */
578 }
579 }
580 else{ /* sciButtons */
581 switch(CAL_BUTTON){
582 case sci_sin:
583 transcendFunc("sin", &result, &power);
584 break;
585 case sci_cos:
586 transcendFunc("cos", &result, &power);
587 break;
588 case sci_fac:
589 if (power<0 || power>8 || result<0 ) calStatus = cal_error;
590 else if(result == 0) {result = 1; power = 0; }
591 else{
592 while(power > 0) {result *= 10; power--;}
593 if ( ( result - (int)result) > MINIMUM )
594 calStatus = cal_error;
595 else {
596 k = result; result = 1;
597 while (k > 1){
598 doMultiple(&result, &power, k, 0);
599 formatResult();
600 k--;
601 }
602 calStatus = cal_normal;
603 }
604 }
605 break;
606 default:
607 calStatus = cal_toDo;
608 break; /* just for the safety */
609 }
610 }
611}
612
613
614/* -----------------------------------------------------------------------
615Handles all two operands calculations
616----------------------------------------------------------------------- */
617void twoOperands(void){
618 switch(oper){
619 case '-':
620 doAdd(&operand, &operandPower, -result, power);
621 break;
622 case '+':
623 doAdd(&operand, &operandPower, result, power);
624 break;
625 case '*':
626 doMultiple(&operand, &operandPower, result, power);
627 break;
628 case '/':
629 if ( ABS(result) > MINIMUM ){
630 doMultiple(&operand, &operandPower, 1/result, -power);
631 }
632 else calStatus = cal_error;
633 break;
634 default: /* ' ' */
635 switchOperands(); /* counter switchOperands() below */
636 break;
637 } /* switch(oper) */
638 switchOperands();
639 clearOper();
640}
641/* -----------------------------------------------------------------------
642move button index
643Invert display new button, invert back previous button
644----------------------------------------------------------------------- */
645void moveButton(void){
646 switch(btn){
647 case BUTTON_LEFT:
648 case BUTTON_LEFT | BUTTON_REPEAT:
649 if (n == 0) n = 4;
650 else n--;
651 break;
652
653 case BUTTON_RIGHT:
654 case BUTTON_RIGHT | BUTTON_REPEAT:
655 if (n == 4) n = 0;
656 else n++;
657 break;
658
659 case BUTTON_UP:
660 case BUTTON_UP | BUTTON_REPEAT:
661 if (m == 0) m = 4;
662 else m--;
663 break;
664
665 case BUTTON_DOWN:
666 case BUTTON_DOWN | BUTTON_REPEAT:
667 if (m == 4) m = 0;
668 else m++;
669 break;
670 }
671
672 rb->lcd_invertrect( X_0_POS + prev_n*REC_WIDTH + 1,
673 Y_1_POS + prev_m*REC_HEIGHT + 1,
674 REC_WIDTH - 1, REC_HEIGHT - 1);
675
676 rb->lcd_invertrect( X_0_POS + n*REC_WIDTH + 1,
677 Y_1_POS + m*REC_HEIGHT + 1,
678 REC_WIDTH - 1, REC_HEIGHT - 1);
679
680 rb->lcd_update_rect( X_0_POS + prev_n*REC_WIDTH + 1,
681 Y_1_POS + prev_m*REC_HEIGHT + 1,
682 REC_WIDTH - 1, REC_HEIGHT - 1);
683
684 rb->lcd_update_rect( X_0_POS + n*REC_WIDTH + 1,
685 Y_1_POS + m*REC_HEIGHT + 1,
686 REC_WIDTH - 1, REC_HEIGHT - 1);
687
688 prev_m = m; prev_n = n;
689
690}
691/* -----------------------------------------------------------------------
692Print buttons when switching 1st and 2nd
693int group = {basicButtons, sciButtons}
694----------------------------------------------------------------------- */
695void printButtonGroups(int group){
696 int i,j,w,h;
697 for (i = 0; i < 5; i++){
698 for (j = 3; j <= 4; j++){
699 rb->lcd_getstringsize( buttonChar[group][i][j],&w,&h);
700 rb->lcd_clearrect( X_0_POS + j*REC_WIDTH + 1,
701 Y_1_POS + i*REC_HEIGHT + 1,
702 REC_WIDTH - 1, REC_HEIGHT - 1);
703 rb->lcd_putsxy( X_0_POS + j*REC_WIDTH + (REC_WIDTH - w)/2,
704 TEXT_2_POS + i*REC_HEIGHT,
705 buttonChar[group][i][j] );
706 }
707 }
708 for (i = 0; i <= 0; i++){
709 for (j = 0; j <= 2; j++){
710 rb->lcd_getstringsize( buttonChar[group][i][j],&w,&h);
711 rb->lcd_clearrect( X_0_POS + j*REC_WIDTH + 1,
712 Y_1_POS + i*REC_HEIGHT + 1,
713 REC_WIDTH - 1, REC_HEIGHT - 1);
714 rb->lcd_putsxy( X_0_POS + j*REC_WIDTH + (REC_WIDTH - w)/2,
715 TEXT_2_POS + i*REC_HEIGHT,
716 buttonChar[group][i][j] );
717 }
718 }
719 rb->lcd_invertrect( X_0_POS + 2*REC_WIDTH + 1,
720 Y_1_POS + 0*REC_HEIGHT + 1,
721 REC_WIDTH - 1, REC_HEIGHT - 1);
722 rb->lcd_update_rect( X_0_POS, Y_1_POS,
723 REC_WIDTH*5, REC_HEIGHT*5);
724}
725/* -----------------------------------------------------------------------
726flash the button pressed
727----------------------------------------------------------------------- */
728void flashButton(int b){
729 int i = b/5; int j = b - i*5;
730 int k;
731 for (k=1*2;k>0;k--){
732 rb->lcd_invertrect( X_0_POS + j*REC_WIDTH + 1,
733 Y_1_POS + i*REC_HEIGHT + 1,
734 REC_WIDTH - 1, REC_HEIGHT - 1);
735 rb->lcd_update_rect( X_0_POS + j*REC_WIDTH + 1,
736 Y_1_POS + i*REC_HEIGHT + 1,
737 REC_WIDTH - 1, REC_HEIGHT - 1);
738
739 if (k!= 1)
740 rb->sleep(HZ/22);
741
742 }
743}
744
745/* -----------------------------------------------------------------------
746pos is the position that needs animation. pos = [1~18]
747----------------------------------------------------------------------- */
748void deleteAnimation(int pos){
749 int k;
750 if (pos<1 || pos >18) return;
751 pos--;
752 rb->lcd_fillrect(1+pos*6, TEXT_1_POS, 6, 8);
753 rb->lcd_update_rect(1+pos*6, TEXT_1_POS, 6, 8);
754
755 for (k=1;k<=4;k++){
756 rb->sleep(HZ/32);
757 rb->lcd_clearrect(1+pos*6, TEXT_1_POS, 6, 8);
758 rb->lcd_fillrect(1+pos*6+1+k, TEXT_1_POS+k,
759 (5-2*k)>0?(5-2*k):1, (7-2*k)>0?(7-2*k):1 );
760 rb->lcd_update_rect(1+pos*6, TEXT_1_POS, 6, 8);
761 }
762
763}
764
765/* -----------------------------------------------------------------------
766result may be one of these formats:
7670
768xxxx.xxxx
7690.xxxx
7700.0000xxxx
771
772formatResult() change result to standard format: 0.xxxx
773if result is close to 0, let it be 0;
774if result is close to 1, let it be 0.1 and power++;
775----------------------------------------------------------------------- */
776void formatResult(void){
777 int resultsign = SIGN(result);
778 result = ABS(result);
779 if(result > MINIMUM ){ /* doesn't check power, might have problem
780 input wouldn't,
781 + - * / of two formatted number wouldn't.
782 only a calculation that makes a formatted
783 number (0.xxxx) less than MINIMUM in only
784 one operation */
785
786 if (result<1){
787 while( (int)(result*10) == 0 ){
788 result *= 10; power--; modifier *= 10;
789 }
790 }
791 else{ /* result >= 1 */
792 while( (int)result != 0 ){
793 result /= 10; power++; modifier /= 10;
794 }
795 } /* if result<1 */
796
797 if (result > (1-MINIMUM)){
798 result = 0.1; power++; modifier /= 10;
799 }
800 result *= resultsign;
801 }
802 else{ result = 0; power = 0; modifier = 0.1; }
803}
804
805/* -----------------------------------------------------------------------
806result2typingbuf() outputs standard format result to typingbuf.
807case SCIENTIFIC_FORMAT, let temppower = 1;
808case temppower > 0: print '.' in the middle
809case temppower <= 0: print '.' in the begining
810----------------------------------------------------------------------- */
811void result2typingbuf(void){
812 bool haveDot = false;
813 char tempchar = 0;
814 int k;
815 double tempresult = ABS(result); /* positive num makes things simple */
816
817 int temppower;
818 if(SCIENTIFIC_FORMAT) temppower = 1; /* output x.xxxx format */
819 else temppower = power;
820
821 double tempmodifier = 1;
822 int count;
823 cleartypingbuf();
824
825 if(tempresult < MINIMUM){ /* if 0,faster display and avoid complication*/
826 typingbuf[0] = ' ';
827 typingbuf[1] = '0';
828 }
829 else{ /* tempresult > 0 */
830 typingbuf[0] = (SIGN(result)<0)?'-':' ';
831
832 typingbufPointer = typingbuf;
833 if(temppower > 0){
834 for (k = 0; k<DIGITLEN+1 ; k++){
835 typingbufPointer++;
836 if(temppower || *(typingbufPointer-1) == '.'){
837 count = 0;
838 tempmodifier = tempmodifier/10;
839 while( (tempresult-tempmodifier*count) >
840 (tempmodifier-MINIMUM)){
841 count++;
842 }
843 tempresult -= tempmodifier*count;
844 tempresult = ABS(tempresult);
845 temppower-- ;
846 *typingbufPointer = count + '0';
847 }
848 else{ /* temppower == 0 */
849 *typingbufPointer = '.';
850 haveDot = true;
851 }
852 } /* for */
853 }
854 else{
855 haveDot = true;
856 typingbufPointer++; *typingbufPointer = '0';
857 typingbufPointer++; *typingbufPointer = '.';
858 for (k = 2; k<DIGITLEN+1 ; k++){
859 typingbufPointer++;
860 count = 0;
861 if ( (-temppower) < (k-1)){
862 tempmodifier = tempmodifier/10;
863 while((tempresult-tempmodifier*count)>(tempmodifier-MINIMUM)){
864 count++;
865
866 }
867 tempresult -= tempmodifier*count;
868 tempresult = ABS(tempresult);
869 temppower-- ;
870 }
871 *typingbufPointer = count + '0';
872 }
873 }
874 /* now, typingbufPointer = typingbuf + 16 */
875 /* backward strip off 0 and '.' */
876 if (haveDot){
877 while( (*typingbufPointer == '0') || (*typingbufPointer == '.')){
878 tempchar = *typingbufPointer;
879 *typingbufPointer = 0;
880 typingbufPointer--;
881 if (tempchar == '.') break;
882 }
883 }
884 typingbuf[DIGITLEN+1] = 0;
885 } /* else tempresult > 0 */
886}
887
888/* -----------------------------------------------------------------------
889printResult() generates LCD display.
890----------------------------------------------------------------------- */
891void printResult(void){
892
893 int k;
894
895 switch_Status:
896 switch(calStatus){
897 case cal_exit:
898 rb->lcd_clear_display();
899 rb->splash(HZ/3, true, "Bye now!");
900 break;
901 case cal_error:
902 clearbuf();
903 rb->snprintf(buf, 19, "%18s","Error");
904 break;
905 case cal_toDo:
906 clearbuf();
907 rb->snprintf(buf, 19, "%18s","Coming soon ^_* ");
908 break;
909
910 case cal_normal:
911 formatResult();
912
913 if( power > 1000 ){ /* power -1 > 999 */
914 calStatus = cal_error;
915 goto switch_Status;
916 }
917 if (power < -998 ) /* power -1 < -999 */
918 clearResult(); /* too small, let it be 0 */
919
920 result2typingbuf();
921 clearbuf();
922
923 buf[0] = oper;
924 buf[1] = ( ABS(memTemp) > MINIMUM )?'M':' ';
925 buf[2] = ' ';
926
927 if(SCIENTIFIC_FORMAT){
928 /* output format: X.XXXX eXXX */
929 if(power > -98){ /* power-1 >= -99, eXXX or e-XX */
930 rb->snprintf(buf+3, 12, "%11s",typingbuf);
931 for(k=14;k<=17;k++) buf[k] = ' ';
932 cleartypingbuf();
933 rb->snprintf(typingbuf, 5, "e%d",power-1);
934 rb->snprintf(buf+14, 5, "%4s",typingbuf);
935 }
936 else{ /* power-1 <= -100, e-XXX */
937 rb->snprintf(buf+2, 12, "%11s",typingbuf);
938 rb->snprintf(buf+13, 6, "e%d",power-1);
939 }
940 }
941 else{
942 rb->snprintf(buf+7, 12, "%11s",typingbuf);
943 } /* if SCIENTIFIC_FORMAT */
944 break;
945 case cal_typing:
946 case cal_dotted:
947 clearbuf();
948 buf[0] = oper;
949 buf[1] = ( ABS(memTemp) > MINIMUM )?'M':' ';
950 for(k=2;k<=6;k++)
951 buf[k] = ' ';
952 rb->snprintf(buf+7, 12, "%11s",typingbuf);
953 break;
954
955 }
956
957 rb->lcd_putsxy(1, TEXT_1_POS,buf);
958 rb->lcd_update_rect(1, TEXT_1_POS, 6*18, 8);
959}
960
961/* -----------------------------------------------------------------------
962Process typing buttons: 1-9, '.', sign
963main operand "result" and typingbuf are processed seperately here.
964----------------------------------------------------------------------- */
965void typingProcess(void){
966 switch( CAL_BUTTON ){
967 case btn_sign:
968 if (calStatus == cal_typing ||
969 calStatus == cal_dotted)
970 typingbuf[0] = (typingbuf[0]=='-')?' ':'-';
971 result = -result;
972 break;
973 case btn_dot:
974 operInputted = false;
975 switch(calStatus){
976 case cal_normal:
977 clearInput();
978 *typingbufPointer = '0';
979 typingbufPointer++;
980 case cal_typing:
981 calStatus = cal_dotted;
982 *typingbufPointer = '.';
983 if (typingbufPointer != typingbuf+DIGITLEN+1)
984 typingbufPointer++;
985 break;
986 default: /* cal_dotted */
987 break;
988 }
989 break;
990 default: /* 0-9 */
991 operInputted = false;
992 /* normal,0; normal,1-9; typing,0; typing,1-9 */
993 switch(calStatus){
994 case cal_normal:
995 if(CAL_BUTTON == btn_0 )
996 break; /* first input is 0, ignore */
997 clearInput();
998 /*no operator means start a new calculation*/
999 if (oper ==' ')
1000 clearOperand();
1001 calStatus = cal_typing;
1002 /* go on typing, no break */
1003 case cal_typing:
1004 case cal_dotted:
1005 switch(CAL_BUTTON){
1006 case btn_0:
1007 *typingbufPointer = '0';
1008 break;
1009 default:
1010 *typingbufPointer=(7+n-3*(m-1))+ '0';
1011 break;
1012 }
1013 if (typingbufPointer!=typingbuf+DIGITLEN+1){
1014 typingbufPointer++;
1015
1016 {/* result processing */
1017 if (calStatus == cal_typing) power++;
1018 if (CAL_BUTTON != btn_0)
1019 result= result +
1020 SIGN(result)*
1021 (7+n-3*(m-1))*modifier;
1022 modifier /= 10;
1023 }
1024 }
1025 else /* last byte always '\0' */
1026 *typingbufPointer = 0;
1027 break;
1028 default: /* cal_error, cal_exit */
1029 break;
1030 }
1031 break; /* default, 0-9 */
1032 } /* switch( CAL_BUTTON ) */
1033}
1034
1035/* -----------------------------------------------------------------------
1036Handle delete operation
1037main operand "result" and typingbuf are processed seperately here.
1038----------------------------------------------------------------------- */
1039void doDelete(void){
1040 deleteAnimation(18);
1041 switch(calStatus){
1042 case cal_dotted:
1043 if (*(typingbufPointer-1) == '.'){
1044 /* if dotted and deleting '.',
1045 change status and delete '.' below */
1046 calStatus = cal_typing;
1047 }
1048 else{ /* if dotted and not deleting '.',
1049 power stays */
1050 power++; /* counter "power--;" below */
1051 }
1052 case cal_typing:
1053 typingbufPointer--;
1054
1055 {/* result processing */ /* 0-9, '.' */
1056 /* if deleting '.', do nothing */
1057 if ( *typingbufPointer != '.'){
1058 power--;
1059 modifier *= 10;
1060 result = result - SIGN(result)*
1061 ((*typingbufPointer)- '0')*modifier;
1062 }
1063 }
1064
1065 *typingbufPointer = 0;
1066
1067 /* if (only one digit left and it's 0)
1068 or no digit left, change status*/
1069 if ( typingbufPointer == typingbuf+1 ||
1070 ( typingbufPointer == typingbuf+2 &&
1071 *(typingbufPointer-1) == '0' ))
1072 calStatus = cal_normal;
1073 break;
1074 default: /* normal, error, exit */
1075 break;
1076 }
1077}
1078/* -----------------------------------------------------------------------
1079Handle buttons on basic screen
1080----------------------------------------------------------------------- */
1081void basicButtonsProcess(void){
1082 switch (btn) {
1083 case BUTTON_PLAY:
1084 if (calStatus == cal_error && (CAL_BUTTON != btn_C) ) break;
1085 flashButton(CAL_BUTTON);
1086 switch( CAL_BUTTON ){
1087 case btn_MR:
1088 operInputted = false;
1089 result = memTemp; power = memTempPower;
1090 calStatus = cal_normal;
1091 break;
1092 case btn_M:
1093 formatResult();
1094 if (memTemp > MINIMUM)
1095 doAdd(&memTemp, &memTempPower, result, power);
1096 else
1097 /* if result is too small and memTemp = 0,
1098 doAdd will not add */
1099 memTemp = result; memTempPower = power;
1100 calStatus = cal_normal;
1101 break;
1102
1103 case btn_C: clearMem(); break;
1104 case btn_CE: clearInput(); break;
1105
1106 case btn_bas:
1107 buttonGroup = sciButtons;
1108 printButtonGroups(buttonGroup);
1109 break;
1110
1111 /* one operand calculation, may be changed to
1112 like sin, cos, log, etc */
1113 case btn_sqr:
1114 case btn_square:
1115 case btn_rec:
1116 formatResult(); /* not necessary, just for safty */
1117 oneOperand();
1118 break;
1119
1120 case_btn_equal: /* F3 shortkey entrance */
1121 case btn_equal:
1122 formatResult();
1123 calStatus = cal_normal;
1124 operInputted = false;
1125 if (oper != ' ') twoOperands();
1126 break;
1127
1128 case btn_div:
1129 case btn_time:
1130 case btn_minus:
1131 case btn_add:
1132 if(!operInputted) {twoOperands(); operInputted = true;}
1133 oper = buttonChar[basicButtons][m][n][0];
1134 case_BUTTON_F2: /* F2 shortkey entrance */
1135 calStatus = cal_normal;
1136 formatResult();
1137 operand = result;
1138 operandPower = power;
1139
1140 break;
1141
1142 case btn_sign:
1143 case btn_dot:
1144 default: /* 0-9 */
1145 typingProcess();
1146 break;
1147 } /* switch (CAL_BUTTON) */
1148 break;
1149
1150 case BUTTON_F2:
1151 if (calStatus == cal_error) break;
1152 if (!operInputted) {twoOperands(); operInputted = true;}
1153 switch (oper){
1154 case ' ':
1155 case '/': oper = '+'; flashButton(btn_add); break;
1156 case '+': oper = '-'; flashButton(btn_minus); break;
1157 case '-': oper = '*'; flashButton(btn_time); break;
1158 case '*': oper = '/'; flashButton(btn_div); break;
1159 }
1160 goto case_BUTTON_F2;
1161 break;
1162 case BUTTON_F3:
1163 if (calStatus == cal_error) break;
1164 flashButton(btn_equal);
1165 goto case_btn_equal;
1166 break;
1167 default: break;
1168 }
1169 printResult();
1170}
1171
1172/* -----------------------------------------------------------------------
1173Handle buttons on scientific screen
1174----------------------------------------------------------------------- */
1175void sciButtonsProcess(void){
1176 switch (btn) {
1177 case BUTTON_PLAY:
1178 if (calStatus == cal_error && (CAL_BUTTON != sci_sci) ) break;
1179 flashButton(CAL_BUTTON);
1180 switch( CAL_BUTTON ){
1181
1182 case sci_pi:
1183 result = PI; power = 0;
1184 calStatus = cal_normal;
1185 break;
1186
1187 case sci_xy: break;
1188
1189 case sci_sci:
1190 buttonGroup = basicButtons;
1191 printButtonGroups(basicButtons);
1192 break;
1193
1194 case sci_fac:
1195 case sci_sin:
1196 case sci_asin:
1197 case sci_cos:
1198 case sci_acos:
1199 case sci_tan:
1200 case sci_atan:
1201 case sci_ln:
1202 case sci_exp:
1203 case sci_log:
1204 formatResult(); /* not necessary, just for safty */
1205 oneOperand();
1206 break;
1207
1208 case btn_sign:
1209 case btn_dot:
1210 default: /* 0-9 */
1211 typingProcess();
1212 break;
1213 } /* switch (CAL_BUTTON) */
1214 break;
1215
1216 case BUTTON_F2:
1217 if (calStatus == cal_error) break;
1218 if (!operInputted) {twoOperands(); operInputted = true;}
1219 switch (oper){
1220 case ' ': oper = '+'; break;
1221 case '/': oper = '+'; deleteAnimation(1); break;
1222 case '+': oper = '-'; deleteAnimation(1); break;
1223 case '-': oper = '*'; deleteAnimation(1); break;
1224 case '*': oper = '/'; deleteAnimation(1); break;
1225 }
1226 calStatus = cal_normal;
1227 formatResult();
1228 operand = result;
1229 operandPower = power;
1230 break;
1231 case BUTTON_F3:
1232 if (calStatus == cal_error) break;
1233 formatResult();
1234 calStatus = cal_normal;
1235 operInputted = false;
1236 if (oper != ' ') twoOperands();
1237 break;
1238 default: break;
1239 }
1240 printResult();
1241}
1242
1243/* -----------------------------------------------------------------------
1244Main();
1245----------------------------------------------------------------------- */
1246enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1247{
1248 TEST_PLUGIN_API(api);
1249 (void)parameter;
1250 rb = api;
1251
1252 /* now go ahead and have fun! */
1253
1254 cal_initial();
1255
1256 while (calStatus != cal_exit ) {
1257 btn = rb->button_get_w_tmo(HZ/2);
1258 switch (btn) {
1259 case BUTTON_PLAY:
1260 case BUTTON_F2:
1261 case BUTTON_F3:
1262 switch(buttonGroup){
1263 case basicButtons:
1264 basicButtonsProcess();
1265 break;
1266 case sciButtons:
1267 sciButtonsProcess();
1268 break;
1269 }
1270 break;
1271
1272 case BUTTON_F1:
1273 switch(calStatus){
1274 case cal_typing:
1275 case cal_dotted:
1276 doDelete();
1277 break;
1278 default: /* cal_normal, cal_error, cal_exit */
1279 clearMem();
1280 break;
1281 }
1282 printResult();
1283 break;
1284
1285 case BUTTON_LEFT:
1286 case BUTTON_LEFT | BUTTON_REPEAT:
1287 case BUTTON_RIGHT:
1288 case BUTTON_RIGHT | BUTTON_REPEAT:
1289 case BUTTON_UP:
1290 case BUTTON_UP | BUTTON_REPEAT:
1291 case BUTTON_DOWN:
1292 case BUTTON_DOWN | BUTTON_REPEAT:
1293 moveButton();
1294 break;
1295 case BUTTON_OFF:
1296 calStatus = cal_exit;
1297 printResult();
1298 break;
1299 case SYS_USB_CONNECTED:
1300 rb->usb_screen();
1301 return PLUGIN_USB_CONNECTED;
1302 break;
1303 } /* switch (btn) */
1304 } /* while (calStatus != cal_exit ) */
1305
1306 /* rb->splash(HZ*2, true, "Hello world!"); */
1307 while (rb->button_get(false));
1308 return PLUGIN_OK;
1309}
1310
1311#endif /* #ifdef HAVE_LCD_BITMAP */