	LIST P=16F876, R=DEC
	INCLUDE "P16F876.inc"

	__CONFIG (_CP_OFF & _HS_OSC & _PWRTE_ON & _WDT_OFF & _LVP_OFF)

	ERRORLEVEL -302

;==========================================================

	;Bank 0 RAM block
	CBLOCK 020h		;20h to 70h = 80 bytes available
		W_TEMP		;Holds W during interrupts
		STATUS_TEMP	;Holds STATUS during interrupts
		PCLATH_TEMP	;Holds PCLATH during interrupts
		txptr		;Transmit character pointer
		txchbuff:50	;transmit character buffer
		lasttxch	;Last transmit character (contents set to 00h)
		HIFIXCHAR	;High part of address of fixed char subroutine
		LOFIXCHAR	;Low part of address of fixed char subroutine

		;Used for Binary to ASCII conversion
		bin:4		; 32-bit binary number (unsigned)
		bcd:10		; 10 BC digits or 10 ascii chars
		pti,pto		; pointers
		ii
		temp
		cnt
	ENDC
	
	; Bank0/1/2/3 mirrored in all banks 0x70, 0xF0, 0x170, 0x1F0, 16 bytes
	CBLOCK	0x070
		; ram variables accesible from all banks mainly used for context saving
		; ( ram area above 0x70 are mirrored in all banks )
		Saved_W:1    	; variable used for context saving 
		Saved_Status:1  ; variable used for context saving
		Saved_Pclath:1	; 
		Saved_Fsr:1	;
		Table_Temp:1	; table lookup temp variable
		SendStrIndex	;Send text string index
		PROGSTAT	;Program status flags
	ENDC


	;Bank 2 RAM block
	CBLOCK 0110h		;Actually 0110h (96 bytes exclusive available in BANK2)
		TIMER0_1	;Second byte counter for Timer0
		TIMER0_2	;Third byte counter for Timer0
		TIMER0_3	;Fourth byte counter for Timer0
		TIMER0_OF	;Overflow status

		TIMER1_1	;Third byte counter for Timer1
		TIMER1_2	;Fourth byte counter for Timer1
		TIMER1_OF	;Overflow status

		;Timer 2 related counters
		ONE_CNT		;One second counter (1/75th second resolution)
		ORN_CNT		;Orientation mode sample counter (1/75th second resolution)
		TMP_CNT		;Temperature request sample counter (1 second resolution)
		MAG_CNT		;Magnetometer request sample counter (1 second resolution)

		TMR0BUFFER:4	;TIMER0 4-Byte buffer
		TMR1BUFFER:4	;TIMER1 4-Byte buffer
		
		TEMP1H		;Temperature 1 High byte
		TEMP1L		;Temperature 1 Low  byte
		TEMP2H		;Temperature 2 High byte
		TEMP2L		;Temperature 2 Low  byte

		SourceL		;Temporary subtraction register (DIFFERENCE ends up here)
		SourceM
		SourceH
		DestL		;Temporary subtraction register
		DestM
		DestH

		ORIENTED	;Flag indicating that sensors are oriented (!0=oriented)
		LOCKED		;Flag indicating that sensors are locked (!0=oriented)
		
	ENDC

	;Bank 3 RAM block
	CBLOCK	0190h		;Actually 0190h (16 bytes in BANK3)
		mv_i		;temporary move counter
		mv_temp		;temporary move register
	ENDC
	CBLOCK	020h		;Actually 01A0h (80 bytes in BANK3)
		TBUFF:80	;Storage for 10 32bit Timer buffers for each Timer
				;Arranged as:
				;TMR0 Byte1 buffer10
				;TMR0 Byte2 buffer10
				;    etc
				;TMR0 Byte4 buffer10
				;TMR1 Byte1 buffer10
				;TMR1 Byte2 buffer10
				;    etc
				;TMR1 Byte4 buffer10
				;TMR0 Byte1 buffer9
				;    etc
				;    etc
				;TMR1 Byte4 buffer1
	ENDC

ONE_PRL	EQU	75	;One Second count preload value 1s = 75 counts @ 19.6608MHz
ORN_PRL	EQU	16	;Orientation mode preload counter value (1/75ths seconds)
MAG_PRL	EQU	1	;Magnetometer sample preload (number of seconds per magnetometer samples)
TMP_PRL	EQU	2	;Temperature sample preload (number of seconds between temperature samples)

;PROGSTAT flag bit definitions
CMDBUSY	EQU	0	;Bit 0 = Command is being processed
STYPE	EQU	1	;Bit 1 = String type 0=Variable, 1=Fixed
ADACQ	EQU	2	;Bit 2 = A/D acquisition state, 0=sampling, 1=converting
TEMPREQ	EQU	3	;Bit 3 = Temperature request
ONESEC	EQU	4	;Bit 4 = On second elapsed flag
SAMPREQ	EQU	5	;Bit 5 = Sample request flag

HEALTH	EQU	2	;PortC bit for health LED

CR	EQU	0Dh
LF	EQU	0Ah
NULL	EQU	00h

; base frequency
XTAL_FREQ	EQU	19660800	; OSC freq in Hz

; caulculates baudrate when BRGH = 1, adjust for rounding errors
#define CALC_HIGH_BAUD(BaudRate)	(((10*XTAL_FREQ/(16*BaudRate))+5)/10)-1
; caulculates baudrate when BRGH = 0, adjust for rounding errors
#define CALC_LOW_BAUD(BaudRate)		(((10*XTAL_FREQ/(64*BaudRate))+5)/10)-1

; calculates timer1 delay when prescale is 1:8, adjust for rounding errors
#define CALC_TIMER(TickTime)	(0xFFFF-((TickTime*XTAL_FREQ)/32000))+1
; used for I2C calculations
;#define  I2CClock    D'100000'           ; define I2C bit rate
#define  I2CClock    D'50000'           ; define I2C bit rate
#define  I2C_ClockValue  (((XTAL_FREQ/I2CClock)/4) -1) ; 

;==========================================================

BANK0 MACRO
	BCF STATUS, RP0		; Select Bank 0
	BCF STATUS, RP1
	BCF STATUS, IRP
	ENDM

BANK1 MACRO
	BSF STATUS, RP0		; Select Bank 1
	BCF STATUS, RP1
	BCF STATUS, IRP
	ENDM

BANK2 MACRO
	BCF STATUS, RP0		; Select Bank 2
	BSF STATUS, RP1
	BSF STATUS, IRP
	ENDM

BANK3 MACRO
	BSF STATUS, RP0		; Select Bank 3
	BSF STATUS, RP1
	BSF STATUS, IRP
	ENDM

MOVE MACRO variable,value	;Move a variable into a file
	MOVLW value
	MOVWF variable
	ENDM

BMOVE MACRO	s_bank,s_variable,d_bank,d_variable 	;Move variables with banks defined
	IF s_bank == 0
		BANK0
	ENDIF
	IF s_bank == 1
		BANK1
	ENDIF
	IF s_bank == 2
		BANK2
	ENDIF
	IF s_bank == 3
		BANK3
	ENDIF
	MOVF	s_variable,W
	IF s_bank != d_bank
		IF d_bank == 0
			BANK0
		ENDIF
		IF d_bank == 1
			BANK1
		ENDIF
		IF d_bank == 2
			BANK2
		ENDIF
		IF d_bank == 3
			BANK3
		ENDIF
	ENDIF
	MOVWF	d_variable
	ENDM


;Check incoming command and go to its handler
; The command is just one char
; The handler is located at label
CMDCHK MACRO	char,label
	MOVF	RCREG, w	; Get the received word
	XORLW	char
	BTFSC	STATUS,Z
	GOTO	label
	ENDM


