; *** NOTICE ***
; MUST disable IRQ's on all routines that talk via i2c
; due to the fact 'write_leds' is called in a timer interupt...
; If you start talking to a device and the timer interupt occures
; the 'write_leds' function will attempt to talk to the i2c i/o chip
; and 'f up the communications, breaking all kinds of shit.
; *** NOTICE ***

;****************** I2C functions begin
start_i2c			;[S]
	Bank0			;bank0 (bank0? names) be sure
	bcf	PIR1,SSPIF
	Bank1			;bank1
	bsf	SSPCON2,SEN     ;send i2c START [S] bit
	Bank0			;bank0
	btfsS	PIR1,SSPIF	;start bit cycle complete?
	goto	$-1
	return

restart_i2c
	Bank0
	bcf	PIR1,SSPIF
	Bank1
	bsf	SSPCON2,RSEN	; resend start bit
	Bank0
	btfss	PIR1,SSPIF	; cycle complete?
	goto	$-1		; Nope
	return

enable_receive_i2c
	Bank1			;bank1
	bsf	SSPCON2,RCEN	;enable receiving at master 16f877
	Bank0			;bank0
	bcf	PIR1,SSPIF
	btfsS	PIR1,SSPIF             ;sspbuf buffer full byte?
	goto	$-1
	return

send_nack_i2c
	Bank1
        bsf     SSPCON2,ACKDT   ; acknowledge bit state to send (not ack)
        bsf     SSPCON2,ACKEN   ; initiate acknowledge sequence
        btfsc   SSPCON2,ACKEN   ; ack cycle complete?
        goto    $-1             ; no, so loop again
	Bank0
        return

; Send Acknowledge
send_ack_i2c
	Bank1
        bcf     SSPCON2,ACKDT   ; acknowledge bit state to send
        bsf     SSPCON2,ACKEN   ; initiate acknowledge sequence
        btfsc   SSPCON2,ACKEN   ; ack cycle complete?
        goto    $-1             ; no, so loop again
;        bsf     SSPCON2,RCEN    ; generate receive condition
	Bank0
        return                  ;

stop_i2c
	Bank0			;bank0
	bcf	PIR1,SSPIF
	Bank1			;bank1
	bsf	SSPCON2,PEN	;send i2c STOP [P] bit
	Bank0			;bank0
	btfsS	PIR1,SSPIF	;stop bit cycle completed?
	goto	$-1
	return

wait_for_ack_i2c
	bcf	LCD_Data, 3
	Bank0				;bank0
	bcf	PIR1,SSPIF
	btfsS	PIR1,SSPIF                 ;ACK received?
	goto	$-1
	bsf	LED_Data, 3
	return
check_idle_i2c
        banksel SSPSTAT         ; linker to select SFR bank
        btfsc   SSPSTAT,R_W     ; test if transmit is progress
         goto    $-1            ; module busy so wait
        movf    SSPCON2,W
        andlw   0x1F            ; mask out non-status bits
        btfss   STATUS,Z        ; test for zero state, if Z set, bus is idle
         goto    $-3            ; bus is busy so test again

	Bank0
        return                  ; return to calling routine
;**********************************************************
; END I2C Core Functions
;**********************************************************

;*****
; Reads Function button array, stores it in FBut_State
;*****
read_funct_buts				;io1 is inputs only
	call	check_idle_i2c
	call	start_i2c
	movlw	FBUT_ADDR
	movwf	SSPBUF

	call	wait_for_ack_i2c
	
	call	enable_receive_i2c
	
	movf	SSPBUF, W
	movwf	FBut_State

	call	send_nack_i2c		; send NACK

	call	stop_i2c

	return

;*****
; Writes Status LEDs, data in LED_Data
;*****
write_leds				;io2 is output only
        banksel SSPSTAT         ; linker to select SFR bank
        btfsc   SSPSTAT,R_W     ; test if transmit is progress
         goto led_done            ; module busy so wait
        movf    SSPCON2,W
        andlw   0x1F            ; mask out non-status bits
        btfss   STATUS,Z        ; test for zero state, if Z set, bus is idle
         goto led_done            ; bus is busy so test again

	Bank0

	call	start_i2c
	movlw	LED_ADDR		; Load the address
	movwf	SSPBUF			; Send it
	call	wait_for_ack_i2c

	movf	Led_Data, W		; move Led_Data to W
	movwf	SSPBUF			; Send it to the i2c
	call	wait_for_ack_i2c
	call	stop_i2c
	return
led_done
	Bank0
	return

;*****
; Initilizes the Temperature chip
;*****
init_temp
	call	check_idle_i2c

;	call	start_i2c
;	movlw	TEMP_ADDR_W
;	movwf	SSPBUF
;	call	wait_for_ack_i2c

