;********************************************************************************
;*																				*
;* 			   	             Solder : Time  Watch         						*
;*																				*
;*							    SpikenzieLabs									*
;* 																				*
;********************************************************************************
;	Operation;
;
; 1. Displays time on 4x Seven Segment Display
; 2. Turns off display - Goes to sleep in ~ 10 seconds
; 3. Wakes on button press
; 4. Check time over I2C (DS1337 RTC)
; 5. Press Button to + 1 Minutes
; 6. Hold for ~4 seconds and fast forward time to set
;
; Time Setting:
; Button pressed for more than x seconds, time advances and is saved when stops
;
;******************************************************************************
;
; Copyright (c) 2011, SpikenzieLabs
; All rights reserved.
; The Solder : Time design, a time piece made of layered plastics, itŐs schematic
; and source code / firmware are presented here strictly for educational and
; informative purposes. SpikenzieLabs retains all rights to the design, look,
; source code and firmware. Reproduction is allowed only for personal use. 
; No commercial reproduction is allowed without previous written approval from 
; SpikenzeLabs.
;
;******************************************************************************
;	
; Bit-Banged I2C code section is modified firmware of 
; Chris Parris / Microchip Technology, Inc.
; Please see Microchip App note #AN982 for more details.
;
;******************************************************************************
;
; THIS SOFTWARE IS PROVIDED BY SPIKENZIELABS ``AS IS'' AND ANY
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL SPIKENZIELABS BE LIABLE FOR ANY
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;
;******************************************************************************



;******************************************************************************
;							COMPILER OPTIONS
;******************************************************************************
	variable	chipset

;	chipset		set 631			  ; Complies code specific to the PIC16F631
;******************************************************************************

;	list      p=16f687            ; list directive to define processor
;	#include <p16f687.inc>        ; processor specific variable definitions

	ifdef 	__16F689
	list      p=16f689            ; list directive to define processor
	#include <p16f689.inc>        ; processor specific variable definitions
	endif

	ifdef	__16F631
	list      p=16f631            ; list directive to define processor
	#include <p16f631.inc>        ; processor specific variable definitions
	endif

	ifdef	__16F690
	list      p=16f690            ; list directive to define processor
	#include <p16f690.inc>        ; processor specific variable definitions
	endif

;******************************************************************************
	errorlevel  -302              ; suppress message 302 from list file

;	if clkspeed == 8
		__CONFIG   _CP_OFF & _CPD_OFF  & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT & _BOR_OFF & _FCMEN_OFF & _IESO_OFF
;	else
;		__CONFIG   _CP_OFF & _CPD_OFF  & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC & _BOR_ON & _FCMEN_OFF
;	endif
	
;*************************** DEFINE STATEMENTS ********************************


; input and output definitions	

#define		COLONFLAG		DATAFLAG,0		; Seven Segment Colon Flasher
#define		BUTTONFLAG		DATAFLAG,1		; Button is pressed
#define		SLEEPFLAG		DATAFLAG,3		; Wake Time Timed out -> go to sleep
#define		SETTIME			DATAFLAG,4		; SEND updated time to RTC
#define		JUSTWAKEUPFLAG	DATAFLAG,5		; Pic just woke-up
#define		FLASHCOLONFLAG	DATAFLAG,6		; Is colon flashing 1=flash 0=full on
#define		FLASHONOFFFLAG	DATAFLAG,7

; Common DIGIT pin on 7 Segment display
#define		DIG1PIN			PORTA,5			; Leftmost
#define		DIG2PIN			PORTA,4
#define		DIG3PIN			PORTA,0
#define		DIG4PIN			PORTA,1			; Rightmost

#define		colon			PORTC,7

#define		HoursTens		DIGITS+3
#define		HoursOnes		DIGITS+2
#define		MinTens			DIGITS+1
#define		MinOnes			DIGITS

#define		TIMERZEROSET	0xF8

#define		BUTTONPIN		PORTA,2
#define		ONJUMPERPIN		PORTB,5

#define		CLOCK1224		RAW_HOURS,6		; When set time = 12 hours

#define 	LEDBRIGHT		0x10							

#define		SFcountSet		0xD8			; Count before Slow Increment

; DS1337+ Address locations
#define		RTCDS1337	b'11010000'		;  
#define		RTCCONT		b'00000000'		; Control
#define		RTC_HSEC	b'00000001'		; Hundredth of a secound
#define		RTC_SEC		b'00000000'		; Seconds
#define		RTC_MIN		b'00000001'		; Minuites
#define		RTC_HOUR	b'00000010'		; Hours

; I2C
#define		SDA     4	           		; I2C data pin
#define		SCL     6		          	; I2C clock pin
#define		SDA_OUT		b'10100000' 	; TRIS value for SDA as an output 
#define		SDA_IN		b'10110000' 	; TRIS value for SDA as an input

#define		DO      0	           		; TX/RX buffer output bit
#define		DI      1           		; TX/RX buffer input bit
#define		ACKB    2           		; ACK/NO ACK select bit


;******************************************************************************
;								MACRO DEFINITIONS 
;******************************************************************************

RESETSLEEPTIMER	macro		
	clrf	sleepycounter
	movlw	0xB3				; Delay before watch goes into sleep mode
	movwf	sleepycounter+1
        endm