;Set the MUX value to addr
; The 8 channel MUX is located on the lower three bits of PORTB
; addr can be anything from 0-7
MUXSET	MACRO	addr
	MOVF	PORTB,W			;Get existing PORT B value
	ANDLW	011111000b
	IORLW	111b & addr
	MOVWF	PORTB
	ENDM

;	TABLE_JUMP Calculates an eventual page boundary crossing  
;	set's up the PCLATH register correctly
;	Offset must be in w-reg, offset 0 jumps to the next instr. 
;	Adjusts for 256 bytes boundary
;	Uses one byte of dedicated ram
TABLE_JUMP	MACRO	
	MOVWF	Table_Temp	; save wanted offset
	MOVLW	LOW($+8)	; get low adress ( of first instr. after macro )
	ADDWF	Table_Temp,F	; add offset
	MOVLW	HIGH($+6)	; get highest 5 bits ( of first instr. after macro )
	BTFSC	STATUS,C	; page crossed ? ( 256 byte )
	ADDLW	0x01		; Yes add one to high adress
	MOVWF	PCLATH		; load high adress in latch
	MOVF	Table_Temp,W	; get computed adress
	MOVWF   PCL		;   And jump
	ENDM

;STRFIX 
; - This macro is used to define fixed text to be sent out the serial port.
; - The address of this macro is called as a subroutine.
; - This 'subroutine' returns the character pointed to by the index SendStrIndex.
; Example usage:
; STRINGLABEL SSTRING "HELLO WORLD\x0D\x0A\x00"
; - Note the CRLF and zero termination.
; - Directive dt generates a number of RETLW lines.
; SendStrIndex is a pointer number from 0-n 
STRFIX	MACRO	text
	MOVF    SendStrIndex, W ; Get the string index
        TABLE_JUMP 		; tablejump macro jumps W number of lines
	dt	text		; i.e. equal to RETLW 'H' RETLW 'E' ....
	ENDM


PULSE MACRO	port,bit		;Single debugging pulse
	BANK0
	BSF port,bit
	BCF port,bit
	ENDM

PULSER MACRO	port,bit		;Continuous debugging pulse
	BANK0
	BSF port,bit
	BCF port,bit
	GOTO	$-2
	ENDM
	
;+++++
;	LONG_CALL long call, sets the page bits 4:5 of PCLATH
;	so call can cross ANY page boundary, reset's PCLATH after call.
; 	w-reg is left untouched.

LONG_CALL	MACRO	LABEL	
	LOCAL	DEST_HIGH, SOURCE_HIGH, DIFF_HIGH

DEST_HIGH  	SET	(HIGH(LABEL)&0x18)  	; save bit's 4:5 of dest adress
SOURCE_HIGH	SET	(HIGH($)&0x18)		; --- || ---  source adress
DIFF_HIGH	SET     DEST_HIGH ^ SOURCE_HIGH ; get difference ( XOR )

	IF	(DIFF_HIGH == 0) ; same page, SHOULD generate no extra code, delta 0 pages
	MESSG	"Call on same page, replace LONG_CALL with PCALL " LABEL
	NOP	; redundant NOP's 
	NOP
	CALL	LABEL
	NOP
	NOP
	ELSE	
		; test if both bits must be set ? i.e. page0<->page3 or page2<->page3
		IF	(DIFF_HIGH == 0x18) ; difference in BOTH bit's, delta 2 pages
		;MESSG  "Setting page bit's for long page crossing call"
		SET_PCLATH	DEST_HIGH   ; set both bits in PCLATH
		CALL	LABEL		
		SET_PCLATH	SOURCE_HIGH ; reset both bits in pclath	
		ELSE
			; if we end up here then one BSF/BCF is enough, i.e. delta 1 page
			; i.e. page0<->1 or page2<->3
			MESSG "Call only one page, replace LONG_CALL with SHORT_CALL " LABEL
			IF	(DIFF_HIGH == 0x10) ; diff in high bit
			NOP	; redundant NOP
			SET_PCLATH4 	DEST_HIGH ; set high(4) bit of PCLATH
			CALL	LABEL
			SET_PCLATH4	SOURCE_HIGH
			NOP	; redundant NOP
			ELSE
			; lowest bit only
			NOP	; redundant NOP
			SET_PCLATH3 	DEST_HIGH ; set low(3) bit of PCLATH
			CALL	LABEL
			SET_PCLATH3	SOURCE_HIGH
			NOP
			ENDIF
		ENDIF
	ENDIF
	
	ENDM

;+++++
;	SHORT_CALL short call, code for calling between page0<->1 or page2<->3
;	Reset's PCLATH after call.
; 	w-reg is left untouched.

SHORT_CALL	MACRO	LABEL	
	LOCAL	DEST_HIGH, SOURCE_HIGH, DIFF_HIGH
DEST_HIGH  	SET	(HIGH(LABEL)&0x18)  	; save bit's 4:5 of dest adress
SOURCE_HIGH	SET	(HIGH($)&0x18)		; --- || ---  source adress
DIFF_HIGH	SET     DEST_HIGH ^ SOURCE_HIGH ; get difference ( XOR )

	IF	(DIFF_HIGH == 0) ; same page, SHOULD generate no extra code, delta 0 pages
	MESSG	"Call on same page, replace SHORT_CALL with PCALL " LABEL
	NOP	; redundant NOP's 
	CALL	LABEL
	NOP
	ELSE	
		; for safety check so we do not require LONG_CALL
		IF	((DIFF_HIGH&0x18)==0x18)
		MESSG  " WARNING ! Replace SHORT_CALL with LONG_CALL " LABEL
		ENDIF

		;MESSG  "Setting page bit's for short page crossing call"
		IF	(DIFF_HIGH == 0x10) ; diff in high bit
		SET_PCLATH4 	DEST_HIGH ; set high(4) bit of PCLATH
		CALL	LABEL
		SET_PCLATH4	SOURCE_HIGH
		ELSE
		; lowest bit only
		SET_PCLATH3 	DEST_HIGH ; set low(3) bit of PCLATH
		CALL	LABEL
		SET_PCLATH3	SOURCE_HIGH
		ENDIF
	ENDIF
	
	ENDM

;+++++
;	PCALL page call, code for calling on same page
;	outputs messages if LONG/SHORT call could/must be used
;

PCALL	MACRO	LABEL	
	LOCAL	DEST_HIGH, SOURCE_HIGH, DIFF_HIGH
DEST_HIGH  	SET	(HIGH(LABEL)&0x18)  	; save bit's 4:5 of dest adress
SOURCE_HIGH	SET	(HIGH($)&0x18)		; --- || ---  source adress
DIFF_HIGH	SET     DEST_HIGH ^ SOURCE_HIGH ; get difference ( XOR )

	IF	(DIFF_HIGH == 0) ; same page, call ok
	CALL	LABEL
	ELSE	
		; for safety check so we do not require LONG_CALL
		IF	((DIFF_HIGH&0x18)==0x18)
		MESSG  " WARNING ! Replace PCALL with LONG_CALL " LABEL
		CALL	LABEL	; INCORRECT Call !!!
		ELSE
		MESSG  " WARNING ! Replace PCALL with SHORT_CALL " LABEL
		CALL	LABEL
		ENDIF
	ENDIF
	
	ENDM


;==========================================================

	ORG	0
	GOTO	INIT 

;==========================================================
	ORG	4