;	movlw	TEMP_AC			; Send Access Config
;	movwf	SSPBUF
;	call	wait_for_ack_i2c

;	movlw	b'00001110'
;	movwf	SSPBUF
;	call	wait_for_ack_i2c

;	call	stop_i2c
;	Wait	2 Millisec, 0

	call	start_i2c
	movlw	TEMP_ADDR_W
	movwf	SSPBUF
	call	wait_for_ack_i2c

	movlw	TEMP_STC		; Send StarT Conversion
	movwf	SSPBUF
	call	wait_for_ack_i2c	; Get ACK
	call	stop_i2c
	return

;*****
; Reads current temp from the Temperature chip, Stores data in Local_Temp[MSB/LSB]
;*****
read_temp
	call	check_idle_i2c
	call	start_i2c		; Send START bit

	movlw	TEMP_ADDR_W
	movwf	SSPBUF
	call	wait_for_ack_i2c

	movlw	TEMP_RT			; Send Read Temp
	movwf	SSPBUF
	call	wait_for_ack_i2c	; Wait for ACK

	call	restart_i2c		; Send start again

	movlw	TEMP_ADDR_R		; Send read address
	movwf	SSPBUF
	call	wait_for_ack_i2c	; Wait for ACK

	call	enable_receive_i2c	; Get temperature MSB
	movf	SSPBUF, W
	movwf	Local_TempMSB		; Save it

	call	send_ack_i2c		; Send ACK

	call	enable_receive_i2c	; Get temperature LSB
	movf	SSPBUF, W
	movwf	Local_TempLSB		; Save it

	call	send_nack_i2c		; send NACK

	call	stop_i2c		; send STOP bit

	return

;*****
; Writes to registers on the RTC, Address to write in RTC_Adder, data in RTC_Data
;*****
rtc_write_time
	call	check_idle_i2c
	call	start_i2c
	movlw	b'11010000'
	movwf	SSPBUF
	call	wait_for_ack_i2c	; Send adder

	movf	RTC_Addr, W
	movwf	SSPBUF
	call	wait_for_ack_i2c

	movf	RTC_Data, W
	movwf	SSPBUF
	call	wait_for_ack_i2c

	call	stop_i2c
	return

;*****
; Initilizes the RTC, enables the clock and sets it to 12hr mode (broken?)
;*****
rtc_init
	movlw	0x00			; First get seconds register
	call	rtc_get_time
;	btfss	RTC_Data, 7		; If its allready set, ignore it
;	goto	rtc_init_form

;	movlw	'S'
;	call	lcd_put_char
	bcf	RTC_Data, 7		; Clear OSC OFF bit

	movlw	0x00			; write new seconds register
	movwf	RTC_Addr
	call	rtc_write_time
rtc_init_form
	movlw	0x02			; Now get HOURS register, to set 12/24 format
	call	rtc_get_time
;	btfsc	RTC_Data, 6
;	goto	rtc_init_end

	bsf	RTC_Data, 6		; set high, 12hour format

	movlw	0x02			; write new hour register
	movwf	RTC_Addr
	call	rtc_write_time
rtc_init_end
	return

;*****
; Reads data from the RTC, Address in W, Data returned in RTC_Data
;*****
rtc_get_time
	movwf	RTC_Addr

	call	check_idle_i2c
	call	start_i2c
	movlw	b'11010000'
	movwf	SSPBUF
	call	wait_for_ack_i2c

	movf	RTC_Addr, W
	movwf	SSPBUF
	call	wait_for_ack_i2c
	
	call	stop_i2c
	call	start_i2c
	movlw	b'11010001'
	movwf	SSPBUF
	call	wait_for_ack_i2c

	call	enable_receive_i2c
	movf	SSPBUF, W
	movwf	RTC_Data

	call	send_nack_i2c

	call	stop_i2c

	movf	RTC_Data, W
	return

;*****
; Displays a clock at the top of the LCD, Used in the Waiting screen.
;*****
rtc_show_time
	LCD_MOV 0, 7
;;;Hours
	movlw	0x02
	call	rtc_get_time
	andlw	0x3f
	call	rtc_print_num

	movlw	':'
	call	lcd_put_char
;;;Mins
	movlw	0x01
	call	rtc_get_time
	call	rtc_print_num

	movlw	':'
	call	lcd_put_char
;;;Secs
	movlw	0x00
	call	rtc_get_time
	call	rtc_print_num

;;;AM/PM
	movlw	0x02				; Get hours again for AM/PM
	call	rtc_get_time

	btfss	RTC_Data, 5
	goto	rtc_am
	goto	rtc_pm

rtc_am
	movlw	'A'
	call	lcd_put_char
	goto rtc_ampm_done
