/* ECE 476 SPRING 2003 FINAL PROJECT: GRAPHING CALCULATOR Jonathan Wang (jdw24) & Jeannette Lukito (jl259) This code contains all of our three state machines to run the graphing calculator using a TV and two keypads. This program is optimized for MEGA32 with 16MHz crystal. Keypad one uses PORTA and keypad two uses PORTB The TV uses PORTC. For debugging purposes, we have set up PORTD to hyperterminal. */ //video gen and sound //D.5 is sync:1000 ohm + diode to 75 ohm resistor //D.6 is video:330 ohm + diode to 75 ohm resistor //C.0 is sound #pragma regalloc- //I allocate the registers myself #pragma optsize- //optimize for speed #include #include #include #include #include #include //cycles = 63.625 * 16 Note NTSC is 63.55 //but this line duration makes each frame exactly 1/60 sec //which is nice for keeping a realtime clock #define lineTime 1018 #define begin { #define end } #define ScreenTop 30 #define ScreenBot 230 #define T0reload 256-60 #define width 126 #define maxkeys 16 // Different states of state machines #define NoPush 30 #define MaybePush 31 #define Pushed 32 #define MaybeNoPush 33 #define recorded 34 #define init 35 #define parseA 36 #define Idle 37 #define clearScreen1 38 #define clearScreen2 39 #define clearScreen3 40 #define printTrig 41 #define BeginGraph 42 #define deleteOnScreen 43 #define paramInput 44 #define Graph 45 #define GraphInit1 46 #define GraphInit2 47 #define DoneGraph 48 #define parseB 49 #define calculateNow 50 #define GraphInit3 51 //Calculate logic #define divide 13 #define multiply 14 #define subtract 15 #define add 16 #define sine 21 #define cosine 22 #define tangent 23 #define expon 24 #define pow 25 #define arcsin 26 #define arccos 27 #define arctan 28 #define ln 29 #define pi 3.1415926535 #define eConst 2.7182818284 //NOTE that v1 to v8 and i must be in registers! register char v1 @4; register char v2 @5; register char v3 @6; register char v4 @7; register char v5 @8; register char v6 @9; register char v7 @10; register char v8 @11; register int i @12; #pragma regalloc+ // Debugging char instr[10], outstr[10]; // State machines Vars char butnum1, butnum2, maybe; unsigned char Statekey1, Statekey2, Statekey3, key; // Input parsing char Aarray[20], Barray[20], calculation[20], resultStr[20]; char oploc, xloc, yloc, text[15]; // Flags int calc_done, graph_done, currentInp, precMode; // Scientific vars float result, A, B, powRes; // Graphing vars float inputA, inputB, inputC; float xCoord, yCoord, xGraph, yGraph, xGraphold, yGraphold; float xMin, xMax, yMin, yMax; float Binput, gran; int lineGraph; char graphCommand, input[6]; // Error checking inputs char err, decErrCount, negErrCount, undefErr, boundErr, numEntry; // Software timer and counters char t; int time, k, j; // TV int LineCount; char syncON, syncOFF; char screen[1600]; // text stored to flash memory to minimize memory location flash char cu1[]="SCIENTIFIC"; flash char cu2[]="GRAPHING"; flash char cu3[]="MODE"; flash char sinSign[]="SIN"; flash char cosSign[]="COS"; flash char tanSign[]="TAN"; flash char asinSign[]="ASIN"; flash char acosSign[]="ACOS"; flash char atanSign[]="ATAN"; flash char lnSign[]="LN"; flash char pollSin[] ="A SIN (BX+C)"; flash char pollCos[] ="A COS (BX+C)"; flash char pollTan[] ="A TAN (BX+C)"; flash char pollaSin[] ="A ASIN (BX+C)"; flash char pollaCos[] ="A ACOS (BX+C)"; flash char pollaTan[] ="A ATAN (BX+C)"; flash char pollLn[] = "A LN (BX)"; flash char pollPoly[] ="(AX+B)^C"; flash char pollexp[] ="A EXP^(BX)"; flash char pollA[]="A: "; flash char pollB[]="B: "; flash char pollC[]="C: "; flash char dotMode[]="DOT "; flash char lineMode[]="LINE"; flash char syntax[]="SYNTAX ERROR"; flash char undef[]="UNDEF"; flash char bigVal[]="INVALID ENTRY"; //Point plot lookup table flash char pos[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; flash unsigned char keytbl[16]={0xee, 0xed, 0xeb, 0xe7, 0xde, 0xdd, 0xdb, 0xd7, 0xbe, 0xbd, 0xbb, 0xb7, 0x7e, 0x7d, 0x7b, 0x77}; // TV print lookup talbe flash unsigned char numtblprint[17]={0, 49, 52, 55, 48, 50, 53, 56, 46, 51, 54, 57, 36, 47, 42, 45, 43}; // keypads look table according to allocated numbers for calculation flash unsigned char numtblone[17]={0, 1, 4, 7, 0, 2, 5, 8, 10, 3, 6, 9, 11, 13, 14, 15, 16}; flash unsigned char numtbltwo[17]={0, 17, 21, 25, 29, 18, 22, 26, 30, 19, 23, 27, 31, 20, 24, 28, 32}; //=============================== //3x5 font numbers, then letters //packed two per definition for fast //copy to the screen at x-position divisible by 4 flash char smallbitmap[53][5]={ //blank -0 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b00000000, //sqrt - 1 0b00000000, 0b00100010, 0b00100010, 0b10101010, 0b01000100, //e - 2 0b11101110, 0b10101010, 0b11101110, 0b10001000, 0b11101110, //n - 3 0b00000000, 0b00000000, 0b11001100, 0b10101010, 0b10101010, //(-) -4 0b00000000, 0b00000000, 0b01100110, 0b00000000, 0b00000000, //no need -5 0b11101110, 0b10101010, 0b10101010, 0b10101010, 0b11101110, //no need -6 0b11101110, 0b10101010, 0b10101010, 0b10101010, 0b11101110, //no need -7 0b11101110, 0b10101010, 0b10101010, 0b10101010, 0b11101110, //( -8 0b01000100, 0b10001000, 0b10001000, 0b10001000, 0b01000100, // ) -9 0b01000100, 0b00100010, 0b00100010, 0b00100010, 0b01000100, //* - 10 0b00000000, 0b10101010, 0b01000100, 0b10101010, 0b00000000, //+ - 11 0b00000000, 0b01000100, 0b11101110, 0b01000100, 0b00000000, //^ - 12 0b01000100, 0b10101010, 0b00000000, 0b00000000, 0b00000000, //- - 13 0b00000000, 0b00000000, 0b11101110, 0b00000000, 0b00000000, //. -14 0b00000000, 0b00000000, 0b00000000, 0b00000000, 0b01000100, //div - 15 0b01000100, 0b00000000, 0b11101110, 0b00000000, 0b01000100, //0 - 16 0b11101110, 0b10101010, 0b10101010, 0b10101010, 0b11101110, //1 -17 0b01000100, 0b11001100, 0b01000100, 0b01000100, 0b11101110, //2 -18 0b11101110, 0b00100010, 0b11101110, 0b10001000, 0b11101110, //3 -19 0b11101110, 0b00100010, 0b11101110, 0b00100010, 0b11101110, //4 -20 0b10101010, 0b10101010, 0b11101110, 0b00100010, 0b00100010, //5 -21 0b11101110, 0b10001000, 0b11101110, 0b00100010, 0b11101110, //6 -22 0b11001100, 0b10001000, 0b11101110, 0b10101010, 0b11101110, //7 -23 0b11101110, 0b00100010, 0b01000100, 0b10001000, 0b10001000, //8 -24 0b11101110, 0b10101010, 0b11101110, 0b10101010, 0b11101110, //9 -25 0b11101110, 0b10101010, 0b11101110, 0b00100010, 0b01100110, //: -26 0b00000000, 0b01000010, 0b00000000, 0b01000010, 0b00000000, //A - 27 0b11101110, 0b10101010, 0b11101110, 0b10101010, 0b10101010, //B - 28 0b11001100, 0b10101010, 0b11101110, 0b10101010, 0b11001100, //C - 29 0b11101110, 0b10001000, 0b10001000, 0b10001000, 0b11101110, //D - 30 0b11001100, 0b10101010, 0b10101010, 0b10101010, 0b11001100, //E - 31 0b11101110, 0b10001000, 0b11101110, 0b10001000, 0b11101110, //F - 32 0b11101110, 0b10001000, 0b11101110, 0b10001000, 0b10001000, //G - 33 0b11101110, 0b10001000, 0b10001000, 0b10101010, 0b11101110, //H - 34 0b10101010, 0b10101010, 0b11101110, 0b10101010, 0b10101010, //I - 35 0b11101110, 0b01000100, 0b01000100, 0b01000100, 0b11101110, //J - 36 0b00100010, 0b00100010, 0b00100010, 0b10101010, 0b11101110, //K - 37 0b10001000, 0b10101010, 0b11001100, 0b11001100, 0b10101010, //L - 38 0b10001000, 0b10001000, 0b10001000, 0b10001000, 0b11101110, //M - 39 0b10101010, 0b11101110, 0b10101010, 0b10101010, 0b10101010, //N - 40 0b10101010, 0b11101110, 0b11101110, 0b10101010, 0b10101010, //O - 41 0b01000100, 0b10101010, 0b10101010, 0b10101010, 0b01000100, //P - 42 0b11101110, 0b10101010, 0b11101110, 0b10001000, 0b10001000, //Q - 43 0b01000100, 0b10101010, 0b10101010, 0b11101110, 0b01100110, //R - 44 0b11101110, 0b10101010, 0b11001100, 0b11101110, 0b10101010, //S - 45 0b11101110, 0b10001000, 0b11101110, 0b00100010, 0b11101110, //T - 46 0b11101110, 0b01000100, 0b01000100, 0b01000100, 0b01000100, //U - 47 0b10101010, 0b10101010, 0b10101010, 0b10101010, 0b11101110, //V - 48 0b10101010, 0b10101010, 0b10101010, 0b10101010, 0b01000100, //W - 49 0b10101010, 0b10101010, 0b11101110, 0b11101110, 0b10101010, //X - 50 0b00000000, 0b10101010, 0b01000100, 0b01000100, 0b10101010, //Y - 51 0b10101010, 0b10101010, 0b01000100, 0b01000100, 0b01000100, //Z - 52 0b11101110, 0b00100010, 0b01000100, 0b10001000, 0b11101110 }; //=============================== //Calling keypad1 routine void call_keypad1(void) { //get lower nibble DDRA = 0x0f; PORTA = 0xf0; delay_us(5); key = PINA; //get upper nibble DDRA = 0xf0; PORTA = 0x0f; delay_us(5); key = key | PINA; //find matching keycode in keytbl if (key != 0xff) { for (butnum1=0; butnum1=ScreenTop) begin //compute byte index for beginning of the next line //left-shift 4 would be individual lines // <<3 means line-double the pixels //The 0xfff8 truncates the odd line bit //i=(LineCount-ScreenTop)<<3 & 0xfff8; // #asm push r16 lds r12, _LineCount lds r13, _LineCount+1 ldi r16, 30 sub r12, r16 ldi r16,0 sbc r13, r16 lsl r12 rol r13 lsl r12 rol r13 lsl r12 rol r13 mov r16,r12 andi r16,0xf0 mov r12,r16 pop r16 #endasm //load 16 registers with screen info #asm push r14 push r15 push r16 push r17 push r18 push r19 push r26 push r27 ldi r26,low(_screen) ;base address of screen ldi r27,high(_screen) add r26,r12 ;offset into screen (add i) adc r27,r13 ld r4,x+ ;load 16 registers and inc pointer ld r5,x+ ld r6,x+ ld r7,x+ ld r8,x+ ld r9,x+ ld r10,x+ ld r11,x+ ld r12,x+ ld r13,x+ ld r14,x+ ld r15,x+ ld r16,x+ ld r17,x+ ld r18,x+ ld r19,x pop r27 pop r26 #endasm delay_us(4); //adjust to center image on screen //blast 16 bytes to the screen #asm ;but first a macro to make the code shorter ;the macro takes a register number as a parameter ;and dumps its bits serially to PORTC.6 ;the nop can be eliminated to make the display narrower .macro videobits ;regnum BST @0,7 IN R30,0x15 BLD R30,6 nop OUT 0x15,R30 BST @0,6 IN R30,0x15 BLD R30,6 nop OUT 0x15,R30 BST @0,5 IN R30,0x15 BLD R30,6 nop OUT 0x15,R30 BST @0,4 IN R30,0x15 BLD R30,6 nop OUT 0x15,R30 BST @0,3 IN R30,0x15 BLD R30,6 nop OUT 0x15,R30 BST @0,2 IN R30,0x15 BLD R30,6 nop OUT 0x15,R30 BST @0,1 IN R30,0x15 BLD R30,6 nop OUT 0x15,R30 BST @0,0 IN R30,0x15 BLD R30,6 nop OUT 0x15,R30 .endm videobits r4 ;video line -- byte 1 videobits r5 ;byte 2 videobits r6 ;byte 3 videobits r7 ;byte 4 videobits r8 ;byte 5 videobits r9 ;byte 6 videobits r10 ;byte 7 videobits r11 ;byte 8 videobits r12 ;byte 9 videobits r13 ;byte 10 videobits r14 ;byte 11 videobits r15 ;byte 12 videobits r16 ;byte 13 videobits r17 ;byte 14 videobits r18 ;byte 15 videobits r19 ;byte 16 clt ;clear video after the last pixel on the line IN R30,0x15 BLD R30,6 OUT 0x15,R30 pop r19 pop r18 pop r17 pop r16 pop r15 pop r14 #endasm end end #pragma warn+ //================================= //plot one point //at x,y with color 1=white 0=black 2=invert #pragma warn- void video_pt(char x, char y, char c) { #asm ; i=(x>>3) + ((int)y<<4) ;the byte with the pixel in it push r16 ldd r30,y+2 ;get x lsr r30 lsr r30 lsr r30 ;divide x by 8 ldd r12,y+1 ;get y lsl r12 ;mult y by 16 clr r13 lsl r12 rol r13 lsl r12 rol r13 lsl r12 rol r13 add r12, r30 ;add in x/8 ;v2 = screen[i] ;r5 ;v3 = pos[x & 7];r6 ;v4 = c r7 ldi r30,low(_screen) ldi r31,high(_screen) add r30, r12 adc r31, r13 ld r5,Z ;get screen byte ldd r26,y+2 ;get x ldi r27,0 andi r26,0x07 ;form x & 7 ldi r30,low(_pos*2) ldi r31,high(_pos*2) add r30,r26 adc r31,r27 lpm r6,Z ld r16,y ;get c ;if (v4==1) screen[i] = v2 | v3 ; ;if (v4==0) screen[i] = v2 & ~v3; ;if (v4==2) screen[i] = v2 ^ v3 ; cpi r16,1 brne tst0 or r5,r6 tst0: cpi r16,0 brne tst2 com r6 and r5,r6 tst2: cpi r16,2 brne writescrn eor r5,r6 writescrn: ldi r30,low(_screen) ldi r31,high(_screen) add r30, r12 adc r31, r13 st Z, r5 ;write the byte back to the screen pop r16 #endasm } #pragma warn+ //================================= // put a small character on the screen // x-cood must be on divisible by 4 // c is index into bitmap void video_smallchar(char x, char y, char c) { char mask; //printf("x= %d y= %d \r\n", x, y); i=((int)x>>3) + ((int)y<<4) ; if (x == (x & 0xf8)) mask = 0x0f; else mask = 0xf0; screen[i] = (screen[i] & mask) | (smallbitmap[c][0] & ~mask); screen[i+16] = (screen[i+16] & mask) | (smallbitmap[c][1] & ~mask); screen[i+32] = (screen[i+32] & mask) | (smallbitmap[c][2] & ~mask); screen[i+48] = (screen[i+48] & mask) | (smallbitmap[c][3] & ~mask); screen[i+64] = (screen[i+64] & mask) | (smallbitmap[c][4] & ~mask); } //================================= // put a string of small characters on the screen // x-cood must be on divisible by 4 void video_putsmalls(char x, char y, char *str) { char i; i=0; while(str[i]!=0) { //string is b/w ascii 0x20->0x3a( space -> : ) if (str[i]>=0x20 && str[i]<=0x3a) video_smallchar(x,y,str[i]-0x20); // if string is ^ else if(str[i]==0x5e) video_smallchar(x,y,12); // else string is an alphabet else video_smallchar(x,y,str[i]-0x40+26); x = x+4; i++; } } //================================= //plot a line //at x1,y1 to x2,y2 with color 1=white 0=black 2=invert //NOTE: this function requires signed chars //Code is from David Rodgers, //"Procedural Elements of Computer Graphics",1985 void video_line(char x1, char y1, char x2, char y2, char c) { int e; signed char dx,dy,j, temp; signed char s1,s2, xchange; signed char x,y; x = x1; y = y1; dx = cabs(x2-x1); dy = cabs(y2-y1); s1 = csign(x2-x1); s2 = csign(y2-y1); xchange = 0; if (dy>dx) { temp = dx; dx = dy; dy = temp; xchange = 1; } e = ((int)dy<<1) - dx; for (j=0; j<=dx; j++) { video_pt(x,y,c) ; if (e>=0) { if (xchange==1) x = x + s1; else y = y + s2; e = e - ((int)dx<<1); } if (xchange==1) y = y + s2; else x = x + s1; e = e + ((int)dy<<1); } } //================================= //return the value of one point //at x,y with color 1=white 0=black 2=invert char video_set(char x, char y) { //The following construction //detects exactly one bit at the x,y location i=((int)x>>3) + ((int)y<<4) ; return ( screen[i] & 1<<(7-(x & 0x7))); } //================================= // Returns the result of taking A to // the power of B. // However, this simple function can only use // integer exponents and cannot handle floating point exp. float power(float A, float B) { int powCount; powRes=A; // Keep multiplying A with itself for(powCount=1;powCount<(int)B;powCount++) { powRes=powRes*A; ftoa(powRes, 2, outstr); } // if exponent is zero, result will // always equal to 1 if(B==0) powRes=1; return powRes; } //================================== // This function prints to the TV a notification // that user have invalid operation. void Myerror(char err) { // if user have entered some syntax error if(err==1) strncpyf(text, syntax, 13); // If the operation have an undefined result if(err==2) strncpyf(text, undef, 13); // If user have entered too big of a value if(err==3) strncpyf(text, bigVal, 13); video_putsmalls(xloc,yloc+12,text); calc_done=1; // indicate calculation completed Statekey2=init; // State machine back to polling input } //================================== // This function return a flag that notifies the program // that user have entered an input beyond the // trigonometric calculation bound // The bounds are: -2pi to 2pi for SIN, COS, TAN // -1 to 1 for ASIN, ACOS, ATAN char boundCheck(float inptoCheck, char cmd) { boundErr=0; // if operand command is SIN, COS, or TAN if(cmd>=21&&cmd<=23) { // if input is outside the +/- 2.5pi boundary // throw an error if((inptoCheck<(-2.5*pi))||(inptoCheck>(2.5*pi))) { boundErr=1; } } // if operant command is ASIN, ACOS, ATAN else if(cmd>=26&&cmd<=28) { // if input is outside the +/- 1 boundary // throw an error if(inptoCheck<-1||inptoCheck>1) boundErr=1; } // if operand command is Ln else if(cmd==29){ if(inptoCheck<0) boundErr=1; } else boundErr=0; return boundErr; } //================================== //convert from calculator to TV X coord. float convertxCoord(float xCoord, float xVal){ //Assuming range is from -2*pi to 2*pi xGraph = (xCoord+xVal)*126/(xVal*2); return xGraph; } //================================== //convert from calculator to TV Y coord. float convertyCoord(float yCoord, float yVal){ //Assuming a range of -2 to 2 yGraph = 99 - (yCoord+yVal)*(99/(yVal*2)); return yGraph; } //================================== /*char errCheckingOnG(void) { j=0; totErrCount=0; decErrCount=-1; negErrCount=0; while(j<6) { if (input[j]==11&&j!=0) negErrCount++; else if (input[j]==10) // decimal places decErrCount++; j++; } totErrCount=decErrCount+ negErrCount; return totErrCount; } */ //================================== // This function returns the floating point result of // the desired operation command that user has inputted // undefErr is a flag that will be turned on if // operation result is undefined float calculate(float A, float B, int command){ switch (command) { case add: result = A + B; undefErr=0; break; case subtract: result = A - B; undefErr=0; break; case multiply: result = A * B; undefErr=0; break; case divide: // if denominator is zero, if(B==0) undefErr=1; // division result is undefined // else, regular division is performed else { result = A / B; undefErr=0; } break; case sine: if ((-5*pi/2<=B) && (B<=-3*pi/2)) B = B + 2*pi; else if ((-3*pi/2<=B) && (B<-pi/2)) B = -pi - B; else if ((pi/2= Binput) Binput = Binput + 2*pi; while (2*pi <= Binput) Binput = Binput - 2*pi; } //if polynomial, special y coordinate calc. if(graphCommand==25) yCoord=power((inputA*xCoord+inputB), inputC); else yCoord = calculate(inputA, Binput, graphCommand); //convert x and y coordinates to TV coordinates xGraph = convertxCoord(xCoord, xMax); yGraph = convertyCoord(yCoord, yMax); //if in graph line mode if(lineGraph==0){ //only graph line if point is within TV range if((xGraph <= 126) && (yGraph>=0&&yGraph<=99) ){ if(xCoord==xMin) video_pt(xGraph, yGraph, 1); else video_line(xGraphold, yGraphold, xGraph, yGraph, 1); } xGraphold = xGraph; yGraphold = yGraph; } else { //just dots if((xGraph <= 126) && (yGraph>=0&&yGraph <= 99)){ video_pt(xGraph, yGraph, 1); } } //================================== // This fuction is a routine that displays functions in graphing mode // and updates vars that will be needed to poll for user input and // finally graph the function void Gprint(flash char poll[]) { strncpyf(text, poll, 15); // copy string from flash video_putsmalls(xloc,yloc,text);// Display function to screen xloc = 8; yloc = yloc+6; // Update x and y location on screen for(i=0;i<15;i++) // clear text vars for next input text[i]=0; strncpyf(text, pollA, 3); // copy string from flash video_putsmalls(xloc,yloc,text);// display "A:" to screen to poll for user input xloc = xloc+12; // update x location on screen currentInp++; // increment counter on current input entered by user Statekey3=recorded; // Update State machine graphCommand=numtbltwo[butnum2];// Record the function user has entered to graph } //==========MAIN============== // set up the ports and timers void main(void) { //init timer 1 to generate sync OCR1A = lineTime; //One NTSC line TCCR1B = 9; //full speed; clear-on-match TCCR1A = 0x00; //turn off pwm and oc lines TIMSK = 0x10; //enable interrupt T1 cmp //init ports DDRD =0x00; //hyper terminal set as output DDRA = 0x00; //input from keypad 1 DDRB = 0x00; //input from keypad 2 DDRC=0xf0; //video out and switches //D.5 is sync:1000 ohm + diode to 75 ohm resistor //D.6 is video:330 ohm + diode to 75 ohm resistor //init timer 0 to 1/uSec TCCR0 = 2; //initialize synch constants LineCount = 1; syncON = 0b00000000; syncOFF = 0b00100000; // Setting hyper terminal for debugging UCSRB = 0x10 + 0x08 ; UBRRL = 103; //side lines video_line(0,0,0,99,1); video_line(width,0,width,99,1); //top line & bottom lines video_line(0,0,width,0,1); video_line(0,10,width,10,1); video_line(0,99,width,99,1); strncpyf(text, cu1, 11); //copy string from flash video_putsmalls(4,4,text); //Print "SCIENTIFIC" strncpyf(text, cu3, 5); //copy string from flash video_putsmalls(48,4,text); //Print "MODE" //init software timer t=0; time=0; // Initializes states Statekey1 = init; Statekey2 = init; Statekey3 = Idle; graph_done=1; precMode=0; if(precMode) video_smallchar(116, 94, 'P'-0x40+26); else video_smallchar(116, 94, 'N'-0x40+26); //enable sleep mode MCUCR = 0b10000000; #asm ("sei"); //The following loop executes once/video line during lines //1-230, then does all of the frame-end processing while(1) { //stall here until next line starts //sleep enable; mode=idle //use sleep to make entry into sync ISR uniform time #asm ("sleep"); //The following code executes during the vertical blanking //Code here can be as long as //a total of 60 lines x 63.5 uSec/line x 8 cycles/uSec if (LineCount==231) { // ================= // State Machine 1 = // ================= /* State machine 1 handles the first keypad. Below is what this keypad operates ----------------- | 1 | 2 | 3 | \ | ----------------- | 4 | 5 | 6 | * | ----------------- | 7 | 8 | 9 | - | ----------------- | 0 | . |(-)| + | ----------------- */ switch (Statekey1) { case init: // Initialize vars to start polling for input oploc=-1; butnum1 = 0; xloc=8; yloc=14; call_keypad1(); Statekey1 = NoPush; for(i=0;i<20;i++) { Aarray[i]=0; Barray[i]=0; } break; case NoPush: // Check if keypad is pushed if (butnum1!=0){ Statekey1 = MaybePush; maybe = butnum1; call_keypad1(); } else { Statekey1=NoPush; call_keypad1(); } break; case MaybePush: // Double check for keypad push if (maybe==butnum1) { Statekey1=Pushed; call_keypad1(); } else { Statekey1=NoPush; call_keypad1(); } break; case Pushed: // If keypad is really pushed by user if (maybe==butnum1) { // Avoid typing any operand more than once if(oploc>0&&numtblone[butnum1]>=13) { call_keypad1(); Statekey1=recorded; } else { // GRAPHING MODE // program will display numbers pertinent to the functions to be graphed if (Statekey2 == Idle) { if(butnum1<13) { video_smallchar(xloc, yloc,numtblprint[butnum1]-0x20); xloc=xloc+4; // update loc input[k++]=numtblone[butnum1]; // store input in char array } } // SCIENTIFIC MODE // program will display numbers and operands exist in keypad 1 else { video_smallchar(xloc, yloc,numtblprint[butnum1]-0x20); xloc=xloc+4; // update loc if(butnum1>=13) // record operand location oploc=k; calculation[k++] = numtblone[butnum1]; // store input in char array } call_keypad1(); Statekey1=recorded; } // end else } // end if else { call_keypad1(); Statekey1=MaybeNoPush; }// end else break; case recorded: // Avoid recording button more than once when user only press it once if (maybe==butnum1) { call_keypad1(); Statekey1 = recorded; } else { call_keypad1(); Statekey1 = MaybeNoPush; } break; case MaybeNoPush: if (maybe==butnum1) { call_keypad1(); Statekey1=Pushed; } else { call_keypad1(); Statekey1=NoPush; } break; case Idle: // This state machine will be idle when calculation or graphing are being processed if(calc_done==1||Statekey3==BeginGraph) Statekey1=init; break; } // end switch case statement // ================= // State Machine 2 = // ================= /* State machine 2 handles the second keypad in scientific mode. Below is what this keypad operates: ------------------------- |exit |clear| del | y= | ------------------------- | SIN | COS | TAN | e^ | ------------------------- | ^ |ASIN |ACOS |ATAN | ------------------------- | ln | N/P | |enter| ------------------------- */ switch (Statekey2) { // These cases are similar to the procedure of the state machine above case init: calc_done=0; butnum2 = 0; k = 0; call_keypad2(); Statekey2 = NoPush; oploc=-1; decErrCount=-1; negErrCount=0; break; case NoPush: if (butnum2!=0){ Statekey2 = MaybePush; maybe = butnum2; call_keypad2(); } else { Statekey2=NoPush; call_keypad2(); } break; case MaybePush: if (maybe==butnum2) { Statekey2=Pushed; call_keypad2(); } else { Statekey2=NoPush; call_keypad2(); } break; case Pushed: // When keypad is really pushed if (maybe==butnum2) { // go to calculate state when enter is pressed if(numtbltwo[butnum2]==32 && k!=0) { Statekey2 = parseA; Statekey1 = Idle; } //switch between non-precision and precision mode else if(numtbltwo[butnum2]==30){ precMode = precMode^1; if(precMode) video_smallchar(116, 94, 'P'-0x40+26); else video_smallchar(116, 94, 'N'-0x40+26); Statekey2=recorded; } // go to clear screen procedure when clear button is pressed else if (numtbltwo[butnum2]==18) Statekey2 = clearScreen1; // go to graphing mode when graph button is pressed else if (numtbltwo[butnum2]==20){ Statekey2 = Idle; // switch from statemachine 2 to three graph_done=0; // Turn off graph_done flag and change to graphing mode } // delete and decrement count when del button is pressed else if (numtbltwo[butnum2]==19) Statekey2 = deleteOnScreen; //printing trig functions else Statekey2= printTrig; } // end if else { call_keypad2(); Statekey2=MaybeNoPush; } break; case printTrig: // Avoid printing more than once operand if(oploc>0&&numtbltwo[butnum2]>=13) { call_keypad2(); Statekey2=recorded; } else { // printing sin function if(numtbltwo[butnum2]==21) { strncpyf(text, sinSign, 4); // Copy string from flash video_putsmalls(xloc, yloc, text); // display on screen xloc=xloc+16; // update x axis location oploc = k; // record operand's location calculation[k++] = numtbltwo[butnum2]; // record keys in char array } // printing cos function else if(numtbltwo[butnum2]==22) { strncpyf(text, cosSign, 4); // Copy string from flash video_putsmalls(xloc, yloc, text); // display on screen xloc=xloc+16; // update x axis location oploc = k; // record operand's location calculation[k++] = numtbltwo[butnum2]; } // printing tan function else if(numtbltwo[butnum2]==23) { strncpyf(text, tanSign, 4); // Copy string from flash video_putsmalls(xloc, yloc, text); // display on screen xloc=xloc+16; // update x axis location oploc = k; // record operand's location calculation[k++] = numtbltwo[butnum2]; // record keys in char array } // printing Asin function else if(numtbltwo[butnum2]==26) { strncpyf(text, asinSign, 5); // Copy string from flash video_putsmalls(xloc, yloc, text); // display on screen xloc=xloc+20; // update x axis location oploc = k; // record operand's location calculation[k++] = numtbltwo[butnum2]; // record keys in char array } // printing Acos function else if(numtbltwo[butnum2]==27) { strncpyf(text, acosSign, 5); // Copy string from flash video_putsmalls(xloc, yloc, text); // display on screen xloc=xloc+20; // update x axis location oploc = k; // record operand's location calculation[k++] = numtbltwo[butnum2]; // record keys in char array } // printing Atan function else if(numtbltwo[butnum2]==28) { strncpyf(text, atanSign, 5); // Copy string from flash video_putsmalls(xloc, yloc, text); // display on screen xloc=xloc+20; // update x axis location oploc = k; // record operand's location calculation[k++] = numtbltwo[butnum2]; // record keys in char array } // printing exponential or power function else if(numtbltwo[butnum2]==24||numtbltwo[butnum2]==25) { if(numtbltwo[butnum2]==24) video_smallchar(xloc, yloc, 2); // display e on screen video_smallchar(xloc+4, yloc, 12); // display ^ on screen xloc=xloc+12; // update x axis location oploc = k; // record operand's location calculation[k++] = numtbltwo[butnum2]; // record keys in char array } //printing ln function else if(numtbltwo[butnum2]==29) { video_smallchar(xloc,yloc,38); // display L on screen video_smallchar(xloc+4,yloc,3); // display n on screen xloc=xloc+12; // update x axis location oploc = k; // record operand's location calculation[k++] = numtbltwo[butnum2]; // record keys in char array } call_keypad2(); Statekey2=recorded; } // end else break; case deleteOnScreen: xloc=xloc-4; // move x axis location on screen video_smallchar(xloc, yloc, 0); // Delete key by displaying blank char k--; // decrement array index if(calculation[k]>=13&&oploc!=0)// if operand is deleted, set operand loc back to zero oploc=0; calculation[k]=0; // remove recorded key from char array call_keypad2(); Statekey2=recorded; break; case recorded: if (maybe==butnum2) { call_keypad2(); Statekey2 = recorded; } else { call_keypad2(); Statekey2 = MaybeNoPush; } break; case MaybeNoPush: if (maybe==butnum2) { call_keypad2(); Statekey2=Pushed; } else { call_keypad2(); Statekey2=NoPush; } break; case parseA: // Initialize vars j=0; numEntry=0; // Error checking 1: unless operand is trig functions, error will be thrown if // user pressed operand with any inputs if(oploc==0&&(calculation[oploc]<21||calculation[oploc]==25)) // check error Myerror(1); else{ // else continue process // If operand is a trig function or exp, input A are automatically set to 1 if(calculation[0]>=21&&calculation[0]<=24) { A=1; // Set input A to 1 Statekey2=parseB; // Continue to parse input B } // if operand is a inverse trig function or ln, input A are automatically set to 1 else if(calculation[0]>=26&&calculation[0]<=29) { A=1; // Set input A to 1 Statekey2=parseB; // Continue to parse input B } else { // else continue with process negErrCount=0; decErrCount=-1; // Parsing input A by going through the char array // until the indicated operand location while(j0||decErrCount>0||numEntry==0) Myerror(1); else { // else continue process Aarray[j]=0; // null terminate the last space in the array A=atof(Aarray); // convert char array into float Statekey2=parseB; // continue to parse B input } // end else } // end else } break; case parseB: negErrCount=0; decErrCount=-1; numEntry=0; // initialize vars j=oploc+1; // set index location one after operand loc //Parse input B by going through the char array //from operand loc till the end while(j<=k-1) { if(calculation[j]==11) { // negative sign Barray[j-oploc-1]=0x2d; // provide B input array with ascii rep. of negative sign if((j-1)!=oploc) // If negative sign is detected not infront of input negErrCount++; // increment negative sign error count } // end if else if (calculation[j]==10) { // decimal places Barray[j-oploc-1]=0x2e; // provide B input array with ascii rep. of dec. decErrCount++; // increment decimal count } //end else if else { Barray[j-oploc-1]=calculation[j]+0x30; // regular numbers are converted to ascii before saved numEntry++; // increment number entry count } //end else j++; // increment index count }//end while // Error checking 1: if one of these error counter is not zero, // user has inputted a syntax error and program will stop calc process if(negErrCount>0||decErrCount>0||numEntry==0) // check error Myerror(1); else { // else continue process Barray[j-oploc]=0; // null terminate the last space in the array B=atof(Barray); // convert char array into float // Error checking 2: if input B exceeded the bound set for trig functions // invalid entry has been detected if(boundCheck(B, calculation[oploc])==1) Myerror(3); else { // else continue process calculate(A,B,(int)calculation[oploc]); // Perform calculation calc_done=1; // set calc_done on Statekey2=init; // set state back to polling input for next calc } // end else } // end else break; /* case calculateNow: calculate(A,B,(int)calculation[oploc]); calc_done=1; Statekey2=init; break; */ case clearScreen1: for (i=0;i<1600;i++) screen[i]=0; Statekey2 = clearScreen2; break; case clearScreen2: //side lines video_line(0,0,0,99,1); video_line(width,0,width,99,1); Statekey2 = clearScreen3; for(i=0;i<20;i++) calculation[i]=0; if(precMode) video_smallchar(116, 94, 'P'-0x40+26); else video_smallchar(116, 94, 'N'-0x40+26); break; case clearScreen3: //top line & bottom lines video_line(0,0,width,0,1); video_line(0,10,width,10,1); video_line(0,99,width,99,1); //Print "SCIENTIFIC" strncpyf(text, cu1, 12); video_putsmalls(4,4,text); Statekey2 = init; //Print "MODE" strncpyf(text, cu3, 5); video_putsmalls(48,4,text); // re-initialize states Statekey1 = init; break; case Idle: //printf("statekey2 is in idle state"); if(graph_done==1) Statekey2=clearScreen1; break; } // end switch case statement // ================= // State Machine 3 = // ================= /* State machine 3 handles the second keypad in graphing mode. Below is what this keypad operates: ------------------------- |exit |clear| del | | ------------------------- | SIN | COS | TAN | e^ | ------------------------- | POLY|ASIN |ACOS |ATAN | ------------------------- | ln | |./line|enter| ------------------------- */ //new state machine starts here switch (Statekey3) { case init: break; case BeginGraph: butnum2 = 0; k = 0; currentInp = 0; //currentInp lets you know whether you are inputting A, B, or C; call_keypad2(); lineGraph = 0; //initially in line-drawing mode Statekey3 = NoPush; Statekey1 = init; break; case NoPush: if (butnum2!=0){ Statekey3 = MaybePush; maybe = butnum2; call_keypad2(); } else { Statekey3=NoPush; call_keypad2(); } break; case MaybePush: if (maybe==butnum2) { Statekey3=Pushed; call_keypad2(); } else { Statekey3=NoPush; call_keypad2(); } break; case Pushed: if (maybe==butnum2) { // if clear screen button is pressed if (numtbltwo[butnum2]==18) Statekey3 = clearScreen1; else if(numtbltwo[butnum2]==19) Statekey3 = deleteOnScreen; // exit button is pressed: go back to scientific mode else if(numtbltwo[butnum2]==17) { Statekey3 = Idle; graph_done = 1; } // end if exit pressed //dot button is pressed, toggle dot mode //lineGraph = 0, draw lines; lineGraph = 1, draw dots else if(numtbltwo[butnum2]==31) { lineGraph=lineGraph^1; if(lineGraph){ strncpyf(text, dotMode, 5); video_putsmalls(100, 4, text); } else { strncpyf(text, lineMode, 5); video_putsmalls(100, 4, text); } Statekey3 = recorded; } //if select trig function, display parameters needed else if((numtbltwo[butnum2]>=21&&numtbltwo[butnum2]<=29)||(numtbltwo[butnum2]==32)) { if (currentInp == 0) { if (numtbltwo[butnum2]==21) Gprint(pollSin); else if (numtbltwo[butnum2]==22) Gprint(pollCos); else if(numtbltwo[butnum2]==23) Gprint(pollTan); else if(numtbltwo[butnum2]==24) Gprint(pollexp); else if(numtbltwo[butnum2]==25) Gprint(pollPoly); else if (numtbltwo[butnum2]==26) Gprint(pollaSin); else if (numtbltwo[butnum2]==27) Gprint(pollaCos); else if (numtbltwo[butnum2]==28) Gprint(pollaTan); else if (numtbltwo[butnum2]==29) Gprint(pollLn); } // end if currentInp == 0 //if press enter, go to parameter input else if(numtbltwo[butnum2] == 32) Statekey3 = paramInput; else { Statekey3=recorded; call_keypad2(); } } // end else if else { Statekey3=recorded; call_keypad2(); } } // if (maybe==butnum2) else { call_keypad2(); Statekey3=MaybeNoPush; }// end else break; //deletes one character from screen case deleteOnScreen: xloc=xloc-4; video_smallchar(xloc, yloc, 0); k--; input[k]=0; call_keypad2(); Statekey3=recorded; break; case recorded: if (maybe==butnum2) { call_keypad2(); Statekey3 = recorded; } else { call_keypad2(); Statekey3 = MaybeNoPush; } break; case MaybeNoPush: if (maybe==butnum2) { call_keypad2(); Statekey3=Pushed; } else { call_keypad2(); Statekey3=NoPush; } break; //takes in A, B, C parameters for graphing case paramInput: for(i=0; i=graphCommand){ if(inputA > 3){ yMin = -inputA; yMax = inputA; } else{ yMax = 3; yMin = -3; } xMin = -2*pi; xMax = 2*pi; } else if(24==graphCommand){ xMin=-2; xMax= 2; yMin = -3; yMax = 3; } else if((graphCommand==25)||(graphCommand==29)){ xMin = -5; xMax = 5; yMin = -5; yMax = 5; } else if(26==graphCommand ){ xMin = -1; xMax = 1; yMin = -2; yMax = 2; } else if(graphCommand==27 ||graphCommand==28){ xMin = -1; xMax = 1; yMin = -4; yMax = 4; } xCoord = xMin; //calc.granularity gran = .1; //but set it to .1 for now //xMin = -2*pi;// + inputC; //xMax = inputB*2*pi + inputC; //effX = inputB*xCoord + inputC; xGraphold = 0; yGraphold = 50; Statekey3 = GraphInit2; break; case GraphInit2: //draw axes video_line(0,50,126,50,1); video_line(63,0,63,99,1); //print labels ftoa(xMin, 2, resultStr); video_putsmalls(0,53,resultStr); ftoa(xMax, 2, resultStr); video_putsmalls(108,53,resultStr); Statekey3 = GraphInit3; Statekey1 = Idle; break; case GraphInit3: //print remaining labels ftoa(yMax, 2, resultStr); video_putsmalls(64,0,resultStr); ftoa(yMin, 2, resultStr); video_putsmalls(64,90,resultStr); Statekey3 = Graph; break; //calculate and draw points on the fly case Graph: graphFunction(inputA, inputB, inputC, xCoord, graphCommand); xCoord = xCoord + .1; if(xCoord>xMax) Statekey3 = DoneGraph; else Statekey3 = Graph; break; case DoneGraph: call_keypad2(); //let the viewer admire the graph and press a button when he's done if(numtbltwo[butnum2]==17||numtbltwo[butnum2]==18){ Statekey3 = clearScreen1; } else Statekey3 = DoneGraph; break; //clear and redraw screen for graphing mode case clearScreen1: for (i=0;i<1600;i++) screen[i]=0; Statekey3 = clearScreen2; break; case clearScreen2: //side lines video_line(0,0,0,99,1); video_line(width,0,width,99,1); if(precMode) video_smallchar(116, 94, 'P'-0x40+26); else video_smallchar(116, 94, 'N'-0x40+26); Statekey3 = clearScreen3; break; case clearScreen3: //top line & bottom lines video_line(0,0,width,0,1); video_line(0,10,width,10,1); video_line(0,99,width,99,1); strncpyf(text, cu2, 12); video_putsmalls(4,4,text); //Print "MODE" strncpyf(text, cu3, 5); video_putsmalls(40,4,text); //Print "line" strncpyf(text, lineMode, 5); video_putsmalls(100, 4, text); // re-initialize states Statekey3 = BeginGraph; break; case Idle: if (graph_done==0) Statekey3 = clearScreen1; break; }// end of switch case statement } //line 231 } //while } //main