INTS
	;Save STATUS, W, and PCLATH registers in RAM
	MOVWF	W_TEMP		;Copy W to TEMP register
	SWAPF	STATUS,W	;Swap status to be saved into W
	CLRF	STATUS		;bank 0, regardless of current bank, Clears IRP,RP1,RP0
	MOVWF	STATUS_TEMP	;Save status to bank zero STATUS_TEMP register
	MOVF	PCLATH, W	;Only required if using pages 1, 2 and/or 3
	MOVWF	PCLATH_TEMP	;Save PCLATH into W
	CLRF	PCLATH		;Page zero, regardless of current page

	;determine if "RX character" interrupt
	BANK0
	BTFSC	PIR1, RCIF	; Check for received character  
	GOTO	COMMAND

	;determine if "TX buffer empty" interrupt
	BTFSS	PIR1,TXIF	;Check transmit Interrupt flag (1=interrupt)
	GOTO	INST1		;not set, check next int
	MOVF	txptr,F		;Check if characters are being sent
	BTFSS	STATUS,Z	;Zero=no string
	GOTO	NEXTCHAR


INST1
	;determine if Timer2 interrupt (semi-real-time-clock)
	BTFSC	PIR1,TMR2IF	;Check Timer2 Interrupt Flag
	GOTO	TIMER2INT

	;determine if Timer1 interrupt (second optional magnetometer)
	BTFSC	PIR1,TMR1IF	;Check Timer1 Interrupt Flag
	GOTO	TIMER1INT

	;determine if Timer0 interrupt (first magnetometer)
	BTFSC	INTCON,T0IF	;Check Timer0 Interrupt Flag
	GOTO	TIMER0INT


	;If nothing determined
	GOTO	INTEXIT

;-----------------------------------------------------------
TIMER0INT			;Timer0 Interrupt Handler
	BCF	INTCON,T0IF	;Clear out old interrupt flag
	BANK2
	INCFSZ	TIMER0_1,F	;Increment second byte and check for rollover
	GOTO	INTEXIT
	INCFSZ	TIMER0_2,F	;Increment third byte
	GOTO	INTEXIT
	INCFSZ	TIMER0_3,F	;Increment fourth byte
	GOTO	INTEXIT
	MOVE	TIMER0_OF,1	;Set Overflow bit
	GOTO	INTEXIT

;-----------------------------------------------------------
TIMER1INT			;Timer1 Interrupt Handler
	BCF	PIR1,TMR1IF	;Clear out old interrupt flag
	BANK2
	INCFSZ	TIMER1_1,F	;Increment third byte and check for rollover
	GOTO	INTEXIT
	INCFSZ	TIMER1_2,F	;Increment fourth byte
	GOTO	INTEXIT
	MOVE	TIMER1_OF,1	;Set Overflow bit
	GOTO	INTEXIT
;============================================================================
TIMER2INT	;TIMER2 Interrupt Handler
;This interrupt is generted many times a second by the accumulation
; of counts from TIMER2, its prescaler, and postscaler.
;Various asynchronous timers are maintained:
; - Magnetometer sample request (normally 1 second frequency)
; - Temperature sample request (normally 2 second frequency)
; - Orientation mode (normally many times faster than 1 second frequency)
;
;Magnetometer samples are shifted and the most recent count is recorded. 
;The magnetometer counters are reset so that a new count can be started.
;Since the magnetometer TIMERs get reset even though they may be about to
;  count up, it is possible to miss that count. Fortunately that missed count
;  is not that important so we can ignore the small error.
;---------------------------------------------------------------------------

	BCF	PIR1,TMR2IF	;Clear out old interrupt flag

;---------------------------------------------------------------------------
;Extinguish HEALTH lamp in case it was previously on
	BANK0
	BCF	PORTC,HEALTH

;---------------------------------------------------------------------------
;Check if ORIENTATION (high-speed) sample mode count has elapsed
	BANK2
	DECFSZ	ORN_CNT,F
	GOTO	T2_OR_E		;Orientation counter still running (do nothing)

;Orientation counter expired
	MOVE	ORN_CNT,ORN_PRL	;Reload ORIENT mode counter

	;Check for ORIENT mode
	BANK0
	BTFSS	PORTB,5		;Check if orientation mode switch is set (=0)
	BSF	PROGSTAT,SAMPREQ	;Request Magnetometer Sample

T2_OR_E	;All finished checking orientation counter	
	

;---------------------------------------------------------------------------
;Check if 1s has elapsed
	BANK2
	DECFSZ	ONE_CNT,F
	GOTO	T2_ON_E		;One second has not yet elapsed,

;One second has elapsed:
; - Reload One second counter
	MOVE	ONE_CNT,ONE_PRL	;Reload one second counter


; - Check if Magnetometers should be sampled 

	DECFSZ	MAG_CNT,F	;Check magnetometer sample counter
	GOTO	T2_ON_2		;Magnetometer sample is not yet required

	MOVE	MAG_CNT,MAG_PRL	;Reload magnetometer sample rate counter

	;Check for REGULAR (non-Orient) mode
	BANK0
	BTFSC	PORTB,5		;Check if orientation mode switch is not set (=1)
	BSF	PROGSTAT,SAMPREQ	;Request Magnetometer Sample

T2_ON_2

; - Check if temperature sensors should be sampled 
	BANK2
	DECFSZ	TMP_CNT,F	;Check if temperature sample should be done
	GOTO	T2_ON_E		;Temperature sample is not yet required

T2_ON_3	MOVE	TMP_CNT,TMP_PRL	;Reload temperature sample rate counter
	BSF	PROGSTAT,TEMPREQ	;Request a temperature reading

T2_ON_E

;---------------------------------------------------------------------------

	BTFSS	PROGSTAT,SAMPREQ	;Check if Magnetometer sample has been requested
	GOTO	T2_MAGSAMP_E		;Magnetometer sample has not been requested

	BCF	PROGSTAT,SAMPREQ	;Clear out sample request since it is being done now

;Illuminate health light indicating that a sample is being taken
	BANK0
	BSF	PORTC,HEALTH


;---------------------------------------------------------------------------
;Record TMR0 value
;Check for TMR0 overflow then buffer the timer counts
T2_T0_0	BTFSS	INTCON,T0IF	;Check Timer0 Interrupt Flag
	GOTO	T2_T0_2		;TMR0 Int flag is not set

T2_T0_1	;TMR0 Int flag is set
	BCF	INTCON,T0IF	;Clear out old interrupt flag
	BANK2
	INCFSZ	TIMER0_1,F	;Increment second byte and check for rollover
	GOTO	T2_T0_2
	INCFSZ	TIMER0_2,F	;Increment third byte
	GOTO	T2_T0_2
	INCFSZ	TIMER0_3,F	;Increment fourth byte
	GOTO	T2_T0_2
	MOVE	TIMER0_OF,1	;Set Overflow bit

T2_T0_2	;Store current counts temporarily
	BMOVE	2,TIMER0_3,2,TMR0BUFFER
	BMOVE	2,TIMER0_2,2,TMR0BUFFER+1
	BMOVE	2,TIMER0_1,2,TMR0BUFFER+2
	BMOVE	0,TMR0    ,2,TMR0BUFFER+3

	;Make one last check if Interrupt flag was set during last reading
	BTFSC	INTCON,T0IF	;Check Timer0 Interrupt Flag
	GOTO	T2_T0_1

	;Reset counters, overflow indicators, timer registers
	BANK2
	CLRF	TIMER0_3
	CLRF	TIMER0_2
	CLRF	TIMER0_1
	CLRF	TIMER0_OF
	BANK0
	CLRF	TMR0
	BCF	INTCON,T0IF	;Clear out overflow flag in case it just overflowed

;---------------------------------------------------------------------------
	;Turn off Timer 1 to prevent any rollover for example:
	; - two 8 bit counters may roll over unless stopped
	; - 16 bit counter may generate an overflow
	BANK0
	BCF	T1CON,TMR1ON

;Check for TMR1 overflow in case it overflowed before entering this routine
T2_T1_0	BANK0
	BTFSS	PIR1,TMR1IF	;Check Timer1 Interrupt Flag
	GOTO	T2_T1_2		;TMR1 Int flag is not set

