;---------------------------------------------------------------------
SSP_Handler; Code is adapted from Microchip AN734A
;---------------------------------------------------------------------
;	The I2C code below checks for 5 states:
;---------------------------------------------------------------------
;	State 1:  	I2C write operation, last byte was an address byte.
;
;	SSPSTAT bits:  	S = 1, D_A = 0, R_W = 0, BF = 1
;
;	State 2:	  I2C write operation, last byte was a data byte.
;
;	SSPSTAT bits:	  S = 1, D_A = 1, R_W = 0, BF = 1
;
;	State 3:	  I2C read operation, last byte was an address byte.
;
;	SSPSTAT bits:	  S = 1, D_A = 0, R_W = 1, BF = 0
;
;	State 4:	  I2C read operation, last byte was a data byte.
;
;	SSPSTAT bits:	  S = 1, D_A = 1, R_W = 1, BF = 0
;
;	State 5:  Slave I2C logic reset by NACK from master.
;	
;	SSPSTAT bits:  S = 1, D_A = 1, R_W = 0, BF = 0
;
; For convenience, WriteI2C and ReadI2C functions have been used.
;----------------------------------------------------------------------

	banksel	STATE
	movf	STATE,W		; Get the saved value of SSPSTAT
	andlw	b'00100101'	      ; Mask out unimportant bits in SSPSTAT. (WAS: 00101101 in AN734A!)
	banksel	Temp		; Put masked value in Temp
	movwf	Temp		      ; for comparision checking.

;										SPSTAT BITS: SMP | CKE | D_A | P | S | R_W | UA | BF

State1:				; Write operation, last byte was an
	movlw	b'00000001'	      ; address, buffer is full.			(WAS 00001001 in AN734A!)
	xorwf	Temp,W		; 							but works only if S bit is
	btfss	STATUS,Z	      ; Are we in State1?				discarded!
	goto	State2		; No, check for next state.....
	
	call	ReadI2C		; Do a dummy read of the SSPBUF.
	return
	
State2:			; Write operation, last byte was data,
	movlw	b'00100001'	; buffer is full.						(WAS 00101001 in AN734A!)
	xorwf	Temp,W
	btfss	STATUS,Z	; Are we in State2?
	goto	State3	; No, check for next state.....
		
	call	ReadI2C	; Get the byte from the SSP.
	MOVWF	SWITCHES1	; save received byte
	MOVWF	SWITCHES2
	return
	
State3:			; Read operation, last byte was an
	movlw	b'00000100'	; address, buffer is empty.				(WAS 00001100 in AN734A!)
	xorwf	Temp,W
	btfss	STATUS,Z	; Are we in State3?
	goto	State4	; No, check for next state.....
	MOVF	SSPBUF, W
	MOVF	SWITCHES2,W
	call	WriteI2C	; Write the byte to SSPBUF
	return
	
State4:			; Read operation, last byte was data,
	movlw	b'00100100'	; buffer is empty.						(WAS 00101100 in AN734A!)
	xorwf	Temp,W
	btfss	STATUS,Z	; Are we in State4?
	goto	State5	; No, check for next state....
	MOVF	SWITCHES2,W
	call	WriteI2C	; Write to SSPBUF
	return

State5:
	movlw	b'00100000'	; A NACK was received when transmitting (WAS 00101000 in AN734A!)
	xorwf	Temp,W	; data back from the master.  Slave logic
	btfss	STATUS,Z	; is reset in this case.  R_W = 0, D_A = 1
	goto	I2CErr	; and BF = 0
	banksel	SSPCON
	bsf	SSPCON, CKP ; Release clock (this is not from AN734A
	return		; but a tip I got from Robert Soubie and Alan B. Pearce)		

I2CErr				; If we aren’t in State5, then something is 
	banksel	PORTB		; wrong!  FLASH LED slowly
	clrf	PORTA
	clrf	PORTB
	bsf	PORTA,3
	call	WAIT_100MSEC
	bcf	PORTA,3
	CALL	WAIT_100MSEC
	goto	$-4
	
FFLED
	banksel	PORTB		; Unknown interrupt!  FLASH LED fast
	clrf	PORTA
	clrf	PORTB
	bsf	PORTA,3
	call	WAIT_10MSEC
	bcf	PORTA,3
	CALL	WAIT_10MSEC
	goto	$-4		
;---------------------------------------------------------------------
; WriteI2C
;---------------------------------------------------------------------

WriteI2C
	banksel	SSPSTAT
	btfsc	      SSPSTAT,BF	; Is the buffer full?
	goto	      WriteI2C	; Yes, keep waiting.
	banksel	SSPCON	; No, continue.
DoI2CWrite
	bcf		SSPCON,WCOL	; Clear the WCOL flag.
	movwf	      SSPBUF	; Write the byte in WREG
	btfsc	      SSPCON,WCOL	; Was there a write collision?
	goto	      DoI2CWrite
	NOP
	NOP
	NOP
	NOP
	NOP
	bsf	      SSPCON,CKP	; Release the clock.
	return

;---------------------------------------------------------------------
ReadI2C
;---------------------------------------------------------------------
	
	banksel	SSPBUF
	movf	SSPBUF,W	; Get the byte and put in W
	return