RESETFFORWARDCOUNTER	macro		
	clrf	nextmodecounter
	movlw	0xFE				; Delay before watch goes into FF mode
								; Higher number is shorter delay
	movwf	nextmodecounter+1
        endm

CLEARDISPLAY macro
	movlw	b'11111111'   		; 
	movwf	PORTC
;	clrf	PORTA
	movlw	b'00000100'			; were 5,4,1,0 are digit pins and 2 is Button
	andwf	PORTA,f
;	movf	PORTA
		endm

TIMER1ENABLE macro
	bsf		T1CON,TMR1ON		; Turn on Timer 1
	bsf		STATUS,RP0			; Bank 1
	bsf		PIE1,TMR1IE
	bcf		STATUS,RP0			; Bank 0
		endm

TIMER1DISSABLE macro
	bsf		STATUS,RP0			; Bank 1
	bcf		PIE1,TMR1IE
	bcf		STATUS,RP0			; Bank 0
	bcf		T1CON,TMR1ON		; Turn OFF Timer 1
		endm
		
; I2C Macros

THIGH   macro                   ; Clock high time delay (5 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        endm

THDSTA  macro                   ; Start condition hold time delay (5 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        endm

TSUSTA  macro                   ; Start condition setup time delay (5 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        endm

TSUSTO  macro                   ; Stop condition setup time delay (5 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        endm

TAA     macro                   ; Output valid from clock delay (4 us)
        goto    $+1             ; 2-inst. cycle delay (2 us)
        nop                     ; 1-inst. cycle delay (1 us)
        endm

SETTRIS macro                   ; Macro to set TRIS
		banksel	TRISB
    	movwf   TRISB          	; Copy value to TRISIO reg.
		banksel	PORTB
    	endm		

;******************************************************************************		
;								VARIABLE DEFINITIONS 
;******************************************************************************


;     cblock	0x20
      cblock	0x40			; PIC16F631 memory starts higher	


	INDEX
	INDEX2
	DELAY_COUNTER
	DELAY_COUNTER2
	DELAY_COUNTER3
	DATAFLAG

; - Watch Variables
	SEGmask
	SEGcurrent
	SEGindex
	SEGbuffer
	DIGindex
	DIGdisplay
	DIGITS:4
	SFcount						; Number of Slow forward digits befor FF

	OLDMinOnes

; - I2C Variables
	buffer                  	; Transfer/Receive bit buffer
	datai                   	; Data input byte buffer
	datao                   	; Data output byte buffer
	bitcount                	; Bit loop counter
	bytecount               	; Byte loop counter
	address                 	; Word address pointer
	loops                  		; Delay loop counter
	loops2                  	; Delay loop counter

	TIMEUPDATECOUNTER
	MODEindex
	
; - RTC Variables
	RAW_HOURS
	RAW_MINUTES


;	(16 bit)
	sleepycounter:2
;	ffcounter:2
	nextmodecounter:2
      endc

      cblock	0x70			; Shadow memory location shared all banks
	WTEMP
	STATUSTEMP
	PCLATHTEMP
	FSRTEMP
	portb
      endc


;****************************** Start of Program ******************************
	org     0x000			; processor reset vector
	goto	Initialize

	org     0x004
;********************************************************************************
;																				*
;  INTERRUPT 																	*
;																				*
;********************************************************************************

INTERRUPT:

; 	Interrupt PREP. here ---------------------------------
	movwf   WTEMP         	;Save off current W register contents
	swapf	STATUS,w

	clrf	STATUS			; Reset to Bank 0			

	movwf	STATUSTEMP									 
	movf	PCLATH,w
	movwf	PCLATHTEMP		;Save PCLATH
	movf	FSR,w
	movwf	FSRTEMP			;Save FSR
	
; --------------------------------------------------------
;	TEST Cause of INTERRUPT

	btfsc	INTCON,T0IF			; Yes TIMER 0, check if it timed-out
	goto	TIMERZERO

	btfsc	PIR1,TMR1IF
	goto	TIMERONE
	
	btfsc	INTCON,INTF
	goto	ButtonINT

; 	Interrupt EXIT here ----------------------------------
InterruptEXIT:
	
	banksel	INTCON
	bcf		INTCON,T0IF

InterruptEXITCONT:
	clrf	STATUS
	movf	FSRTEMP,w
	movwf	FSR				  ;Restore FSR
	movf	PCLATHTEMP,w
	movwf	PCLATH			  ;Restore PCLATH

	swapf	STATUSTEMP,w
	movwf	STATUS			  ;Restore STATUS & Bank

	swapf	WTEMP,f			  
	swapf	WTEMP,w			  ;Restore W without corrupting STATUS bits

	retfie

;******************************************************************************
; Initialize      
;******************************************************************************

;	#include <i2c_Macro.inc>    	; This is the I2C code
;	#include <RTCDS1337.inc>    	; This is the Real Time Clock code
;	These two files have been copied into this file for ease of reading. 

Initialize

	banksel	TMR0

	clrwdt
	clrf	TMR0

	banksel	OPTION_REG
	movlw	B'00000011'		; Weak pullups: EN-abled
	movwf	OPTION_REG		; 

	banksel	TRISA
	movlw	b'11001100'		; Set  OUTS
	movwf	TRISA

	clrf	TRISC

	banksel	PORTA
	clrf	PORTA
	clrf	PORTB
	clrf	PORTC

;******************************************************************************	
;					    	Weak Pull-Up Init
;******************************************************************************

	banksel	WPUA

	bsf		WPUA,2			; RA2 is button input, turn ON weak pull-up

	banksel	WPUB
	bsf		WPUB,WPUB5		; RB5 is Jumper Pad input, turn ON weak pull-up

	banksel	PORTB

;******************************************************************************	
;					    	Set Output of unused Pins to low
;******************************************************************************

;;	bcf     PORTB,7			; Pin not used

;******************************************************************************	
;								A2D Init
;******************************************************************************
	ifdef	ANSEL
	banksel	ANSEL
	clrf	ANSEL			; make All digital
	clrf	ANSELH			; make All digital
	endif
;******************************************************************************	
;								TIMER 0 Init 
;******************************************************************************
;- Used to cycle through LED segments
	banksel	TMR0
	clrf	TMR0
	bcf		INTCON,T0IF		
	bsf		INTCON,T0IE		; Enable Timer 0 Interupts

;******************************************************************************	
;								TIMER 1 Init
;******************************************************************************
; - Used to flash colon when in time setting mode

								; Bank 0
	clrf	TMR1H
	clrf	TMR1L
	bcf		PIR1,TMR1IF		
;	bsf		T1CON,T1CKPS0		; Set prescaler to 1:2
	bsf		T1CON,T1CKPS1		; Set prescaler to 1:4 = Slower flashing
;	bsf		T1CON,TMR1ON		; Turn on Timer 1

; Note: not on during normal operation


;******************************************************************************	
;						  General Init & Variable Init
;******************************************************************************

	clrf	INDEX
	clrf	INDEX2
	clrf	DELAY_COUNTER
	clrf	DELAY_COUNTER2
;	clrf	DELAY_COUNTER3
	clrf 	TMR0				; clear Timer 0

;	Watch Init
	clrf	SEGcurrent
;	clrf	DIGindex
	movlw	0x05
	movwf	DIGindex
	clrf	DIGdisplay
	movlw	0x08
	movwf	SEGindex
	movlw	b'10000000'
	movwf	SEGmask

; temp for test
	clrf	DIGdisplay

	clrf	DIGITS
	clrf	DIGITS+1
	clrf	DIGITS+2
	clrf	DIGITS+3

	clrf	HoursTens
	clrf	HoursOnes
	clrf	MinTens
	clrf	MinOnes

	bcf		JUSTWAKEUPFLAG
	bcf		FLASHCOLONFLAG							; Not flashing on start-up
	bcf		FLASHONOFFFLAG							; colon is on
	

	clrf	MODEindex
	clrf	nextmodecounter
	clrf	nextmodecounter+1


; Sleep
	bcf		SLEEPFLAG
	RESETSLEEPTIMER

; Initial Power-Up Time
	movlw	b'00000000'								; Start-up time 12:00 AM
	movwf	RAW_MINUTES

	movlw	b'00010010'
	movwf	RAW_HOURS
	bsf		CLOCK1224								; AM/PM 12 hour mode

	call	DOUBLEWRITE
	
	bsf		SETTIME

	movlw	LEDBRIGHT								; Count of TMR0 calls before slow
													; I2C read, ie leds on longer
	movwf	TIMEUPDATECOUNTER

;******************************************************************************
;  INTERPUT ENABLE
;******************************************************************************

	banksel	OPTION_REG				; Bank 1
 
	bcf		OPTION_REG,INTEDG		; Cause INT on falling edge

	banksel	INTCON					; Bank 0 

	bsf		INTCON,GIE
	bsf		INTCON,PEIE

		

;********************************************************************************
;																				*
;								MAIN PROGRAM									*
;																				*
;********************************************************************************
MAINLOOP:

DO_MODESTATE:									; Which function mode is Watch in
;
	movlw	HIGH MODETABLE						
	movwf	PCLATH
	movf	MODEindex,w
	addlw	LOW MODETABLE
	btfsc	STATUS,C
	incf	PCLATH,f
	movwf	PCL
;
MODETABLE:				
	goto	MODE0_JUSTAWAKE		;
	goto	MODE1_IDEL			;
	goto	MODE2_PRE_SETTIME	;
	goto	MODE3_SLOWFORWARD	;	
	goto	MODE4_FASTFORWARD	;

; -------------------------------------------------------------------------------
MODE0_JUSTAWAKE:									; MODE 0

	call	UPDATECLOCKVARIABLES
	RESETSLEEPTIMER
												
	btfss	BUTTONPIN								; Do not sleep, wait for button release
	goto	MAINLOOPCONT
MODE0_JUSTAWAKECONT:								; Only here when button released
	bcf		JUSTWAKEUPFLAG
	movlw	0x01
	movwf	MODEindex								; Change to Idel mode
	goto	MAINLOOPCONT	

; -------------------------------------------------------------------------------
MODE1_IDEL:											; MODE 1

	call	UPDATECLOCKVARIABLES

;Part 1 : Check for a Button Press
	movlw	0x0A				
	movwf	INDEX2				
	call	SHORTDELAY	

	btfsc	BUTTONPIN								; Clear when pressed
	goto 	MODE1_IDELPART2
;	goto	MODE1_IDELEXIT

MODE1_IDELEXIT:										; Button was pressed - change modes
	RESETSLEEPTIMER
	movlw	0x02
	movwf	MODEindex								; Change to Pre-SETTIME mode
	clrf	nextmodecounter
	clrf	nextmodecounter+1

	goto	MODE1_IDELCONT

MODE1_IDELPART2:
;Part 2 : Check if time to Sleep
	btfss	SLEEPFLAG								; -- Test for Sleep
	goto	MODE1_IDELCONT

	btfsc	ONJUMPERPIN								; Test in Always On jumper is jumped = low
	goto	MODE1_DOSLEEP

MODE1_NOSLEEP:
	bcf		SLEEPFLAG
	RESETSLEEPTIMER
	TIMER1DISSABLE
	bcf		FLASHCOLONFLAG
	goto	MODE1_IDELCONT	


				
MODE1_DOSLEEP:
; ------------------------ SLEEP - START
	TIMER1DISSABLE
	bcf		INTCON,T0IE								; Dissable Timer 0 Interupts
	CLEARDISPLAY
	bcf		INTCON,INTF								; Clear flag
	bsf		INTCON,INTE
; ------------------------ SLEEP - END
	nop
	nop
	SLEEP
	nop
	nop
; ------------------------ SLEEP WAKE - START
	bcf		INTCON,INTF								; Clear flag
	bcf		INTCON,INTE
	bsf		INTCON,T0IE								; Enable Timer 0 Interupts
	bsf		JUSTWAKEUPFLAG							; Just woke up, don't set the time button

	bcf		BUTTONFLAG								; added March 8th
;	bcf		SFDOFLAG								; added March 8th
; ------------------------ SLEEP WAKE - END

	movlw	0x0A				
	movwf	INDEX2				
	call	SHORTDELAY	

	RESETSLEEPTIMER

;	movlw	0x00
;	movwf	MODEindex
	clrf	MODEindex								; Change to Just woke up mode
	bcf		FLASHCOLONFLAG
;	TIMER1DISSABLE									; Disable timer 1 during normal opperation

MODE1_IDELCONT:
	goto	MAINLOOPCONT

; -------------------------------------------------------------------------------
MODE2_PRE_SETTIME:									; MODE 2

	call	UPDATECLOCKVARIABLES

;Part 1 : Check for a Button Release
	movlw	0x0A				
	movwf	INDEX2				
	call	SHORTDELAY	

	btfss	BUTTONPIN								; Set when Released
	goto	MODE2_PRE_SETTIMECONT
;	goto	MODE2_PRE_SETTIMEEXIT

MODE2_PRE_SETTIMEEXIT:								; Button Released = not setting time
	movlw	0x01
	movwf	MODEindex
	
MODE2_PRE_SETTIMECONT:

	RESETSLEEPTIMER

	incfsz	nextmodecounter,f
	goto	MODE2_PRE_SETTIMECONT2

;	incfsz	nextmodecounter+1,f						; Delay this long is not needed
;	goto	MODE2_PRE_SETTIMECONT2
YESSLOWFORWARDSTARTED:
;	clrf	nextmodecounter							; Clearing variable here not required
;	clrf	nextmodecounter+1

	RESETFFORWARDCOUNTER

	movlw	SFcountSet
	movwf	SFcount
	bsf		FLASHCOLONFLAG
	TIMER1ENABLE
	movlw	0x03
	movwf	MODEindex	

MODE2_PRE_SETTIMECONT2:	
	goto	MAINLOOPCONT

; -------------------------------------------------------------------------------
MODE3_SLOWFORWARD:									; MODE 3

	movlw	0x0A				
	movwf	INDEX2				
	call	SHORTDELAY	

	btfss	BUTTONPIN								; Set when Released
	goto	MODE3_SLOWFORWARD_DO

	RESETFFORWARDCOUNTER
	goto	MODE3_SLOWFORWARD_IDEL	
	
MODE3_SLOWFORWARD_DO:

;	RESETSLEEPTIMER

	incfsz	nextmodecounter,f
	goto	MODE3_SLOWFORWARD_DOCONT

	incfsz	nextmodecounter+1,f						; Larger number for longer delay
	goto	MODE3_SLOWFORWARD_DOCONT
;	goto	MODE3_SLOWFORWARD_EXIT

MODE3_SLOWFORWARD_EXIT:
;	clrf	nextmodecounter
	movlw	0x04
	movwf	MODEindex

	goto	MAINLOOPCONT

MODE3_SLOWFORWARD_DOCONT

	RESETSLEEPTIMER

	incfsz	SFcount,f
	goto	MODE3_SLOWFORWARD_IDEL

	call	UPDATECLOCKVARIABLES
	call	INCREMENTTIME

	movlw	SFcountSet
	movwf	SFcount
	
	goto	MAINLOOPCONT

MODE3_SLOWFORWARD_IDEL:								; Button Not pressed

	btfss	SLEEPFLAG								; -- Test for Sleep
	goto	MAINLOOPCONT
	movlw	0x01
	movwf	MODEindex
	goto	MAINLOOPCONT

; -------------------------------------------------------------------------------
MODE4_FASTFORWARD:									; MODE 4
	movlw	0x10				
	movwf	INDEX2				
	call	SHORTDELAY	

	btfsc	BUTTONPIN								; Set when Released
	goto	MODE4_SLOWFORWARD_STOP
;	goto	MODE4_SLOWFORWARD_DO	
	
MODE4_SLOWFORWARD_DO:
	RESETSLEEPTIMER
	call	UPDATECLOCKVARIABLES
	call	INCREMENTTIME	
	goto	MAINLOOPCONT

MODE4_SLOWFORWARD_STOP:

	movlw	SFcountSet
	movwf	SFcount
;	clrf	nextmodecounter
;	clrf	nextmodecounter+1
	RESETFFORWARDCOUNTER

	movlw	0x03									; Jump back to Slow Forward
	movwf	MODEindex
	goto	MAINLOOPCONT
; -------------------------------------------------------------------------------


MAINLOOPCONT:

	goto	MAINLOOP
	

;********************************************************************************
;																				*
;  SUBROUTINES 																	*
;																				*
;********************************************************************************

;******************************************************************************
; DELAY SUBROUTINE 
;******************************************************************************
DELAY
	movlw	0xFF
	movwf	DELAY_COUNTER
	movwf	DELAY_COUNTER2
	movfw	INDEX2
	movwf	DELAY_COUNTER3

DELAY_LOOP
	decfsz	DELAY_COUNTER,1
	goto 	DELAY_LOOP
	decfsz	DELAY_COUNTER2,1
	goto	DELAY_LOOP
	decfsz	DELAY_COUNTER3,1
	goto	DELAY_LOOP
	
	return
;
;******************************************************************************
; SHORT DELAY SUBROUTINE 
;******************************************************************************
SHORTDELAY:
	movf	INDEX2,w
	movwf	DELAY_COUNTER
	movwf	DELAY_COUNTER2

SHORTDELAY_LOOP:
	decfsz	DELAY_COUNTER,1
	goto 	SHORTDELAY_LOOP
	decfsz	DELAY_COUNTER2,1
	goto	SHORTDELAY_LOOP
	
	return

;******************************************************************************
; VERY SHORT DELAY SUBROUTINE 
;******************************************************************************
VERYSHORTDELAY:
	movf	INDEX2,w
	movwf	DELAY_COUNTER

VERYSHORTDELAY_LOOP:
	decfsz	DELAY_COUNTER,f
	goto 	VERYSHORTDELAY_LOOP
	
	return

;******************************************************************************
; Update Time Variables with latest time 
;******************************************************************************
UPDATECLOCKVARIABLES:
	movf	RAW_MINUTES,w
	andlw	b'00001111'
	movwf	MinOnes
			
	swapf	RAW_MINUTES,w
	andlw	b'00000111'		
	movwf	MinTens

	movf	RAW_HOURS,w
	andlw	b'00001111'
	movwf	HoursOnes
			
;	swapf	RAW_HOURS,w
;	andlw	b'00000011'		
;	movwf	HoursTens
;
;	btfsc	CLOCK1224								; Set when time = 12 hour format
;	bcf		HoursTens,1								; This the AM/PM or Higher 10 Hours bit

; newer
	swapf	RAW_HOURS,w
	andlw	b'00000001'		
	movwf	HoursTens								; 12 hour format

	return
	
;******************************************************************************
; Increment Current Time by 1 Minute 
;******************************************************************************
INCREMENTTIME:
	bsf		BUTTONFLAG						; Button NOW pressed
;	RESETSLEEPTIMER

;	CLEARDISPLAY
	incf	MinOnes,f
TESTIFOVERTEN_MIN:
	movlw	0x0A
	subwf	MinOnes,w
	btfss	STATUS,C
	goto	UPDATETIMECONT					; was UNDERTEN_MIN
OVERTEN_MIN:
	clrf	MinOnes

	incf	MinTens,f
TESTIFOVER60_MIN:
	movlw	0x06							; MinTens goes to 59 minutes, but only 0 to 5
	subwf	MinTens,w
	btfss	STATUS,C
	goto	UPDATETIMECONT
OVER60_MIN
	clrf	MinTens

;******************************************************* HOURS ONES UP -S
	incf	HoursOnes,f

; ------- test for 12 (or "3") o'clock -S
TESTIFOVERT12_HOURS:
	movlw	0x03
	subwf	HoursOnes,w
	btfss	STATUS,C
	goto	TESTIFOVERTEN_HOURS				; Check if 9 to 10 transition
	goto	TESTFOR12_HOURS_PART2			; Is three or higher

TESTFOR12_HOURS_PART2:						; Yes, x2 to x3 transition
	movf	HoursTens,f
	btfss	STATUS,Z						; If HoursTens is zero then we are not 12:00->1:00
	goto	TESTFOR12TO1
	goto	TESTIFOVERTEN_HOURS					; Yes HoursTens is Zero

TESTFOR12TO1:
	clrf	HoursTens
	movlw	0x01
	movwf	HoursOnes
	goto	UPDATETIMECONT	
	
; ------- test for 12 o clock -E
TESTIFOVERTEN_HOURS:						; Are the 1s going to 10s
	movlw	0x0A
	subwf	HoursOnes,w
	btfss	STATUS,C
	goto	UPDATETIMECONT					; Not over 10
OVERTEN_HOURS:
	clrf	HoursOnes						; Set time to 10:00 o'clock
	movlw	0x01
	movwf	HoursTens
	goto	UPDATETIMECONT


UPDATETIMECONT
	movlw	b'11110000'						; Minutes Ones Update
	andwf	RAW_MINUTES,f

	movf	MinOnes,w
	iorwf	RAW_MINUTES,f

	movlw	b'00001111'						; Minutes Tens Update				
	andwf	RAW_MINUTES,f

	swapf	MinTens,w
	iorwf	RAW_MINUTES,f

; ---

	movlw	b'11110000'						; Hours Ones Update
	andwf	RAW_HOURS,f

	movf	HoursOnes,w
	iorwf	RAW_HOURS,f

	movlw	b'11001111'						; Hours Tens Update				
	andwf	RAW_HOURS,f

	swapf	HoursTens,w
	iorwf	RAW_HOURS,f

	bsf		CLOCK1224						; Set the 12 hour indicator bit

;newer
	bcf		RAW_HOURS,5						; Force to 12 hour format

	bsf		SETTIME
	return
	
;*****************************************************************		
;	Modified I2C firmware of Chris Parris of Microchip Technology,
;	Please see Microchip App note #AN982
;*****************************************************************

BSTART

    bsf     PORTB,SCL            ; Make sure SCL is high
    TSUSTA                      ; Start condition setup time delay
    movlw   SDA_OUT             ; Configure SDA to be an output
    SETTRIS                     ; Copy value to TRISB register
    bcf     PORTB,SDA            ; Pull SDA low to initiate
                                ;  Start condition
    THDSTA                      ; Start condition hold time delay
    bcf     PORTB,SCL            ; Bring SCL low in preparation
                                ;  for data transfer
    movlw   SDA_IN              ; Configure SDA to be an input
    SETTRIS                     ; Copy value to TRISB register
    retlw   0

BSTOP
    movlw   SDA_OUT             ; Configure SDA to be an output
    SETTRIS                     ; Copy value to TRISB register
    bcf     PORTB,SDA            ; Pull SDA low
    bsf     PORTB,SCL            ; Make sure SCL is high
    TSUSTO                      ; Stop condition setup time delay
    movlw   SDA_IN              ; Configure SDA to be an input
    SETTRIS                     ; Copy value to TRISB register
                                ;  to initiate Stop condition
    retlw   0

BITOUT
    bcf     PORTB,SCL            ; Make sure SCL is low
    btfss   buffer,DO           ; Check for state of bit to xmit
    goto    bitlow              ; If bit is low, pull SDA low
clockout                        ; If bit is high, leave SDA high
    bsf     PORTB,SCL            ; Bring SCL high to begin transfer
    THIGH                       ; Clock high time delay
    movlw   SDA_IN              ; Configure SDA to be an input
    bcf     PORTB,SCL            ; Bring SCL low again
    SETTRIS                     ; Copy value to TRISB register
    retlw   0

bitlow
    movlw   SDA_OUT             ; Configure SDA to be an output
    SETTRIS                     ; Copy value to TRISB register
    bcf     PORTB,SDA            ; Pull SDA low
    goto    clockout

BITIN
    bcf     PORTB,SCL            ; Make sure SCL is low
    movlw   SDA_IN              ; Configure SDA to be an input
    SETTRIS                     ; Copy value to TRISB register
    bsf     buffer,DI           ; Assume input bit is high
    bsf     PORTB,SCL            ; Bring SCL high to begin transfer
    TAA                         ; Output valid from clock delay
    btfss   PORTB,SDA            ; Check for state of SDA bit
    bcf     buffer,DI           ; If SDA is low, set bit low
    bcf     PORTB,SCL            ; Bring SCL low again
    retlw   0

TX
    movlw   .8
    movwf   bitcount            ; Initialize loop counter to 8
txlp
    bsf     buffer,DO           ; Assume output bit is high
    btfss   datao,7             ; Check state of next output bit
    bcf     buffer,DO           ; If low, set buffer bit low
    call    BITOUT              ; Call routine to output bit
    rlf     datao,F             ; Rotate datao left for next bit
    decfsz  bitcount,F          ; Decrement counter, check if done
    goto    txlp                ; Keep looping
    call    BITIN               ; Call routine to read ACK bit
;   btfsc   buffer,DI           ; Check if ACK bit was received
;   goto    ackfailed           ; This executes if no ACK received   
    retlw   0

RX
    clrf    datai               ; Clear input buffer
    movlw   .8
    movwf   bitcount            ; Initialize loop counter to 8
    bcf     STATUS,C            ; make sure carry bit is low
rxlp
    rlf     datai,F             ; Rotate datai 1 bit left
    call    BITIN               ; Read a bit
    btfsc   buffer,DI
    bsf     datai,0             ; Set bit 0 if necessary
    decfsz  bitcount,F          ; 8 bits done?
    goto    rxlp                ; If not, do another
    bsf     buffer,DO           ; Assume ACK will not be sent
    btfsc   buffer,ACKB         ; Check state of ACKB bit
    bcf     buffer,DO           ; If ACKB = 1, send ACK (DO = 0)
    call    BITOUT              ; Send bit
    retlw   0

WAITTIME
top
    movlw   .100                ; Timing adjustment variable
    movwf   loops2              ;  this loop creates a 1 ms delay
top2
    nop                         ; Delay for 10 us
    goto    $+1                 ;  the delay includes the decfsz & goto
    goto    $+1
    goto    $+1
    decfsz  loops2, F           ; Inner loops complete?
    goto    top2                ; If no, go again

    decfsz  loops, F            ; Outer loops complete?
    goto    top                 ; If no, go again
    retlw   0                   ; If yes, return from sub
	
	
	
;******************************************************************************
; Double I2C Read Routine Minutes then Hours for DS1337+
;******************************************************************************
DOUBLEREAD:
		call    BSTART              ; Generate start bit
                                	; Now send the control byte
                                	; for a write, to set address
		movlw	RTCDS1337	; THIS WAS WRITE_ADDR
		movwf	datao               ; Copy control byte to buffer
		call	TX                  ; Output control byte to device

                                	; Next, the address pointer
		movlw	RTC_MIN          	; Copy address to WREG
		movwf   datao               ; Copy address to buffer
		call    TX                  ; Output address to device

		call	BSTART              ; Generate another start bit
                                	; to switch to read mode
		movlw	RTCDS1337+1	;THIS WAS READ_ADDR
		movwf	datao               ; Copy control byte to buffer
		call	TX                  ; Output control byte to device
                                	; Finally, read the data byte
;	  	bcf		buffer,ACKB         ; Select to send NO ACK bit
		bsf		buffer,ACKB         ; Select to send ACK bit ?
		call	RX                  ; Input data from device

	  	bcf		buffer,ACKB         ; Select to send NO ACK bit

		movf	datai,w
		movwf	RAW_MINUTES

		call	RX                  ; Input data from device

		call	BSTOP               ; Generate stop bit
		movf	datai,w
		movwf	RAW_HOURS

		return	
		
;******************************************************************************
; Double I2C WRITE Routine Minutes then Hours for DS1337+
;******************************************************************************
DOUBLEWRITE:
		call    BSTART              ; Generate start bit
                                	; Now send the control byte
                                	; for a write, to set address
		movlw	RTCDS1337	; THIS WAS WRITE_ADDR
		movwf	datao               ; Copy control byte to buffer
		call	TX                  ; Output control byte to device

                                	; Next, the address pointer
		movlw	RTC_SEC          	; Copy address to WREG
		movwf   datao               ; Copy address to buffer
		call    TX                  ; Output address to device

		clrf	datao				; Start the new time at zero seconds
		call	TX

		movf	RAW_MINUTES,w
		movwf   datao               ; Copy data to buffer	
		call    TX                  ; Output data to device

		movf	RAW_HOURS,w
		movwf   datao               ; Copy data to buffer	
		call    TX                  ; Output data to device

		call    BSTOP               ; Generate stop bit
    	movlw   .5
    	movwf   loops               ; Set delay time for 5 ms
    	call    WAITTIME              ; Delay for write operation

		return		

;******************************************************************************
; Handle Button Press - NEW INT
;******************************************************************************
ButtonINT:

	RESETSLEEPTIMER

	bcf		SLEEPFLAG
	bsf		JUSTWAKEUPFLAG							; Just woke up, don't set the time

	bcf		INTCON,INTF
	goto	InterruptEXIT 


;******************************************************************************
; Handle Timer 1 Int. - Used to flash colon
;******************************************************************************
TIMERONE:

	bcf		PIR1,TMR1IF
	clrf	TMR1L
	clrf	TMR1H

	btfsc	FLASHONOFFFLAG
	goto	CLEARFLASHFLAG
;	goto	SETFLASHFLAG

SETFLASHFLAG:
	bsf		FLASHONOFFFLAG

	goto	TIMERONEEXIT 

CLEARFLASHFLAG:
	bcf		FLASHONOFFFLAG

TIMERONEEXIT:
	btfsc	INTCON,T0IF			; Yes TIMER 0, check if it timed-out
	goto	TIMERZERO

	goto	InterruptEXIT 

;******************************************************************************
;  TIMER Zero Overflow  - Used to update lit LEDs on display
;******************************************************************************
TIMERZERO:						
	
	btfss	JUSTWAKEUPFLAG
	goto	TIMERZZEROCONT
	call	DOUBLEREAD							; Read new time right-away if waking-up
	call	UPDATECLOCKVARIABLES
	bcf		JUSTWAKEUPFLAG						; Clear flag to show new time
	goto	TIMERZEROEXIT	


TIMERZZEROCONT:	

	decfsz	SEGindex,f
	goto	DISPSEGMENT
;----------------------------
RESETSEGMENT:
	movlw	0x08								; Reset Segments 
	movwf	SEGindex
	movlw	b'10000000'
	movwf	SEGmask

	decfsz	DIGindex,f
	goto	NEXTDIGIT
RESETDIGIT:
	movlw	0x05
	movwf	DIGindex

	CLEARDISPLAY

	btfsc	FLASHCOLONFLAG
	goto	YESFLASH
	goto	NOFLASH
; ---------------------------------------------- Colon Flasher - S
YESFLASH
;	movf	MinOnes,w
;	subwf	OLDMinOnes,w
;	btfsc	STATUS,Z
;	goto	FLASHONOROFF						; No change are equal
;;	goto	FLASHUPDATESTATUS
;	
;FLASHUPDATESTATUS:
;
;	movf	MinOnes,w
;	movwf	OLDMinOnes	
;
;	btfss	FLASHONOFFFLAG
;	goto	SETFLASHFLAG
;	goto	CLEARFLASHFLAG
;
;SETFLASHFLAG:
;	bsf		FLASHONOFFFLAG
;	goto	FLASHONOROFF
;
;CLEARFLASHFLAG:
;	bcf		FLASHONOFFFLAG
;	goto	FLASHONOROFF

FLASHONOROFF:
	btfsc	FLASHONOFFFLAG
	goto	FLASH_ON
	goto	FLASH_OFF							; Old and new time are equal

FLASH_ON:
	bcf		colon							    ;	Turn On colon 
	goto	FLASHCOLONEXIT

FLASH_OFF:
	bsf		colon							    ;	Turn OFF colon 
	goto	FLASHCOLONEXIT

; ---------------------------------------------- Colon Flasher - E

NOFLASH
	bcf		colon							    ;	Turn On colon 

FLASHCOLONEXIT

	goto	TIMERZEROEXIT
;----------------------------
NEXTDIGIT:										; load next digit here - S
	movlw	DIGITS								; Memory location for BUFFER
	movwf	FSR	
;	movf	DIGindex,w
	decf	DIGindex,w
	addwf	FSR,f								; Add the INDEX offset

	movf	INDF,w								; Pointer to FSR memory location
	
	movwf	INDEX
	call	SEGMENTDECODETABLE

	movwf	DIGdisplay							; load next digit here - E
	CLEARDISPLAY

; ------

	btfsc	SETTIME
	goto	UPDATETIME							; Always update RTC if setting time
CHECKTIME:
	decfsz	TIMEUPDATECOUNTER,f
	goto	SKIPUPDATE	

	movlw	LEDBRIGHT
	movwf	TIMEUPDATECOUNTER

	call	DOUBLEREAD
	goto	DO_DIGITSTATE

UPDATETIME:
;	TOGGLEFLASH									; 

	call	DOUBLEWRITE
	bcf		SETTIME
;	goto	DO_DIGITSTATE
SKIPUPDATE:
; -s
DO_DIGITSTATE:									; Light Up correct digit (1 to 4)
;
	movlw	HIGH DIGITTABLE						; 
	movwf	PCLATH
;	movf	DIGindex,w
	decf	DIGindex,w
	addlw	LOW DIGITTABLE
	btfsc	STATUS,C
	incf	PCLATH,f
	movwf	PCL
;
DIGITTABLE:				
	goto	DIGIT4				;
	goto	DIGIT3				;
	goto	DIGIT2				;
	goto	DIGIT1				;	

DIGIT4:
	bsf		DIG4PIN
	goto	DISPSEGMENT

DIGIT3:
	bsf		DIG3PIN
	goto	DISPSEGMENT

DIGIT2:
	bsf		DIG2PIN
	goto	DISPSEGMENT

DIGIT1:

	movf	HoursTens,f
	btfsc	STATUS,Z
	goto	DIGIT1OFF

	bsf		DIG1PIN
DIGIT1OFF:
	goto	DISPSEGMENT
; -e

DISPSEGMENT:									; Output to Display
	rrf		SEGmask,f
	movf	SEGmask,w
	andwf	DIGdisplay,w
	movwf	SEGbuffer
	comf	SEGbuffer,f
	bsf		SEGbuffer,7  						; Don't light the colon :
	movf	SEGbuffer,w
	movwf	PORTC

TIMERZEROEXIT:

CHECKSLEEP:
	incf	sleepycounter,f
	btfss	STATUS,Z
	goto	CHECKSLEEPEXIT

	incf	sleepycounter+1,f					; Use for longer ON time
	btfss	STATUS,Z
	goto	CHECKSLEEPEXIT
YESSLEEP:

	bsf		SLEEPFLAG

CHECKSLEEPEXIT:


	movlw	TIMERZEROSET
	movwf	TMR0

	bcf		INTCON,T0IF	
	goto	InterruptEXIT 

;******************************************************************************
; DATA TABLES 
;******************************************************************************
SEGMENTDECODETABLE:									; Uses INDEX as an offset to
	movlw	HIGH DECODETABLE						; read other lines of Data
	movwf	PCLATH
	movf	INDEX,w
	addlw	LOW DECODETABLE
	btfsc	STATUS,C
	incf	PCLATH,f
	movwf	PCL

DECODETABLE:
;			"         |     |   |"	
;			  76543210
	RETLW	b'00111111'			; 0
	RETLW	b'00000110'			; 1
	RETLW	b'01011011'			; 2
	RETLW	b'01001111'			; 3
	RETLW	b'01100110'			; 4
	RETLW	b'01101101'			; 5
	RETLW	b'01111100'			; 6
	RETLW	b'00000111'			; 7
	RETLW	b'01111111'			; 8
	RETLW	b'01100111'			; 9

;******************************************************************************

PLACETOSTOP:
	end                     	; end of program