T2_T1_1	;TMR1 Int flag is set
	BANK0
	BCF	PIR1,TMR1IF	;Clear out old interrupt flag
	BANK2
	INCFSZ	TIMER1_1,F	;Increment third byte and check for rollover
	GOTO	T2_T1_2
	INCFSZ	TIMER1_2,F	;Increment fourth byte
	GOTO	T2_T1_2
	MOVE	TIMER1_OF,1	;Set Overflow bit

T2_T1_2	;Store current counts temporarily
	BMOVE	2,TIMER1_2,2,TMR1BUFFER
	BMOVE	2,TIMER1_1,2,TMR1BUFFER+1
	BMOVE	0,TMR1H   ,2,TMR1BUFFER+2
	BMOVE	0,TMR1L   ,2,TMR1BUFFER+3

	;Reset counters, overflow indicators, timer registers
	BANK2
	CLRF	TIMER1_2
	CLRF	TIMER1_1
	CLRF	TIMER1_OF
	BANK0
	CLRF	TMR1H
	CLRF	TMR1L

	;Turn on Timer 1 (two 8 bit counters may roll over unless stopped)
	BANK0
	BSF	T1CON,TMR1ON


;---------------------------------------------------------------------------
	;Move Timer results up through timer buffer
	; From: http://www.piclist.com/techref/microchip/memmove.htm?key=move&from=
	;	Moving data blocks 
	;	Dmitry Kiryashov 
	;
	; for ( mv_i = num_of_elements; mv_i != 0; ) { mv_i--; b[mv_i] = a[mv_i]; } 
	BANK3
        movlw   36	;num_of_elements 
        movwf   mv_i 
mvloop: 
        decf    mv_i, W 
        addlw   TBUFF+4	;a 
        movwf   FSR     ; (a+i) 
        movfw   INDF 
        movwf   mv_temp 
	;
        movlw   4	;(b-a) 
        addwf   FSR, F  ; (b+i) 
        movfw   mv_temp 
        movwf   INDF 
	;
        decfsz  mv_i, F 
        goto    mvloop 


	;Move current count into BUFFER 1
	BMOVE	2,TMR0BUFFER+0,3,TBUFF+72
	BMOVE	2,TMR0BUFFER+1,3,TBUFF+73
	BMOVE	2,TMR0BUFFER+2,3,TBUFF+74
	BMOVE	2,TMR0BUFFER+3,3,TBUFF+75

	BMOVE	2,TMR1BUFFER+0,3,TBUFF+76
	BMOVE	2,TMR1BUFFER+1,3,TBUFF+77
	BMOVE	2,TMR1BUFFER+2,3,TBUFF+78
	BMOVE	2,TMR1BUFFER+3,3,TBUFF+79

;---------------------------------------------------------------------------
;Check for orientation (counts are close)
; If abs(M1-M2)<100 then illuminate "Oriented" LED output
;Note: if identical then locking is occuring, this should be indicated somehow
;      so that the user can orient the sensors at something besides 180
;      degrees apart. **** todo ***

;DestH;M;L = Difference = Dest-Source

	BANK2
	CLRF	ORIENTED

	;TMR0 - TMR1
	BMOVE	2,TMR0BUFFER+3,2,DestL
	BMOVE	2,TMR0BUFFER+2,2,DestM
	BMOVE	2,TMR0BUFFER+1,2,DestH

	BMOVE	2,TMR1BUFFER+3,2,SourceL
	BMOVE	2,TMR1BUFFER+2,2,SourceM
	BMOVE	2,TMR1BUFFER+1,2,SourceH

	CALL	SUBTRACT24
	SKPC			;skip if no borrow
	GOTO	T2_ORN0		;must have been negative check other

	;200 - Difference1
	BMOVE	2,DestL,2,SourceL
	BMOVE	2,DestM,2,SourceM
	BMOVE	2,DestH,2,SourceH

	MOVE	DestL,200
	MOVE	DestM,0
	MOVE	DestH,0

	CALL	SUBTRACT24
	SKPNC			;If carry set then <200 (ORIENTED)
	INCF	ORIENTED,F	

	GOTO	T2_ORN1

T2_ORN0	;TMR1 - TMR0
	BMOVE	2,TMR1BUFFER+3,2,DestL
	BMOVE	2,TMR1BUFFER+2,2,DestM
	BMOVE	2,TMR1BUFFER+1,2,DestH

	BMOVE	2,TMR0BUFFER+3,2,SourceL
	BMOVE	2,TMR0BUFFER+2,2,SourceM
	BMOVE	2,TMR0BUFFER+1,2,SourceH

	CALL	SUBTRACT24

	;200 - Difference1
	BMOVE	2,DestL,2,SourceL
	BMOVE	2,DestM,2,SourceM
	BMOVE	2,DestH,2,SourceH

	MOVE	DestL,200
	MOVE	DestM,0
	MOVE	DestH,0

	CALL	SUBTRACT24
	SKPNC			;If carry set then <200 (ORIENTED)
	INCF	ORIENTED,F	

T2_ORN1	MOVF	ORIENTED,W
	BANK0
	BTFSC	STATUS,Z
	GOTO	T2_ORN2
	BSF	PORTC,5
	GOTO	T2_ORN3
T2_ORN2
	BCF	PORTC,5
T2_ORN3

;Check if units are locked in frequency
	BANK2
	CLRF	LOCKED

	;TMR0 - TMR1
	BMOVE	2,TMR0BUFFER+3,2,DestL
	BMOVE	2,TMR0BUFFER+2,2,DestM
	BMOVE	2,TMR0BUFFER+1,2,DestH

	BMOVE	2,TMR1BUFFER+3,2,SourceL
	BMOVE	2,TMR1BUFFER+2,2,SourceM
	BMOVE	2,TMR1BUFFER+1,2,SourceH

	CALL	SUBTRACT24
	SKPC			;skip if no borrow
	GOTO	T2_ORN5		;must have been negative check other

	;10 - Difference1
	BMOVE	2,DestL,2,SourceL
	BMOVE	2,DestM,2,SourceM
	BMOVE	2,DestH,2,SourceH

	MOVE	DestL,10
	MOVE	DestM,0
	MOVE	DestH,0

	CALL	SUBTRACT24
	SKPNC			;If carry set then <10 (ORIENTED)
	INCF	LOCKED,F	
	GOTO	T2_ORN6

T2_ORN5	;TMR1 - TMR0
	BMOVE	2,TMR1BUFFER+3,2,DestL
	BMOVE	2,TMR1BUFFER+2,2,DestM
	BMOVE	2,TMR1BUFFER+1,2,DestH

	BMOVE	2,TMR0BUFFER+3,2,SourceL
	BMOVE	2,TMR0BUFFER+2,2,SourceM
	BMOVE	2,TMR0BUFFER+1,2,SourceH

	CALL	SUBTRACT24

	;10 - Difference1
	BMOVE	2,DestL,2,SourceL
	BMOVE	2,DestM,2,SourceM
	BMOVE	2,DestH,2,SourceH

	MOVE	DestL,10
	MOVE	DestM,0
	MOVE	DestH,0

	CALL	SUBTRACT24
	SKPNC			;If carry set then <10 (ORIENTED)
	INCF	LOCKED,F	

T2_ORN6	MOVF	LOCKED,W
	BANK0
	BTFSC	STATUS,Z
	GOTO	T2_ORN7
	BSF	PORTB,0
	GOTO	T2_ORN8
T2_ORN7
	BCF	PORTB,0
T2_ORN8






