diff options
author | Daniel Stenberg <daniel@haxx.se> | 2004-05-19 09:19:02 +0000 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2004-05-19 09:19:02 +0000 |
commit | 367aac95190e541b3fe71f3cd371c24d89aac844 (patch) | |
tree | d4b78efe571d786f546d49b31c689d8e75b7a702 /apps/plugins/calculator.c | |
parent | b9c02e6851224cd1915016cb13da71f8ac2b905a (diff) |
Isaac's calculator plugin
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4645 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/calculator.c')
-rw-r--r-- | apps/plugins/calculator.c | 1311 |
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 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2004 Pengxuan(Isaac) <tinousus@yahoo.com> + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* + 00 01 21 22 23 43 44 45 65 66 67 87 88 89 109110111 +00 |-----------|-----------|-----------|-----------|-----------| +01 | + | | | | | + | +***********| +***********| +***********| +***********| +***********| + | +***********| +***********| +***********| +***********| +***********| +11 | + | | | | | +12 |-----------|-----------|-----------|-----------|-----------| +13 |-----------|-----------|-----------|-----------|-----------| y1 +14 | + | | | | | + + | | | | | | +22 | + | | | | | +23 |-----------|-----------|-----------|-----------|-----------| y2 +24 | + | | | | | + + | | | | | | +32 | + | | | | | +33 |-----------|-----------|-----------|-----------|-----------| y3 +34 | + | | | | | + + | | | | | | +42 | + | | | | | +43 |-----------|-----------|-----------|-----------|-----------| y4 +44 | + | | | | | + + | | | | | | +52 | + | | | | | +53 |-----------|-----------|-----------|-----------|-----------| y5 +54 | + | | | | | + + | | | | | | +62 | + | | | | | +63 |-----------|-----------|-----------|-----------|-----------| y6 + x0 x1 x2 x3 x4 x5 +*/ + +/*--------------------------------------------------------------------------- +Features: +- Scientific number format core code. Support range 10^-999 ~ 10^999 +- Number of significant figures up to 10 + +Limitations: +- Right now, only accept "num, operator (+,-,*,/), num, =" input sequence. + Input "3, +, 5, -, 2, =", the calculator will only do 5-2 and result = 3 + You have to input "3, +, 5, =, -, 2, =" to get 3+5-2 = 6 + +- "*,/" have no priority. Actually you can't input 3+5*2 yet. + +User Instructions: +use arrow button to move cursor, "play" button to select, "off" button to exit +F1: if typing numbers, it's equal to "Del"; otherwise, equal to "C" +F2: circle input "+, -, *, /" +F3: equal to "=" + +"MR" : load temp memory +"M+" : add currently display to temp memory +"C" : reset calculator +---------------------------------------------------------------------------*/ + +#include "plugin.h" +#ifdef HAVE_LCD_BITMAP +#include "math.h" + +#define REC_HEIGHT 10 /* blank height = 9 */ +#define REC_WIDTH 22 /* blank width = 21 */ + +#define Y_6_POS (LCD_HEIGHT - 1) /* y6 = 63 */ +#define Y_5_POS (Y_6_POS - REC_HEIGHT) /* y5 = 53 */ +#define Y_4_POS (Y_5_POS - REC_HEIGHT) /* y4 = 43 */ +#define Y_3_POS (Y_4_POS - REC_HEIGHT) /* y3 = 33 */ +#define Y_2_POS (Y_3_POS - REC_HEIGHT) /* y2 = 23 */ +#define Y_1_POS (Y_2_POS - REC_HEIGHT) /* y1 = 13 */ +#define Y_0_POS 0 /* y0 = 0 */ + +#define X_0_POS 0 /* x0 = 0 */ +#define X_1_POS (X_0_POS + REC_WIDTH) /* x1 = 22 */ +#define X_2_POS (X_1_POS + REC_WIDTH) /* x2 = 44 */ +#define X_3_POS (X_2_POS + REC_WIDTH) /* x3 = 66 */ +#define X_4_POS (X_3_POS + REC_WIDTH) /* x4 = 88 */ +#define X_5_POS (X_4_POS + REC_WIDTH) /* x5 = 110, column 111 left blank */ + +#define TEXT_1_POS (Y_1_POS-10) /* y1 = 2 */ /* blank height = 12 */ +#define TEXT_2_POS (Y_2_POS-8) /* y2 = 15 */ /* blank height = 9 */ +#define TEXT_3_POS (Y_3_POS-8) /* y3 = 25 */ +#define TEXT_4_POS (Y_4_POS-8) /* y4 = 35 */ +#define TEXT_5_POS (Y_5_POS-8) /* y5 = 45 */ +#define TEXT_6_POS (Y_6_POS-8) /* y6 = 55 */ + +#define SIGN(x) ((x)<0?-1:1) +#define ABS(x) ((x)<0?-(x):(x)) + +static struct plugin_api* rb; + +enum {basicButtons, sciButtons} buttonGroup; +unsigned char* buttonChar[2][5][5] = { + { { "MR" , "M+" , "2nd" , "CE" , "C" }, + { "7" , "8" , "9" , "/" , "sqr" }, + { "4" , "5" , "6" , "*" , "x^2" }, + { "1" , "2" , "3" , "-" , "1/x" }, + { "0" , "+/-", "." , "+" , "=" } }, + + { { "n!" , "PI" , "1st" , "sin" , "asi" }, + { "7" , "8" , "9" , "cos" , "aco" }, + { "4" , "5" , "6" , "tan" , "ata" }, + { "1" , "2" , "3" , "ln" , "e^x" }, + { "0" , "+/-", "." , "log" , "x^y" } } + }; +enum { btn_MR , btn_M , btn_bas , btn_CE , btn_C , + btn_7 , btn_8 , btn_9 , btn_div , btn_sqr , + btn_4 , btn_5 , btn_6 , btn_time , btn_square , + btn_1 , btn_2 , btn_3 , btn_minus , btn_rec , + btn_0 , btn_sign , btn_dot , btn_add , btn_equal + }; +enum { sci_fac, sci_pi , sci_sci , sci_sin , sci_asin , + sci_7 , sci_8 , sci_9 , sci_cos , sci_acos , + sci_4 , sci_5 , sci_6 , sci_tan , sci_atan , + sci_1 , sci_2 , sci_3 , sci_ln , sci_exp , + sci_0 , sci_sign , sci_dot , sci_log , sci_xy + }; + +#define PI 3.14159265358979323846 +#define MINIMUM 0.000000000001 /* e-12 */ + /* ^ ^ ^ ^ */ + /* 123456789abcdef */ + +#define DIGITLEN 10 /* must <= 10 */ +#define SCIENTIFIC_FORMAT ( power < -(DIGITLEN-3) || power > (DIGITLEN)) + /* 0.000 00000 0001 */ + /* ^ ^ ^ ^ ^ ^ */ + /* DIGITLEN 12345 6789a bcdef */ + /* power 12 34567 89abc def */ + /* 10^- 123 45678 9abcd ef */ + +unsigned char buf[19];/* 18 bytes of output line, + buf[0] is operator + buf[1] = 'M' if memTemp is not 0 + buf[2] = ' ' + + if SCIENTIFIC_FORMAT + buf[2]-buf[12] or buf[3]-buf[13] = result; + format X.XXXXXXXX + buf[13] or buf[14] -buf[17] = power; + format eXXX or e-XXX + else + buf[3]-buf[6] = ' '; + buf[7]-buf[17] = result; + + buf[18] = '\0' */ + +unsigned char typingbuf[DIGITLEN+2];/* byte 0 is sign or ' ', + byte 1~DIGITLEN are num and '.' + byte (DIGITLEN+1) is '\0' */ +unsigned char* typingbufPointer = typingbuf; + +double result = 0; /* main operand, format 0.xxxxx */ +int power = 0; /* 10^power */ +double modifier = 0.1; /* position of next input */ +double operand = 0; /* second operand, format 0.xxxxx */ +int operandPower = 0; /* 10^power of second operand */ +char oper = ' '; /* operators: + - * / */ +bool operInputted = false; /* false: do calculation first and + replace current oper + true: just replace current oper */ + +double memTemp = 0; /* temp memory */ +int memTempPower = 0; /* 10^^power of memTemp */ + +int m, n, prev_m, prev_n; /* position index for button */ +#define CAL_BUTTON (m*5+n) + +int btn = BUTTON_NONE; + +/* Status of calculator */ +enum {cal_normal, /* 0, normal status, display result */ + cal_typing, /* 1, currently typing, dot hasn't been typed */ + cal_dotted, /* 2, currently typing, dot already has been typed. */ + cal_error, + cal_exit, + cal_toDo +} calStatus; + +/* constant table for CORDIC algorithm */ +double cordicTable[51][2]= { + /* pow(2,0) - pow(2,-50) atan(pow(2,0) - atan(pow(2,-50) */ + {1e+00, + 7.853981633974483e-01}, + {5e-01, + 4.636476090008061e-01}, + {2.5e-01, + 2.449786631268641e-01}, + {1.25e-01, + 1.243549945467614e-01}, + {6.25e-02, + 6.241880999595735e-02}, + {3.125e-02, + 3.123983343026828e-02}, + {1.5625e-02, + 1.562372862047683e-02}, + {7.8125e-03, + 7.812341060101111e-03}, + {3.90625e-03, + 3.906230131966972e-03}, + {1.953125e-03, + 1.953122516478819e-03}, + {9.765625e-04, + 9.765621895593195e-04}, + {4.8828125e-04, + 4.882812111948983e-04}, + {2.44140625e-04, + 2.441406201493618e-04}, + {1.220703125e-04, + 1.220703118936702e-04}, + {6.103515625e-05, + 6.103515617420877e-05}, + {3.0517578125e-05, + 3.051757811552610e-05}, + {1.52587890625e-05, + 1.525878906131576e-05}, + {7.62939453125e-06, + 7.629394531101970e-06}, + {3.814697265625e-06, + 3.814697265606496e-06}, + {1.9073486328125e-06, + 1.907348632810187e-06}, + {9.5367431640625e-07, + 9.536743164059608e-07}, + {4.76837158203125e-07, + 4.768371582030888e-07}, + {2.384185791015625e-07, + 2.384185791015580e-07}, + {1.1920928955078125e-07, + 1.192092895507807e-07}, + {5.9604644775390625e-08, + 5.960464477539055e-08}, + {2.98023223876953125e-08, + 2.980232238769530e-08}, + {1.490116119384765625e-08, + 1.490116119384765e-08}, + {7.450580596923828125e-09, + 7.450580596923828e-09}, + {3.7252902984619140625e-09, + 3.725290298461914e-09}, + {1.86264514923095703125e-09, + 1.862645149230957e-09}, + {9.31322574615478515625e-10, + 9.313225746154785e-10}, + {4.656612873077392578125e-10, + 4.656612873077393e-10}, + {2.3283064365386962890625e-10, + 2.328306436538696e-10}, + {1.16415321826934814453125e-10, + 1.164153218269348e-10}, + {5.82076609134674072265625e-11, + 5.820766091346741e-11}, + {2.910383045673370361328125e-11, + 2.910383045673370e-11}, + {1.4551915228366851806640625e-11, + 1.455191522836685e-11}, + {7.2759576141834259033203125e-12, + 7.275957614183426e-12}, + {3.63797880709171295166015625e-12, + 3.637978807091713e-12}, + {1.818989403545856475830078125e-12, + 1.818989403545856e-12}, + {9.094947017729282379150390625e-13, + 9.094947017729282e-13}, + {4.5474735088646411895751953125e-13, + 4.547473508864641e-13}, + {2.27373675443232059478759765625e-13, + 2.273736754432321e-13}, + {1.136868377216160297393798828125e-13, + 1.136868377216160e-13}, + {5.684341886080801486968994140625e-14, + 5.684341886080801e-14}, + {2.8421709430404007434844970703125e-14, + 2.842170943040401e-14}, + {1.42108547152020037174224853515625e-14, + 1.421085471520200e-14}, + {7.10542735760100185871124267578125e-15, + 7.105427357601002e-15}, + {3.552713678800500929355621337890625e-15, + 3.552713678800501e-15}, + {1.7763568394002504646778106689453125e-15, + 1.776356839400250e-15}, + {8.8817841970012523233890533447265625e-16, 8.881784197001252e-16} +}; + +void doMultiple(double* operandOne, int* powerOne, + double operandTwo, int powerTwo); +void doAdd (double* operandOne, int* powerOne, + double operandTwo, int powerTwo); +void printResult(void); +void formatResult(void); +void oneOperand(void); + +/* ----------------------------------------------------------------------- +Handy funtions +----------------------------------------------------------------------- */ +void cleartypingbuf(void){ + int k; + for( k=1; k<=(DIGITLEN+1); k++) + typingbuf[k] = 0; + typingbuf[0] = ' '; + typingbufPointer = typingbuf+1; +} +void clearbuf(void){ + int k; + for(k=0;k<18;k++) buf[k]=' '; + buf[18] = 0; +} +void clearResult(void){ + result = 0; + power = 0; + modifier = 0.1; +} +void clearInput(void){ + calStatus = cal_normal; + clearResult(); + cleartypingbuf(); +} +void clearOperand(void){ + operand = 0; + operandPower = 0; +} +void clearMemTemp(void){ + memTemp = 0; + memTempPower = 0; +} +void clearOper(void){ + oper = ' '; + operInputted = false; +} +void clearMem(void){ + clearInput(); + clearMemTemp(); + clearOperand(); + clearOper(); + btn = BUTTON_NONE; +} + +void switchOperands(void){ + double tempr = operand; + int tempp = operandPower; + operand = result; + operandPower = power; + result = tempr; + power = tempp; +} + +/* ----------------------------------------------------------------------- +Initiate calculator +----------------------------------------------------------------------- */ +void cal_initial (void){ + int i,j,w,h; + rb->lcd_setfont(FONT_SYSFIXED); + rb->lcd_clear_display(); + + /* draw lines */ + rb->lcd_drawrect(X_0_POS, Y_0_POS, LCD_WIDTH-1, LCD_HEIGHT); + rb->lcd_drawline(X_0_POS, Y_1_POS-1, X_5_POS, Y_1_POS-1); + for (i = 0; i < 5 ; i++) + rb->lcd_drawline(X_0_POS, Y_1_POS+i*REC_HEIGHT, + X_5_POS, Y_1_POS+i*REC_HEIGHT); + for (i = 0; i < 4 ; i++) + rb->lcd_drawline(X_1_POS+i*REC_WIDTH, Y_1_POS, + X_1_POS+i*REC_WIDTH, Y_6_POS); + + /* draw buttons */ + buttonGroup = sciButtons; + for (i = 0; i < 5; i++){ + for (j = 0; j < 5; j++){ + rb->lcd_getstringsize( buttonChar[buttonGroup][i][j],&w,&h); + rb->lcd_putsxy( X_0_POS + j*REC_WIDTH + (REC_WIDTH - w)/2, + TEXT_2_POS + i*REC_HEIGHT, + buttonChar[buttonGroup][i][j] ); + } + } + + /* initially, invert button "5" */ + m = 2; n = 1; + prev_m = m; prev_n = n; + rb->lcd_invertrect( X_0_POS + n*REC_WIDTH + 1, + Y_1_POS + m*REC_HEIGHT + 1, + REC_WIDTH - 1, REC_HEIGHT - 1); + rb->lcd_update(); + + /* initial mem and output display*/ + clearMem(); + printResult(); + + /* clear button queue */ + while (rb->button_get(false)); +} + +/* ----------------------------------------------------------------------- +mySqrt uses Heron's algorithm, which is the Newtone-Raphson algorhitm +in it's private case for sqrt. +Thanks BlueChip for his intro text and Dave Straayer for the actual name. +----------------------------------------------------------------------- */ +double mySqrt(double square){ + int k = 0; + double temp = 0; + double root= ABS(square+1)/2; + + while( ABS(root - temp) > MINIMUM ){ + temp = root; + root = (square/temp + temp)/2; + k++; + if (k>10000) return 0; + } + + return root; +} +/* ----------------------------------------------------------------------- +transcendFunc uses CORDIC (COordinate Rotation DIgital Computer) method +transcendFunc can do sin,cos,log,exp +input parameter is angle +----------------------------------------------------------------------- */ +void transcendFunc(char* func, double* tt, int* ttPower){ + double t = (*tt)*PI/180; int tPower = *ttPower; + + if (tPower < -998) {calStatus = cal_normal; return;} + if (tPower > 8) {calStatus = cal_error; return;} + *ttPower = 0; + calStatus = cal_normal; + + int sign = 1; + int n = 50; /* n <=50, tables are all <= 50 */ + int j; + double x,y,z,xt,yt,zt; + + if( func[0] =='s' || func[0] =='S') sign = SIGN(t); + else { /* if( func[0] =='c' || func[0] =='C') */ sign = 1; } + t = ABS(t); + + while (tPower > 0){ t *= 10; tPower--; } + while (tPower < 0){ t /= 10; tPower++; } + j = 0; + while (t > j*2*PI) {j++;} + t -= (j-1)*2*PI; + if (PI/2 < t && t < 3*PI/2){ + t = PI - t; + if (func[0] =='c' || func[0] =='C') sign = -1; + } + else if ( 3*PI/2 <= t && t <= 2*PI) t -= 2*PI; + + x = 0.60725293500888; y = 0; z = t; + for (j=1;j<n+2;j++){ + xt = x - SIGN(z) * y*cordicTable[j-1][0]; + yt = y + SIGN(z) * x*cordicTable[j-1][0]; + + zt = z - SIGN(z) * cordicTable[j-1][1]; + x = xt;y=yt;z=zt; + } + if( func[0] =='s' || func[0] =='S') {*tt = sign*y; return;} + else /* if( func[0] =='c' || func[0] =='C')*/ {*tt = sign*x; return;} + +} +/* ----------------------------------------------------------------------- +add in scientific number format +----------------------------------------------------------------------- */ +void doAdd (double* operandOne, int* powerOne, + double operandTwo, int powerTwo){ + + if ( *powerOne >= powerTwo ){ + if (*powerOne - powerTwo <= DIGITLEN+1){ + while (powerTwo < *powerOne){ + operandTwo /=10; + powerTwo++; + } + *operandOne += operandTwo; + } + /*do nothing if operandTwo is too small*/ + } + else{ + if (powerTwo - *powerOne <= DIGITLEN+1){ + while(powerTwo > *powerOne){ + *operandOne /=10; + (*powerOne)++; + } + (*operandOne) += operandTwo; + } + else{/* simply copy operandTwo if operandOne is too small */ + *operandOne = operandTwo; + *powerOne = powerTwo; + } + } +} +/* ----------------------------------------------------------------------- +multiple in scientific number format +----------------------------------------------------------------------- */ +void doMultiple(double* operandOne, int* powerOne, + double operandTwo, int powerTwo){ +(*operandOne) *= operandTwo; +(*powerOne) += powerTwo; +} + +/* ----------------------------------------------------------------------- +Handles all one operand calculations +----------------------------------------------------------------------- */ +void oneOperand(void){ + int k = 0; + if (buttonGroup == basicButtons){ + switch(CAL_BUTTON){ + case btn_sqr: + if (result<0) calStatus = cal_error; + else{ + if (power%2 == 1){ + result = (mySqrt(result*10))/10; + power = (power+1) / 2; + } + else{ + result = mySqrt(result); + power = power / 2; + } + calStatus = cal_normal; + } + break; + case btn_square: + power *= 2; + result *= result; + calStatus = cal_normal; + break; + + case btn_rec: + if (result==0) calStatus = cal_error; + else{ + power = -power; + result = 1/result; + calStatus = cal_normal; + } + break; + default: + calStatus = cal_toDo; + break; /* just for the safety */ + } + } + else{ /* sciButtons */ + switch(CAL_BUTTON){ + case sci_sin: + transcendFunc("sin", &result, &power); + break; + case sci_cos: + transcendFunc("cos", &result, &power); + break; + case sci_fac: + if (power<0 || power>8 || result<0 ) calStatus = cal_error; + else if(result == 0) {result = 1; power = 0; } + else{ + while(power > 0) {result *= 10; power--;} + if ( ( result - (int)result) > MINIMUM ) + calStatus = cal_error; + else { + k = result; result = 1; + while (k > 1){ + doMultiple(&result, &power, k, 0); + formatResult(); + k--; + } + calStatus = cal_normal; + } + } + break; + default: + calStatus = cal_toDo; + break; /* just for the safety */ + } + } +} + + +/* ----------------------------------------------------------------------- +Handles all two operands calculations +----------------------------------------------------------------------- */ +void twoOperands(void){ + switch(oper){ + case '-': + doAdd(&operand, &operandPower, -result, power); + break; + case '+': + doAdd(&operand, &operandPower, result, power); + break; + case '*': + doMultiple(&operand, &operandPower, result, power); + break; + case '/': + if ( ABS(result) > MINIMUM ){ + doMultiple(&operand, &operandPower, 1/result, -power); + } + else calStatus = cal_error; + break; + default: /* ' ' */ + switchOperands(); /* counter switchOperands() below */ + break; + } /* switch(oper) */ + switchOperands(); + clearOper(); +} +/* ----------------------------------------------------------------------- +move button index +Invert display new button, invert back previous button +----------------------------------------------------------------------- */ +void moveButton(void){ + switch(btn){ + case BUTTON_LEFT: + case BUTTON_LEFT | BUTTON_REPEAT: + if (n == 0) n = 4; + else n--; + break; + + case BUTTON_RIGHT: + case BUTTON_RIGHT | BUTTON_REPEAT: + if (n == 4) n = 0; + else n++; + break; + + case BUTTON_UP: + case BUTTON_UP | BUTTON_REPEAT: + if (m == 0) m = 4; + else m--; + break; + + case BUTTON_DOWN: + case BUTTON_DOWN | BUTTON_REPEAT: + if (m == 4) m = 0; + else m++; + break; + } + + rb->lcd_invertrect( X_0_POS + prev_n*REC_WIDTH + 1, + Y_1_POS + prev_m*REC_HEIGHT + 1, + REC_WIDTH - 1, REC_HEIGHT - 1); + + rb->lcd_invertrect( X_0_POS + n*REC_WIDTH + 1, + Y_1_POS + m*REC_HEIGHT + 1, + REC_WIDTH - 1, REC_HEIGHT - 1); + + rb->lcd_update_rect( X_0_POS + prev_n*REC_WIDTH + 1, + Y_1_POS + prev_m*REC_HEIGHT + 1, + REC_WIDTH - 1, REC_HEIGHT - 1); + + rb->lcd_update_rect( X_0_POS + n*REC_WIDTH + 1, + Y_1_POS + m*REC_HEIGHT + 1, + REC_WIDTH - 1, REC_HEIGHT - 1); + + prev_m = m; prev_n = n; + +} +/* ----------------------------------------------------------------------- +Print buttons when switching 1st and 2nd +int group = {basicButtons, sciButtons} +----------------------------------------------------------------------- */ +void printButtonGroups(int group){ + int i,j,w,h; + for (i = 0; i < 5; i++){ + for (j = 3; j <= 4; j++){ + rb->lcd_getstringsize( buttonChar[group][i][j],&w,&h); + rb->lcd_clearrect( X_0_POS + j*REC_WIDTH + 1, + Y_1_POS + i*REC_HEIGHT + 1, + REC_WIDTH - 1, REC_HEIGHT - 1); + rb->lcd_putsxy( X_0_POS + j*REC_WIDTH + (REC_WIDTH - w)/2, + TEXT_2_POS + i*REC_HEIGHT, + buttonChar[group][i][j] ); + } + } + for (i = 0; i <= 0; i++){ + for (j = 0; j <= 2; j++){ + rb->lcd_getstringsize( buttonChar[group][i][j],&w,&h); + rb->lcd_clearrect( X_0_POS + j*REC_WIDTH + 1, + Y_1_POS + i*REC_HEIGHT + 1, + REC_WIDTH - 1, REC_HEIGHT - 1); + rb->lcd_putsxy( X_0_POS + j*REC_WIDTH + (REC_WIDTH - w)/2, + TEXT_2_POS + i*REC_HEIGHT, + buttonChar[group][i][j] ); + } + } + rb->lcd_invertrect( X_0_POS + 2*REC_WIDTH + 1, + Y_1_POS + 0*REC_HEIGHT + 1, + REC_WIDTH - 1, REC_HEIGHT - 1); + rb->lcd_update_rect( X_0_POS, Y_1_POS, + REC_WIDTH*5, REC_HEIGHT*5); +} +/* ----------------------------------------------------------------------- +flash the button pressed +----------------------------------------------------------------------- */ +void flashButton(int b){ + int i = b/5; int j = b - i*5; + int k; + for (k=1*2;k>0;k--){ + rb->lcd_invertrect( X_0_POS + j*REC_WIDTH + 1, + Y_1_POS + i*REC_HEIGHT + 1, + REC_WIDTH - 1, REC_HEIGHT - 1); + rb->lcd_update_rect( X_0_POS + j*REC_WIDTH + 1, + Y_1_POS + i*REC_HEIGHT + 1, + REC_WIDTH - 1, REC_HEIGHT - 1); + + if (k!= 1) + rb->sleep(HZ/22); + + } +} + +/* ----------------------------------------------------------------------- +pos is the position that needs animation. pos = [1~18] +----------------------------------------------------------------------- */ +void deleteAnimation(int pos){ + int k; + if (pos<1 || pos >18) return; + pos--; + rb->lcd_fillrect(1+pos*6, TEXT_1_POS, 6, 8); + rb->lcd_update_rect(1+pos*6, TEXT_1_POS, 6, 8); + + for (k=1;k<=4;k++){ + rb->sleep(HZ/32); + rb->lcd_clearrect(1+pos*6, TEXT_1_POS, 6, 8); + rb->lcd_fillrect(1+pos*6+1+k, TEXT_1_POS+k, + (5-2*k)>0?(5-2*k):1, (7-2*k)>0?(7-2*k):1 ); + rb->lcd_update_rect(1+pos*6, TEXT_1_POS, 6, 8); + } + +} + +/* ----------------------------------------------------------------------- +result may be one of these formats: +0 +xxxx.xxxx +0.xxxx +0.0000xxxx + +formatResult() change result to standard format: 0.xxxx +if result is close to 0, let it be 0; +if result is close to 1, let it be 0.1 and power++; +----------------------------------------------------------------------- */ +void formatResult(void){ + int resultsign = SIGN(result); + result = ABS(result); + if(result > MINIMUM ){ /* doesn't check power, might have problem + input wouldn't, + + - * / of two formatted number wouldn't. + only a calculation that makes a formatted + number (0.xxxx) less than MINIMUM in only + one operation */ + + if (result<1){ + while( (int)(result*10) == 0 ){ + result *= 10; power--; modifier *= 10; + } + } + else{ /* result >= 1 */ + while( (int)result != 0 ){ + result /= 10; power++; modifier /= 10; + } + } /* if result<1 */ + + if (result > (1-MINIMUM)){ + result = 0.1; power++; modifier /= 10; + } + result *= resultsign; + } + else{ result = 0; power = 0; modifier = 0.1; } +} + +/* ----------------------------------------------------------------------- +result2typingbuf() outputs standard format result to typingbuf. +case SCIENTIFIC_FORMAT, let temppower = 1; +case temppower > 0: print '.' in the middle +case temppower <= 0: print '.' in the begining +----------------------------------------------------------------------- */ +void result2typingbuf(void){ + bool haveDot = false; + char tempchar = 0; + int k; + double tempresult = ABS(result); /* positive num makes things simple */ + + int temppower; + if(SCIENTIFIC_FORMAT) temppower = 1; /* output x.xxxx format */ + else temppower = power; + + double tempmodifier = 1; + int count; + cleartypingbuf(); + + if(tempresult < MINIMUM){ /* if 0,faster display and avoid complication*/ + typingbuf[0] = ' '; + typingbuf[1] = '0'; + } + else{ /* tempresult > 0 */ + typingbuf[0] = (SIGN(result)<0)?'-':' '; + + typingbufPointer = typingbuf; + if(temppower > 0){ + for (k = 0; k<DIGITLEN+1 ; k++){ + typingbufPointer++; + if(temppower || *(typingbufPointer-1) == '.'){ + count = 0; + tempmodifier = tempmodifier/10; + while( (tempresult-tempmodifier*count) > + (tempmodifier-MINIMUM)){ + count++; + } + tempresult -= tempmodifier*count; + tempresult = ABS(tempresult); + temppower-- ; + *typingbufPointer = count + '0'; + } + else{ /* temppower == 0 */ + *typingbufPointer = '.'; + haveDot = true; + } + } /* for */ + } + else{ + haveDot = true; + typingbufPointer++; *typingbufPointer = '0'; + typingbufPointer++; *typingbufPointer = '.'; + for (k = 2; k<DIGITLEN+1 ; k++){ + typingbufPointer++; + count = 0; + if ( (-temppower) < (k-1)){ + tempmodifier = tempmodifier/10; + while((tempresult-tempmodifier*count)>(tempmodifier-MINIMUM)){ + count++; + + } + tempresult -= tempmodifier*count; + tempresult = ABS(tempresult); + temppower-- ; + } + *typingbufPointer = count + '0'; + } + } + /* now, typingbufPointer = typingbuf + 16 */ + /* backward strip off 0 and '.' */ + if (haveDot){ + while( (*typingbufPointer == '0') || (*typingbufPointer == '.')){ + tempchar = *typingbufPointer; + *typingbufPointer = 0; + typingbufPointer--; + if (tempchar == '.') break; + } + } + typingbuf[DIGITLEN+1] = 0; + } /* else tempresult > 0 */ +} + +/* ----------------------------------------------------------------------- +printResult() generates LCD display. +----------------------------------------------------------------------- */ +void printResult(void){ + + int k; + + switch_Status: + switch(calStatus){ + case cal_exit: + rb->lcd_clear_display(); + rb->splash(HZ/3, true, "Bye now!"); + break; + case cal_error: + clearbuf(); + rb->snprintf(buf, 19, "%18s","Error"); + break; + case cal_toDo: + clearbuf(); + rb->snprintf(buf, 19, "%18s","Coming soon ^_* "); + break; + + case cal_normal: + formatResult(); + + if( power > 1000 ){ /* power -1 > 999 */ + calStatus = cal_error; + goto switch_Status; + } + if (power < -998 ) /* power -1 < -999 */ + clearResult(); /* too small, let it be 0 */ + + result2typingbuf(); + clearbuf(); + + buf[0] = oper; + buf[1] = ( ABS(memTemp) > MINIMUM )?'M':' '; + buf[2] = ' '; + + if(SCIENTIFIC_FORMAT){ + /* output format: X.XXXX eXXX */ + if(power > -98){ /* power-1 >= -99, eXXX or e-XX */ + rb->snprintf(buf+3, 12, "%11s",typingbuf); + for(k=14;k<=17;k++) buf[k] = ' '; + cleartypingbuf(); + rb->snprintf(typingbuf, 5, "e%d",power-1); + rb->snprintf(buf+14, 5, "%4s",typingbuf); + } + else{ /* power-1 <= -100, e-XXX */ + rb->snprintf(buf+2, 12, "%11s",typingbuf); + rb->snprintf(buf+13, 6, "e%d",power-1); + } + } + else{ + rb->snprintf(buf+7, 12, "%11s",typingbuf); + } /* if SCIENTIFIC_FORMAT */ + break; + case cal_typing: + case cal_dotted: + clearbuf(); + buf[0] = oper; + buf[1] = ( ABS(memTemp) > MINIMUM )?'M':' '; + for(k=2;k<=6;k++) + buf[k] = ' '; + rb->snprintf(buf+7, 12, "%11s",typingbuf); + break; + + } + + rb->lcd_putsxy(1, TEXT_1_POS,buf); + rb->lcd_update_rect(1, TEXT_1_POS, 6*18, 8); +} + +/* ----------------------------------------------------------------------- +Process typing buttons: 1-9, '.', sign +main operand "result" and typingbuf are processed seperately here. +----------------------------------------------------------------------- */ +void typingProcess(void){ + switch( CAL_BUTTON ){ + case btn_sign: + if (calStatus == cal_typing || + calStatus == cal_dotted) + typingbuf[0] = (typingbuf[0]=='-')?' ':'-'; + result = -result; + break; + case btn_dot: + operInputted = false; + switch(calStatus){ + case cal_normal: + clearInput(); + *typingbufPointer = '0'; + typingbufPointer++; + case cal_typing: + calStatus = cal_dotted; + *typingbufPointer = '.'; + if (typingbufPointer != typingbuf+DIGITLEN+1) + typingbufPointer++; + break; + default: /* cal_dotted */ + break; + } + break; + default: /* 0-9 */ + operInputted = false; + /* normal,0; normal,1-9; typing,0; typing,1-9 */ + switch(calStatus){ + case cal_normal: + if(CAL_BUTTON == btn_0 ) + break; /* first input is 0, ignore */ + clearInput(); + /*no operator means start a new calculation*/ + if (oper ==' ') + clearOperand(); + calStatus = cal_typing; + /* go on typing, no break */ + case cal_typing: + case cal_dotted: + switch(CAL_BUTTON){ + case btn_0: + *typingbufPointer = '0'; + break; + default: + *typingbufPointer=(7+n-3*(m-1))+ '0'; + break; + } + if (typingbufPointer!=typingbuf+DIGITLEN+1){ + typingbufPointer++; + + {/* result processing */ + if (calStatus == cal_typing) power++; + if (CAL_BUTTON != btn_0) + result= result + + SIGN(result)* + (7+n-3*(m-1))*modifier; + modifier /= 10; + } + } + else /* last byte always '\0' */ + *typingbufPointer = 0; + break; + default: /* cal_error, cal_exit */ + break; + } + break; /* default, 0-9 */ + } /* switch( CAL_BUTTON ) */ +} + +/* ----------------------------------------------------------------------- +Handle delete operation +main operand "result" and typingbuf are processed seperately here. +----------------------------------------------------------------------- */ +void doDelete(void){ + deleteAnimation(18); + switch(calStatus){ + case cal_dotted: + if (*(typingbufPointer-1) == '.'){ + /* if dotted and deleting '.', + change status and delete '.' below */ + calStatus = cal_typing; + } + else{ /* if dotted and not deleting '.', + power stays */ + power++; /* counter "power--;" below */ + } + case cal_typing: + typingbufPointer--; + + {/* result processing */ /* 0-9, '.' */ + /* if deleting '.', do nothing */ + if ( *typingbufPointer != '.'){ + power--; + modifier *= 10; + result = result - SIGN(result)* + ((*typingbufPointer)- '0')*modifier; + } + } + + *typingbufPointer = 0; + + /* if (only one digit left and it's 0) + or no digit left, change status*/ + if ( typingbufPointer == typingbuf+1 || + ( typingbufPointer == typingbuf+2 && + *(typingbufPointer-1) == '0' )) + calStatus = cal_normal; + break; + default: /* normal, error, exit */ + break; + } +} +/* ----------------------------------------------------------------------- +Handle buttons on basic screen +----------------------------------------------------------------------- */ +void basicButtonsProcess(void){ + switch (btn) { + case BUTTON_PLAY: + if (calStatus == cal_error && (CAL_BUTTON != btn_C) ) break; + flashButton(CAL_BUTTON); + switch( CAL_BUTTON ){ + case btn_MR: + operInputted = false; + result = memTemp; power = memTempPower; + calStatus = cal_normal; + break; + case btn_M: + formatResult(); + if (memTemp > MINIMUM) + doAdd(&memTemp, &memTempPower, result, power); + else + /* if result is too small and memTemp = 0, + doAdd will not add */ + memTemp = result; memTempPower = power; + calStatus = cal_normal; + break; + + case btn_C: clearMem(); break; + case btn_CE: clearInput(); break; + + case btn_bas: + buttonGroup = sciButtons; + printButtonGroups(buttonGroup); + break; + + /* one operand calculation, may be changed to + like sin, cos, log, etc */ + case btn_sqr: + case btn_square: + case btn_rec: + formatResult(); /* not necessary, just for safty */ + oneOperand(); + break; + + case_btn_equal: /* F3 shortkey entrance */ + case btn_equal: + formatResult(); + calStatus = cal_normal; + operInputted = false; + if (oper != ' ') twoOperands(); + break; + + case btn_div: + case btn_time: + case btn_minus: + case btn_add: + if(!operInputted) {twoOperands(); operInputted = true;} + oper = buttonChar[basicButtons][m][n][0]; + case_BUTTON_F2: /* F2 shortkey entrance */ + calStatus = cal_normal; + formatResult(); + operand = result; + operandPower = power; + + break; + + case btn_sign: + case btn_dot: + default: /* 0-9 */ + typingProcess(); + break; + } /* switch (CAL_BUTTON) */ + break; + + case BUTTON_F2: + if (calStatus == cal_error) break; + if (!operInputted) {twoOperands(); operInputted = true;} + switch (oper){ + case ' ': + case '/': oper = '+'; flashButton(btn_add); break; + case '+': oper = '-'; flashButton(btn_minus); break; + case '-': oper = '*'; flashButton(btn_time); break; + case '*': oper = '/'; flashButton(btn_div); break; + } + goto case_BUTTON_F2; + break; + case BUTTON_F3: + if (calStatus == cal_error) break; + flashButton(btn_equal); + goto case_btn_equal; + break; + default: break; + } + printResult(); +} + +/* ----------------------------------------------------------------------- +Handle buttons on scientific screen +----------------------------------------------------------------------- */ +void sciButtonsProcess(void){ + switch (btn) { + case BUTTON_PLAY: + if (calStatus == cal_error && (CAL_BUTTON != sci_sci) ) break; + flashButton(CAL_BUTTON); + switch( CAL_BUTTON ){ + + case sci_pi: + result = PI; power = 0; + calStatus = cal_normal; + break; + + case sci_xy: break; + + case sci_sci: + buttonGroup = basicButtons; + printButtonGroups(basicButtons); + break; + + case sci_fac: + case sci_sin: + case sci_asin: + case sci_cos: + case sci_acos: + case sci_tan: + case sci_atan: + case sci_ln: + case sci_exp: + case sci_log: + formatResult(); /* not necessary, just for safty */ + oneOperand(); + break; + + case btn_sign: + case btn_dot: + default: /* 0-9 */ + typingProcess(); + break; + } /* switch (CAL_BUTTON) */ + break; + + case BUTTON_F2: + if (calStatus == cal_error) break; + if (!operInputted) {twoOperands(); operInputted = true;} + switch (oper){ + case ' ': oper = '+'; break; + case '/': oper = '+'; deleteAnimation(1); break; + case '+': oper = '-'; deleteAnimation(1); break; + case '-': oper = '*'; deleteAnimation(1); break; + case '*': oper = '/'; deleteAnimation(1); break; + } + calStatus = cal_normal; + formatResult(); + operand = result; + operandPower = power; + break; + case BUTTON_F3: + if (calStatus == cal_error) break; + formatResult(); + calStatus = cal_normal; + operInputted = false; + if (oper != ' ') twoOperands(); + break; + default: break; + } + printResult(); +} + +/* ----------------------------------------------------------------------- +Main(); +----------------------------------------------------------------------- */ +enum plugin_status plugin_start(struct plugin_api* api, void* parameter) +{ + TEST_PLUGIN_API(api); + (void)parameter; + rb = api; + + /* now go ahead and have fun! */ + + cal_initial(); + + while (calStatus != cal_exit ) { + btn = rb->button_get_w_tmo(HZ/2); + switch (btn) { + case BUTTON_PLAY: + case BUTTON_F2: + case BUTTON_F3: + switch(buttonGroup){ + case basicButtons: + basicButtonsProcess(); + break; + case sciButtons: + sciButtonsProcess(); + break; + } + break; + + case BUTTON_F1: + switch(calStatus){ + case cal_typing: + case cal_dotted: + doDelete(); + break; + default: /* cal_normal, cal_error, cal_exit */ + clearMem(); + break; + } + printResult(); + break; + + case BUTTON_LEFT: + case BUTTON_LEFT | BUTTON_REPEAT: + case BUTTON_RIGHT: + case BUTTON_RIGHT | BUTTON_REPEAT: + case BUTTON_UP: + case BUTTON_UP | BUTTON_REPEAT: + case BUTTON_DOWN: + case BUTTON_DOWN | BUTTON_REPEAT: + moveButton(); + break; + case BUTTON_OFF: + calStatus = cal_exit; + printResult(); + break; + case SYS_USB_CONNECTED: + rb->usb_screen(); + return PLUGIN_USB_CONNECTED; + break; + } /* switch (btn) */ + } /* while (calStatus != cal_exit ) */ + + /* rb->splash(HZ*2, true, "Hello world!"); */ + while (rb->button_get(false)); + return PLUGIN_OK; +} + +#endif /* #ifdef HAVE_LCD_BITMAP */ |