rtc_pm
	movlw	'P'
	call	lcd_put_char
rtc_ampm_done
	movlw	'M'
	call	lcd_put_char

	movlw	' '
	call	lcd_put_char
;;;Month
	movlw	0x05
	call	rtc_get_time
	call	rtc_print_num

	movlw	'/'
	call	lcd_put_char
;;;Day
	movlw	0x04
	call	rtc_get_time
	call	rtc_print_num

	movlw	'/'
	call	lcd_put_char
;;;Year
	movlw	0x06
	call	rtc_get_time
	call	rtc_print_num

	return
;;

;*****
; Converts the BCD time to individual numbers and prints
;*****
rtc_print_num
	movwf	tmp_i2c2

	swapf	tmp_i2c2, 0
	andlw	0x0f
	call	lcd_put_num

	movf	tmp_i2c2, 0
	andlw	0x0f
	call	lcd_put_num
	return

;********************
; LOGO crap
;********************
;*****
; Incraments the EEPROM 16bit address
;*****
logo_addr_inc
	incf EEPROM_Addr_H,f
	incfsz EEPROM_Addr_L,f
	decf EEPROM_Addr_H,f
	return

;*****
; Writes a byte to the EEPROM
; Address in EEPROM_Addr_[H/L]
; Data in EEPROM_Data
;*****
logo_write_byte
	call	check_idle_i2c
	call	start_i2c

	movlw	EEPRM_ADDR_W
	movwf	SSPBUF
	call	wait_for_ack_i2c

	movf	EEPROM_Addr_H, W
	movwf	SSPBUF
	call	wait_for_ack_i2c

	movf	EEPROM_Addr_L, W
	movwf	SSPBUF
	call	wait_for_ack_i2c

	movf	EEPROM_Data, W
	movwf	SSPBUF
	call	wait_for_ack_i2c

	call	stop_i2c
	return

;*****
; Performs a ReadCurrent command
; Data returned in EEPROM_Data
;*****
logo_read_current
	call	check_idle_i2c
	call	start_i2c

	movlw	EEPRM_ADDR_R
	movwf	SSPBUF
	call	wait_for_ack_i2c

	call	enable_receive_i2c
	movf	SSPBUF, W
	movwf	EEPROM_Data

;	call	send_nack_i2c
	call	stop_i2c
	return
;*****
; Performs a ReadRandom command
; Address in EEPROM_Addr_[H/L]
; Data returned in EEPROM_Data
;*****
logo_read_random
	call	check_idle_i2c
	call	start_i2c

	movlw	EEPRM_ADDR_W		; Move write address
	movwf	SSPBUF
	call	wait_for_ack_i2c

	movf	EEPROM_Addr_H, W	; Send MSB
	movwf	SSPBUF
	call	wait_for_ack_i2c	

	movf	EEPROM_Addr_L, W	; Send LSB
	movwf	SSPBUF
	call	wait_for_ack_i2c	

	call	restart_i2c

	movlw	EEPRM_ADDR_R
	movwf	SSPBUF
	call	wait_for_ack_i2c

	call	enable_receive_i2c
	movf	SSPBUF, W
	movwf	EEPROM_Data

	call	send_nack_i2c

	call	stop_i2c

	return

;*****
; Reads data from the EEPROM and displays it to the LCD
; DUN DUN DUN. this code sucked.
; now it un-sucks. 
;*****
display_logo
	
	clrf	EEPROM_Addr_H		; Clear high addr
	clrf	EEPROM_Addr_L		; Clear low addr

	call	lcd_home_graph		; home graphic

	; Start i2c operations

	movlw	DATA_AUTO_WR		; turn on auto-mode
	movwf	COMMANDBUF
	call	lcd_send_cmd		;

	call	logo_read_random

	; OK got first byte..send to lcd

	movf	EEPROM_Data, W
	movwf	DATABUFA
	call	lcd_autosend

	; OK addresses should be set right...read time

	movlw	BYTES_PER_ROW		; 40 bytes per line
	movwf	tmp_i2c1
logoloop1				; Loop 40 times, once for each byte per line
	movlw	64
	movwf	tmp_i2c2
logoloop2				; loop 64 times, once for each line

	call	logo_read_current	; Read a byte from EEPROM

	movf	EEPROM_Data, W
	movwf	DATABUFA
	call	lcd_autosend

	call	logo_addr_inc		; incr the EEPROM address pointers

	decfsz	tmp_i2c2, 1
	goto	logoloop2
	decfsz	tmp_i2c1, 1
	goto	logoloop1

	movlw	AUTO_DATA_RESET
	movwf	COMMANDBUF
	call	lcd_send_cmd

	return