;---------------------------------------------------------------------------
;*** Move all of this time intensive code out of the interrupt routine and into
;    a psuedo multiasker.
;Check if continuous-output mode setting is on
	BANK0
	BTFSC	PORTB,6		;skip if cont mode is required (pin shorted to GND)
	GOTO	T2_MAGSAMP_E	;cont mode is not required

	BSF	PROGSTAT,CMDBUSY	;Indicate that command is being processed
	GOTO	CMD_CONT		;Execute continuous output


T2_MAGSAMP_E	;End of Magnetometer sampling code
	GOTO	INTEXIT


;==========================================================================
COMMAND
	BANK0

	;If already busy then this command gets lost - sorry
	BTFSS	PROGSTAT,CMDBUSY
	GOTO	COMMAND_CHECKING;Not busy - process a new command
	MOVF	RCREG, w	;Clear the RX interrupt flag
	GOTO	INTEXIT		;Exit to wait for other interrupts
	
COMMAND_CHECKING
	BSF	PROGSTAT,CMDBUSY	;Indicate that command is being processed

	;Determine what command was received
	CMDCHK	'1',COMMAND1
	CMDCHK	'2',COMMAND2
	CMDCHK	'v',SEND_A	;test simple variable text sending
	CMDCHK	'f',SEND_B	;test simple fixed text sending

	;All other (unknown) commands fall through here
CMD_CONT
	BMOVE	3,TBUFF+72,0,bin
	BMOVE	3,TBUFF+73,0,bin+1
	BMOVE	3,TBUFF+74,0,bin+2
	BMOVE	3,TBUFF+75,0,bin+3

	call	b2bcd		; convert to 32-bit binary to 10 bcd
	call	bcd2a		; convert 10 bcd to 10 ascii

	;Move ASCII result into transmit buffer area

	MOVF	bcd,W
	MOVWF	txchbuff
	MOVF	bcd+1,W
	MOVWF	txchbuff+1
	MOVF	bcd+2,W
	MOVWF	txchbuff+2
	MOVF	bcd+3,W
	MOVWF	txchbuff+3
	MOVF	bcd+4,W
	MOVWF	txchbuff+4
	MOVF	bcd+5,W
	MOVWF	txchbuff+5
	MOVF	bcd+6,W
	MOVWF	txchbuff+6
	MOVF	bcd+7,W
	MOVWF	txchbuff+7
	MOVF	bcd+8,W
	MOVWF	txchbuff+8
	MOVF	bcd+9,W
	MOVWF	txchbuff+9
	MOVE	txchbuff+10,','		;comma

	;get timer 1 value
	BMOVE	3,TBUFF+76,0,bin
	BMOVE	3,TBUFF+77,0,bin+1
	BMOVE	3,TBUFF+78,0,bin+2
	BMOVE	3,TBUFF+79,0,bin+3

	call	b2bcd		; convert to 32-bit binary to 10 bcd
	call	bcd2a		; convert 10 bcd to 10 ascii

	MOVF	bcd,W
	MOVWF	txchbuff+11
	MOVF	bcd+1,W
	MOVWF	txchbuff+12
	MOVF	bcd+2,W
	MOVWF	txchbuff+13
	MOVF	bcd+3,W
	MOVWF	txchbuff+14
	MOVF	bcd+4,W
	MOVWF	txchbuff+15
	MOVF	bcd+5,W
	MOVWF	txchbuff+16
	MOVF	bcd+6,W
	MOVWF	txchbuff+17
	MOVF	bcd+7,W
	MOVWF	txchbuff+18
	MOVF	bcd+8,W
	MOVWF	txchbuff+19
	MOVF	bcd+9,W
	MOVWF	txchbuff+20

	MOVE	txchbuff+21,','		;comma

	;get temperature 00 value
	BANK0
	MOVE	bin,0
	MOVE	bin+1,0
	BMOVE	2,TEMP1H,0,bin+2
	BMOVE	2,TEMP1L,0,bin+3

	call	b2bcd		; convert to 32-bit binary to 10 bcd
	call	bcd2a		; convert 10 bcd to 10 ascii

	MOVF	bcd,W
	MOVWF	txchbuff+22
	MOVF	bcd+1,W
	MOVWF	txchbuff+23
	MOVF	bcd+2,W
	MOVWF	txchbuff+24
	MOVF	bcd+3,W
	MOVWF	txchbuff+25
	MOVF	bcd+4,W
	MOVWF	txchbuff+26
	MOVF	bcd+5,W
	MOVWF	txchbuff+27
	MOVF	bcd+6,W
	MOVWF	txchbuff+28
	MOVF	bcd+7,W
	MOVWF	txchbuff+29
	MOVF	bcd+8,W
	MOVWF	txchbuff+30
	MOVF	bcd+9,W
	MOVWF	txchbuff+31

	MOVE	txchbuff+32,','		;comma

	;get temperature 1 value
	BANK0
	MOVE	bin,0
	MOVE	bin+1,0
	BMOVE	2,TEMP2H,0,bin+2
	BMOVE	2,TEMP2L,0,bin+3

	call	b2bcd		; convert to 32-bit binary to 10 bcd
	call	bcd2a		; convert 10 bcd to 10 ascii

	MOVF	bcd,W
	MOVWF	txchbuff+33
	MOVF	bcd+1,W
	MOVWF	txchbuff+34
	MOVF	bcd+2,W
	MOVWF	txchbuff+35
	MOVF	bcd+3,W
	MOVWF	txchbuff+36
	MOVF	bcd+4,W
	MOVWF	txchbuff+37
	MOVF	bcd+5,W
	MOVWF	txchbuff+38
	MOVF	bcd+6,W
	MOVWF	txchbuff+39
	MOVF	bcd+7,W
	MOVWF	txchbuff+40
	MOVF	bcd+8,W
	MOVWF	txchbuff+41
	MOVF	bcd+9,W
	MOVWF	txchbuff+42

	MOVE	txchbuff+43,00dh	;CR
	MOVE	txchbuff+44,00ah	;LF
	MOVE	txchbuff+45,000h	;The last character is 00h

	GOTO	FIRSTCHAR
;-----------------------------------------------------------
COMMAND1
	MOVE	txchbuff,031h
	MOVE	txchbuff+1,000h		;The last character is 00h
	GOTO	FIRSTCHAR
;-----------------------------------------------------------
COMMAND2	MOVE	txchbuff,032h
	MOVE	txchbuff+1,000h		;The last character is 00h
	GOTO	FIRSTCHAR

COMMAND_D	;Test fixed string sending

; ***********************************************************************
; To send characters using this method, the following must be used.
; The routine is entered during the interrupt routine.
; The exit of this routine is done with a standard interrupt exit.
; This routine:
;   - stores characters into RAM
;   - Sets the pointer for the first character
;   - GOTO the code that sends the first character (FIRSTCHAR)
;     and exits from the interrupt
;   - Future characters are sent upon TX buffer empty interrupt
; The characters have the following meaning:
;   00 - end of transmission
;   01 XX XX - fixed text at address XX XX (in subroutine form)
;   02 XX XX - location of code to execute at address XX XX (which might produce more text)
;   all others - variable text


SEND_A	;Example code to send variable data
	MOVE	txchbuff,'V'		;Send the character 'V'
	MOVE	txchbuff+1,000h		;The last character is 00h
	GOTO	FIRSTCHAR

SEND_B	;Example code to send fixed code
	MOVE	txchbuff,001h		;Indicate that Fixed text exists at the following address
	MOVE	txchbuff+1,HIGH(STRING0)
	MOVE	txchbuff+2,LOW(STRING0)
	GOTO	FIRSTCHAR

SEND_C	;Example code to send mixed variable and fixed chars starting with variable chars
	MOVE	txchbuff,031h		;Send the character '1'
	MOVE	txchbuff+1,001h		;Indicate that Fixed text exists at the following address
	MOVE	txchbuff+2,HIGH(STRING0)
	MOVE	txchbuff+3,LOW(STRING0)
	GOTO	FIRSTCHAR

SEND_D	;Example code to send mixed variable and fixed chars starting with fixed chars
	MOVE	txchbuff,001h		;Indicate that Fixed text exists at the following address
	MOVE	txchbuff+1,HIGH(STRING0)
	MOVE	txchbuff+2,LOW(STRING0)
	MOVE	txchbuff+3,031h		;Send the character '1'
	MOVE	txchbuff+4,000h		;The last character is 00h
	GOTO	FIRSTCHAR

SEND_E	;Example code to send partial code, continued by next code
	GOTO	FIRSTCHAR
SEND_E1
	GOTO	FIRSTCHAR

;-------------------------------------------------------------------------
FIRSTCHAR	;Send the first character.
	;BANK0 is assumed
	;
	BCF	PROGSTAT,STYPE	;Assume NEXT_CHAR is a variable chars
	CLRF	txptr		;Set the transmit character pointer to the first location.
	BANK1
	BSF	PIE1, TXIE	;Enable the transmit buffer empty interrupt
NEXTCHAR	;Send the next character pointed to by txptr
	;Called by "TX buffer empty" interrupts

	;Check if Fixed or variable characters
	BTFSC	PROGSTAT,STYPE
	GOTO	FCHAR

	BANK0
	MOVF	txptr,W		;Get pointer
	ADDLW	txchbuff	;Add offset of transmit buffer address
	MOVWF	FSR		;Place pointer into indirect file

	;Check for control character
	MOVF	INDF,W		;get character to be sent
	BTFSC	STATUS,Z	;check if last character (00h)
	GOTO	LASTCHAR	;do not send last character, just exit

	XORLW	001h		;check for FIXED character definition (01h)
	BTFSC	STATUS,Z
	GOTO	FIXEDCHAR	;Fixed characters exist

	XORLW	002h		;check for executable code definition (02h)
	BTFSC	STATUS,Z
	GOTO	CODECHAR	;New code exists to create more chars 

	;Send character
	MOVF	INDF,W		;get character to be sent
	MOVWF	TXREG		;send character
	INCF	txptr,F		;Increment pointer
	GOTO	INTEXIT

FCHAR	;Send a fixed character from predefined ROM address
	CALL	F3	;call fixed string subroutine
	;Return here to send character
	GOTO	F1

LASTCHAR
	CLRF	txptr		;indicate that transmission is over
	BCF	PROGSTAT,CMDBUSY ;Indicate that command is finished processing
	BANK1
	BCF	PIE1, TXIE	;Disable the Tx interrupt - no more chars to send
	GOTO	INTEXIT
;----------------------------------------------------------
FIXEDCHAR
;	Address of long call is located at where txptr is pointing to.

	BSF	PROGSTAT,STYPE	;Set NEXT_CHAR for fixed chars
	INCF	txptr,F		;Point to next character in RAM which contains address
	CLRF	SendStrIndex	;point to the first char to send from ROM
	
	CALL	F2
	; - return point from subroutine
F1	CLRF	PCLATH		;Put PCLATH back to where this page
	ADDLW	0		;test for last character (set/reset Z)
	BTFSC	STATUS,Z	;check if last character (00h)
	GOTO	LASTCHAR	;do not send last character, just exit
	MOVWF	TXREG		;send character
	INCF	SendStrIndex,F	;Increment pointer
	GOTO	INTEXIT

F2	;Get pointer to fixed string from RAM
	MOVF	txptr,W		;Get pointer
	ADDLW	txchbuff	;Add offset of transmit buffer address
	MOVWF	FSR		;Place pointer into indirect file
	MOVF	INDF,W		;get HIGH address of jump point
	MOVWF	HIFIXCHAR	;Store High address for later
	INCF	txptr,F		;Increment pointer
	MOVF	txptr,W		;Get pointer
	ADDLW	txchbuff	;Add offset of transmit buffer address
	MOVWF	FSR		;Place pointer into indirect file
	MOVF	INDF,W		;get HIGH address of jump point
	MOVWF	LOFIXCHAR	;Store Low address for later

F3	;Jump to fixed string routine which returns char to be sent in W
	MOVF	HIFIXCHAR,W
	MOVWF	PCLATH
	MOVF	LOFIXCHAR,W
	MOVWF	PCL		;Jump to desired address
				;Return to previous call location

;----------------------------------------------------------
CODECHAR	;*** unfinished ***
	GOTO	INTEXIT
;----------------------------------------------------------

INTEXIT	;Exit from interrupt routines
	;
	;Restore STATUS, W, and PCLATH registers in RAM
	BANK0
	MOVF	PCLATH_TEMP, W	;Restore PCLATH
	MOVWF	PCLATH		;Move W into PCLATH
	SWAPF	STATUS_TEMP,W	;Swap STATUS_TEMP register into W
	;(sets bank to original state)
	MOVWF	STATUS		;Move W into STATUS register
	SWAPF	W_TEMP,F	;Swap W_TEMP
	SWAPF	W_TEMP,W	;Swap W_TEMP into W
	RETFIE			;exit and enable interrupts

;==========================================================


INIT
	; Set initial port values
	BANK0
	MOVE	PORTA, 00h	; Misc PORTA
	MOVE	PORTB, 00h	; Unused port
	MOVE	PORTC, 00h	; Misc. port

	;Set port direction
	BANK1
	MOVE	ADCON1,06h	; Set all bits on port A to digital
	MOVE	TRISA, 00010000b
		;      00------ NC
		;      --0----- unused output
		;      ---1---- T0CKI input
		;      ----0000 unused output

	MOVE	TRISB, 11100000b
		;      1------- Parity setting input
		;      -1------ Continuous setting input
		;      --1----- Orientation mode input
		;      ---0000- unused outputs
		;      -------0 Locked LED output

	BCF	OPTION_REG,NOT_RBPU; enable weak pullups on port B inputs
	MOVE	TRISC, 10011001b
		;      1------- RX is serial data in
		;      -0------ TX is serial data out
		;      --0----- Oriented Indicator output
		;      ---1---- SDA input
		;      ----1--- SCL input
		;      -----0-- HEARBEAT LED output
		;      ------0- T1OSCI input (input for debug only)
		;      -------1 T1CKI input


	BANK0
	CLRF	PROGSTAT	;Clear all program status flags

	;Clear All RAM in BANK2 (from 10h to 7Fh)
	BANK2
	MOVLW	010h		;initialize pointer
	MOVWF	FSR		;to RAM
	CLRF 	INDF		;clear INDF register, Loopback point
	INCF	FSR,F		;inc pointer
	BTFSS	FSR,7		;all done?
	GOTO	$-3		;not done yet, clear next address

	;Clear All RAM in BANK3 (from 10h to 7Fh)
	BANK3
	MOVLW	010h		;initialize pointer
	MOVWF	FSR		;to RAM
	CLRF 	INDF		;clear INDF register, Loopback point
	INCF	FSR,F		;inc pointer
	BTFSS	FSR,7		;all done?
	GOTO	$-3		;not done yet, clear next address

;==========================================================
; Set up TIMER0 for clock pulses from magnetometer 1
;==========================================================
	BANK1
	BSF	OPTION_REG,T0CS	;Tansition on T0CKI pin
	BCF	OPTION_REG,T0SE	;Increment on low-to-high transition on T0CKI pin
	BSF	OPTION_REG,PSA	;Prescaler is assigned to the WDT (not to TMR0, no prescaling required)

	BSF	INTCON,T0IE	;Set Timer0 Interrupt Enable

	BANK2
	CLRF	TMR0		;First byte
	CLRF	TIMER0_1	;Second byte
	CLRF	TIMER0_2	;Third byte
	CLRF	TIMER0_3	;Fourth byte


;==========================================================
; Set up TIMER1 for clock pulses from magnetometer 2 (optional)
;==========================================================

	BANK0
	CLRF	TMR1L		;Clear lower byte of counter
	CLRF	TMR1H		;Clear upper byte of counter

	MOVE	T1CON, 00000011b
		;      00------ Unimplemented
		;      --00---- T1CKPS1,0  = Prescaler 1:1
		;      ----1--- T1OSCEN  Debug Timer1 oscillator enabled (using crystal clock)
		;      ----0--- T1OSCEN  Timer1 oscillator disabled (using external clock)
		;      -----0-- !T1SYNC  = Syncrhonous
		;      ------1- TMR1CS   = Clock source is external RC0/T1CKI
		;      -------1 TMR1ON   = Enable Timer1


	BANK1
	BSF	PIE1,T0IE	;Set Timer0 Interrupt Enable

	BANK2
	CLRF	TIMER1_1	;Third byte counter for Timer1
	CLRF	TIMER1_2	;Fourth byte counter for Timer1
	CLRF	TIMER1_OF	;Overflow status

;==========================================================
; Set up TIMER2 for real-time clock function
;==========================================================
;At Fosc = 4MHz
; Fosc/4 = 1MHz
; Prescaler (1:16) = 62.5kHz
; Timer 8bit = 244Hz
; Postscaler (1:16) = 15.26Hz
; Result = 4MHz / 262144 = interrupt every 65.536 ms (15.2587Hz)
; RTCCOUNT=15 therefore; 1.017..Hz = .98304s



	BANK0
	MOVE	T2CON,01111110b	;<7>   = 0	Not used
				;<6:3> = 1111	Postscaler = 1:16
				;<2>   = 1	Timer 2 ON
				;<1:0> = 10	Prescaler  = 1:16

	BANK1
	BSF	PIE1,TMR2IE	

	;TMR2 is cleared on reset, no need to clear it here.

	BANK2
	MOVE	ONE_CNT,ONE_PRL	;Preload 1 second counter
	MOVE	ORN_CNT,ORN_PRL	;Pre-load Orientation mode counter 
	MOVE	MAG_CNT,MAG_PRL	;Pre-load Magnetometer sample counter 
	MOVE	TMP_CNT,TMP_PRL	;Pre-load Temperature sample counter 


;==========================================================
; Set up USART for 9600 baud communications with computer
;==========================================================

	BANK1
	BSF	TXSTA, BRGH	; Set high-speed mode
	;Baud Rate = FOSC/(16(SPBRG+1))
	;SPBRG = (FOSC/16*Baudrate)-1
	;MOVE	SPBRG, 25	; Set 9600 baud for 4 MHz oscillator
	MOVE	SPBRG, 129	; Set 9600 baud for 20 MHz oscillator
	;MOVE	SPBRG, 127	; Set 9600 baud for 19.6608 MHz oscillator
	BCF	TXSTA, SYNC	; Clear SYNC bit

	BANK0
	BSF	RCSTA, SPEN	; Set serial port enable
  
	BANK1
	BCF	TXSTA, TX9	; 8-bit transmissions
	BSF	TXSTA, TXEN	; Enable transmission
	BSF	PIE1, RCIE	; Rx interrupts are desired

	BANK0
	BCF	RCSTA, RX9	; 8-bit receptions
	BSF	RCSTA, CREN	; Enable reception

	;Fill last char TX buffer with 00h as a saftey catch
	MOVE	lasttxch,00h


;==========================================================
;  INIT_I2C - Initializes I2C, module, 100Khz, master mode
;==========================================================

INIT_I2C
	;Pins are set up before this

	; setup MSSP adress register
	BANK1
	MOVE	SSPADD,I2C_ClockValue	; setup clock rate

	; setup MSSP status reg
	MOVE	SSPSTAT,(1<<SMP)	; enable slewrate control

	; setup MSSP control reg
	; enable syncronous port, enable clock, I2C master mode clock = OSC/(4*(SSPADD)+1)
	BANK0
	MOVE	SSPCON,((1<<SSPEN)|(1<<CKP)|(1<<SSPM3))

	; enable MSSP interrupt
	BANK1
;	BSF	PIE1,SSPIE  ; enable MSSP irq


;==========================================================
;  Prepare for Main routine
;==========================================================
	;Enable system interrupts
	BSF	INTCON,GIE	;Set Global Interrupt Enable
	BSF	INTCON,PEIE	;Set Peripheral Interrupt Enable


;==========================================================
;  Main routine
;==========================================================

MAINLOOP

	BTFSS	PROGSTAT,TEMPREQ	;Check if temperature sample has been requested
	GOTO$-1
	BCF	PROGSTAT,TEMPREQ	;Clear out temperature request since it is being done now

;==========================================================
;  Read LM92 Addr:1 via I2C link
;==========================================================

	;START I2C
	BANK1
	BCF	SSPCON2,RCEN	;enable transmission at master (PIC)
	BANK0
	BCF	PIR1,SSPIF	;clear any previous completion flag
	BANK1
	BSF	SSPCON2,SEN	;send i2c START [S] bit
	BANK0
	BTFSS	PIR1,SSPIF	;start bit cycle complete?
	GOTO	$-1
	BCF	PIR1,SSPIF	;clear any previous completion flag

	;Send address to LM92
	MOVE	SSPBUF,10010001b	; LM92 7 bit address = 10010xyz
				; where x=ADDR1, y=ADDR0, z = 1=R 0=W


	;Wait for address to be sent and ACK from slave
	BANK0
	BTFSS	PIR1,SSPIF	;start bit cycle complete?
	GOTO	$-1
	BCF	PIR1,SSPIF	;clear any previous completion flag

	;Enable receive and wait for data
	BANK1
	BSF	SSPCON2,RCEN	;enable receiving at master (PIC)
	BANK0
	BTFSS	PIR1,SSPIF	;sspbuf buffer full byte?
	GOTO	$-1
	BCF	PIR1,SSPIF	;clear any previous completion flag

	;Read MSB from LM92
	BMOVE	0,SSPBUF,2,TEMP1H

	;Send Ack to LM92
	BANK1
	BCF	SSPCON2,ACKDT	;Ack bit state
	BSF	SSPCON2,ACKEN	;Initiate acknowledge sequence
	BANK0
	BTFSS	PIR1,SSPIF	;ACK sequence complete?
	GOTO	$-1
	BCF	PIR1,SSPIF	;clear any previous completion flag

	;Enable receive and wait for data
	BANK1
	BSF	SSPCON2,RCEN	;enable receiving at master (PIC)
	BANK0
	BCF	PIR1,SSPIF	;clear any previous completion flag
	BTFSS	PIR1,SSPIF	;sspbuf buffer full byte?
	GOTO	$-1

	;Read LSB from LM92
	BMOVE	0,SSPBUF,2,TEMP1L

	;Rotate to remove status bits
	BANK2
	BCF	STATUS,C	;Clear carry for high word
	RRF	TEMP1H,F	;LSB moves into Carry
	RRF	TEMP1L,F
	BCF	STATUS,C	;Clear carry for high word
	RRF	TEMP1H,F	;LSB moves into Carry
	RRF	TEMP1L,F
	BCF	STATUS,C	;Clear carry for high word
	RRF	TEMP1H,F	;LSB moves into Carry
	RRF	TEMP1L,F


	;Send NOT Ack to LM92
	BANK1
	BSF	SSPCON2,ACKDT	;NOT Ack bit state
	BSF	SSPCON2,ACKEN	;Initiate acknowledge sequence
	BTFSC	SSPCON2,ACKEN	;Ack complete?
	GOTO	$-1		;  no, keep checking

	;STOP
	BANK0
	BCF	PIR1,SSPIF	;clear any previous completion flag
	BANK1
	BSF	SSPCON2,PEN	;send i2c STOP [P] bit
	BANK0
	BTFSS	PIR1,SSPIF	;stop bit cycle completed?
	GOTO	$-1


;==========================================================
;  Read LM92 Addr:2 via I2C link
;==========================================================

	;START I2C
	BANK1
	BCF	SSPCON2,RCEN	;enable transmission at master (PIC)
	BANK0
	BCF	PIR1,SSPIF	;clear any previous completion flag
	BANK1
	BSF	SSPCON2,SEN	;send i2c START [S] bit
	BANK0
	BTFSS	PIR1,SSPIF	;start bit cycle complete?
	GOTO	$-1
	BCF	PIR1,SSPIF	;clear any previous completion flag

	;Send address to LM92
	MOVE	SSPBUF,10010011b	; LM92 7 bit address = 10010xyz
				; where x=ADDR1, y=ADDR0, z = 1=R 0=W


	;Wait for address to be sent and ACK from slave
	BANK0
	BTFSS	PIR1,SSPIF	;start bit cycle complete?
	GOTO	$-1
	BCF	PIR1,SSPIF	;clear any previous completion flag


	;Enable receive and wait for data
	BANK1
	BSF	SSPCON2,RCEN	;enable receiving at master (PIC)
	BANK0
	BTFSS	PIR1,SSPIF	;sspbuf buffer full byte?
	GOTO	$-1
	BCF	PIR1,SSPIF	;clear any previous completion flag

	;Read MSB from LM92
	BMOVE	0,SSPBUF,2,TEMP2H

	;Send Ack to LM92
	BANK1
	BCF	SSPCON2,ACKDT	;Ack bit state
	BSF	SSPCON2,ACKEN	;Initiate acknowledge sequence
	BANK0
	BTFSS	PIR1,SSPIF	;ACK sequence complete?
	GOTO	$-1
	BCF	PIR1,SSPIF	;clear any previous completion flag

	;Enable receive and wait for data
	BANK1
	BSF	SSPCON2,RCEN	;enable receiving at master (PIC)
	BANK0
	BCF	PIR1,SSPIF	;clear any previous completion flag
	BTFSS	PIR1,SSPIF	;sspbuf buffer full byte?
	GOTO	$-1

	;Read LSB from LM92
	BMOVE	0,SSPBUF,2,TEMP2L

	;Rotate to remove status bits
	BANK2
	BCF	STATUS,C	;Clear carry for high word
	RRF	TEMP2H,F	;LSB moves into Carry
	RRF	TEMP2L,F
	BCF	STATUS,C	;Clear carry for high word
	RRF	TEMP2H,F	;LSB moves into Carry
	RRF	TEMP2L,F
	BCF	STATUS,C	;Clear carry for high word
	RRF	TEMP2H,F	;LSB moves into Carry
	RRF	TEMP2L,F
	
	;Send NOT Ack to LM92
	BANK1
	BSF	SSPCON2,ACKDT	;NOT Ack bit state
	BSF	SSPCON2,ACKEN	;Initiate acknowledge sequence
	BTFSC	SSPCON2,ACKEN	;Ack complete?
	GOTO	$-1		;  no, keep checking

	;STOP
	BANK0
	BCF	PIR1,SSPIF	;clear any previous completion flag
	BANK1
	BSF	SSPCON2,PEN	;send i2c STOP [P] bit
	BANK0
	BTFSS	PIR1,SSPIF	;stop bit cycle completed?
	GOTO	$-1


;==========================================================
	GOTO MAINLOOP		;Perform main loop, intterupts are enabled





;==========================================================
; Subroutines
;==========================================================

;******************************************************************
; Binary to BCD packed and ASCII, 32 bit to 10 digits 
; From http://www.piclist.com/techref/microchip/math/radix/b2bp-32b10d.htm
; from Ron Kreymborg and Mike Keitz 
; [ed: rough guess is that about 2200 instructions will be executed] 

;******************************************************************
; Convert the 10 binary coded digits (5 bytes) starting at 
; <bcd> into an ascii string also starting at <bcd>. Original
; bcd digits are lost.

bcd2a	movlw	bcd+9
	movwf	pto		; destination pointer
	movlw	bcd+4
	movwf	pti		; source pointer
	movlw	5		; 5 bytes to process
	movwf	cnt

bcd2a1	movf	pti,w		; get current input pointer
	movwf	FSR
	decf	pti,f		; prepare for next
	movf	INDF,w		; get 2 bcds
	movwf	temp		; save for later
	movf	pto,w		; get current output pointer
	movwf	FSR
	decf	pto,f		; prepare for next
	decf	pto,f
	movf	temp,w		; get digits back
	andlw	0x0f		; process lsd
	addlw	"0"
	movwf	INDF		; to output
	decf	FSR,F
	swapf	temp,w		; process msd
	andlw	0x0f
	addlw	"0"
	movwf	INDF		; to output
	decfsz	cnt,F		; all digits?
	goto	bcd2a1
	return			; yes


;******************************************************************
; Convert 32-bit binary number at <bin> into a bcd number
; at <bcd>. Uses Mike Keitz's procedure for handling bcd 
; adjust; Modified Microchip AN526 for 32-bits.

b2bcd	movlw	32		; 32-bits
	movwf	ii		; make cycle counter
	clrf	bcd		; clear result area
	clrf	bcd+1
	clrf	bcd+2
	clrf	bcd+3
	clrf	bcd+4
	
b2bcd2	movlw	bcd		; make pointer
	movwf	FSR
	movlw	5
	movwf	cnt

; Mike's routine:

b2bcd3	movlw	0x33		
	addwf	INDF,f		; add to both nybbles
	btfsc	INDF,3		; test if low result > 7
	andlw	0xf0		; low result >7 so take the 3 out
	btfsc	INDF,7		; test if high result > 7
	andlw	0x0f		; high result > 7 so ok
	subwf	INDF,f		; any results <= 7, subtract back
	incf	FSR,f		; point to next
	decfsz	cnt,F
	goto	b2bcd3
	
	rlf	bin+3,f		; get another bit
	rlf	bin+2,f
	rlf	bin+1,f
	rlf	bin+0,f
	rlf	bcd+4,f		; put it into bcd
	rlf	bcd+3,f
	rlf	bcd+2,f
	rlf	bcd+1,f
	rlf	bcd+0,f
	decfsz	ii,f		; all done?
	goto	b2bcd2		; no, loop
	return			; yes

;------------------------------------------------------------
; 24-bit subtraction-with-Borrow
;       SourceH:SoureceM:SourceL = Number to be subtracted
;       DestH:DestM:DestL = Number to be subtracted FROM
;Out    DestH:DestM:DestL = Result = Dest-Source
;       Carry = NOT( Borrow result)
; by David Cary 2001-06-26
; based on code by Rudy Wieser (2000-02-17)
SUBTRACT24
	movfw	SourceL		; Lo byte
	subwf	DestL,f  

	movfw	SourceM		;middle byte
	skpc
	incfsz	SourceM,W
	subwf	DestM,f

	movfw	SourceH		; Hi byte
	skpc
	incfsz	SourceH,W
	subwf	DestH,f		;dest = dest - source, WITH VALID CARRY
				;(although the Z flag is not valid).
	retlw 0

;============================================================
;Strings to be output
STRING0	STRFIX	"Hello World\x0d\x0a\x00"
STRING1	STRFIX	"Help \x0d\x0aUsage \x0d\x0aetc \x0d\x0aetc\x0d\x0a\x00"


  END
