; Simpson-Lawarence 900GD Windlass Display Unit
;	By David V. Fansler
;		181B Bennett Road
;		Arapahoe, NC  28510
;		252-249-1945
;		dfansler@mindspring.com
;
;		Created: Oct 13, 2001
;		Last Updated: April 10, 2002
;
;		This display unit communicates with the windless interface unit
;		which monitors extra circuitry placed in a 900GD windlass, plus
;		the up-down switches to the windlass relay.	The windlass interface
;		and the windlass display communicate via rs-232.  The windlass
;		interface typically outputs the current rode once per second.
;		The windlass display show the current rode on a 4 digit LED
;		display.  The windlass display also has a row of 4 spst momentary
;		contact switches.  These are used to send commands to the windlass
;		interface.  Button one is the HOLD/CONTINUE control that will
;		tell the windlass interface to ignore any motion of the windlass
;		(for such as using the capstain rather than the gypsy).
;		One push of the button issues a hold command - the display shows
;		"hold".  Pushing the button again issues a CONTINUE command to the
;		windlass interface, and the display once again shows the current
;		rode.  The second button issues a RESET command to the windlass
;		interface, setting the rode to 000.0.  The third button increases
;		the brightness of the LED's using the on board PWM.  The fourth
;		button decreases the LED brightness.
;
;		 The output is RS-232 (19.2k-8-n-1).
;
;		The LEDs are updated every 5 mS, for a multiplexing rate of 20 mS.
;		The TMR0 timer is used in internal interrupt mode to generate the
;		5 mS.
;
;		Command Structure
;			Input: $WLxxxxCR  where $WL is the indentifing header,
;						xxxx is length of rode in Hundreds Tens Ones and
;						Tenths of feet (implied decimal) and CR is a
;						terminating carriage return.
;			Output: $WLHOLDCR where $WL is the indentifing header,
;						HOLD is the command to stop monitoring the
;						windlass, and CR is a terminating carriage return.
;				$WLCONTCR where $WL is the indentifing header,
;						CONT is the command to resume monitoring the
;						windlass, and CR is a terminating carriage return.
;				$WLZEROCR where $WL is the indentifing header,
;						ZERO is the command to set the rode length to
;						0000, and CR is a terminating carriage return.
;
;
;		PIC16F873 Device Info
;			Reset starts execution at locaion 0000h
;			Interrupts will start execution at the address location
;				provided at address 0004h.
;			Program memory is:
;					Page 0  0005h - 07ffh
;					Page 1  0800h - 0fffh
;
;			Data Memory is in 4 banks, addressed by RP1:RP0.  Each bank
;				is 128 bytes long with the lower locations of each bank
;				reserved for Special Functionn Registers.
;				Bank 0 00h-1fh SFR, 20h - 7fh GPR
;				Bank 1 80h-9fh SFR, a0h - ffh GPR  Locations f0h-ffh can
;					be addresses at 70h-7fh.
;				Bank 2 100h-17fh SFR, 120h - 17fh GPR  Locations 170h-17fh can
;					be addresses at 70h-7fh.
;				Bank 3 180h-19fh SFR, 1f0h - 1ffh GPR  Locations 1f0h-1ffh can
;					be addresses at 70h-7fh.
;
;	Configuration Word
;		Bit 0 - 0	HS Oscillator
;		Bit 1 - 1	HS Oscillator
;		Bit 2 - 0	WDT disabled
;		Bit 3 - 0	Power-up Timer Enabled
;		Bit 4 - CP0
;		Bit 5 - CP1
;		Bit 6 - 0 	Brown-out Reset diabled
;		Bit 7 - 0	In-circuit Programming disabled
;		Bit 8 - 1 	Data EEPROM code protection off
;		Bit 9 - 1	Can not write to unprotected program memory
;		Bit 10 - 1	Unimplemented
;		Bit 11 - 1	In-circuit debugger disabled
;		Bit 12 - 1 	Code protection off (duplicate in Bit 4)
;		Bit 13 - 1	Code protection off (duplicate in Bit 5)
;
	include 'C:\pictools\16f873.inc'
	FUSES _HS_OSC
	FUSES _WDT_OFF
	FUSES _CP_OFF
;	FUSES _PWRT_OFF
	FUSES _BODEN_OFF
;	FUSES _MCLR_OFF
	FUSES _LVP_OFF

;	DEVICE PIC16F873,HS_OSC, WDT_OFF; PROTECT_OFF,PWRT_ON,BOD_OFF,MCLR_OFF
; ACKDT=5091    ACKEN=4091    ACKSTAT=6091  ADCON0=001F
; ADCON1=009F   ADCS0=601F    ADCS1=701F    ADIE=608C
; ADIF=600C     ADON=001F     ADRES=001E    ADRESH=001E
; BF=0094       BOD_OFF=FFBF  BOD_ON=FFFF   BOR=008E
; BOR_OFF=FFBF  BOR_ON=FFFF   BRGH=2098
; C=0003        CCP1CON=0017  CCP1IE=208C   CCP1IF=200C
; CCP1M0=0017   CCP1M1=1017   CCP1M2=2017   CCP1M3=3017
; CCPR1H=0016   CCPR1L=0015   CCP1X=5017    CCP1Y=4017
; CCP2CON=001D  CCP2IE=008D   CCP2IF=000D   CCP2M0=001D
; CCP2M1=101D   CCP2M2=201D   CCP2M3=301D   CCP2X=501D
; CCP2Y=401D    CCPR2H=001C   CCPR2L=001B   CHS0=301F
; CHS1=401F     CHS2=501F     CKP=4014      CPD_OFF=FFFF
; CPD_ON=FEFF   CREN=4018     CSRC=7098
; DA=5094       DC=1003       DEBUG_OFF=FFFF  DEBUG_ON=F7FF
; EEADR=010D    EEADRH=010F   EECON1=018C   EECON2=018D
; EEDATA=010C   EEDATH=010E   EEPGD=718C    EERD=018C
; EERESL=009E   EEWR=118C
; FERR=2018     FSR=0004
; GCEN=7091     GIE=700B      GO_DONE=201F
; HS_OSC=FFFE
; IBF=7089      IBOV=5089     INDF=0000     INTCON=000B
; INDIRECT=0000 INTEDG=6081   INTE=400B     INTF=100B
; IRP=7003
; LVP_OFF=FF7F  LVP_ON=FFFF   LP_OSC=FFFC
; OBF=6009      OERR=1018     OPTION=0081
; P=4094        PCFG0=009F    PCFG1=109F    PCFG2=209F
; PCL=0002      PCLATH=000A   PCON=008E     PD=3003
; PIE1=008C     PIE2=008D     PEIE=600B     PEN=2091
; PIR1=000C     PIR2=000D     POR=108E      PORTA=0005
; PORTB=0006    PORTC=0007    PORTD=0008    PORTE=0009
; PR2=0092      PROTECT_HALF=DFDF           PROTECT_OFF=FFFF
; PROTECT_ON=CFCF  PROTECT_1_QTR=EFEF       PS0=0081
; PS1=1081      PS2=2081      PSA=3081      PSPIE=708C
; PSPIF=700C    PSPMODE=4089  PWRT_OFF=FFFF PWRT_ON=FFF7
; RA=0005       RB=0006       RBIE=300B     RBIF=000B
; RBPU=7081     RC=0007       RC89=6018     RCD8=0018
; RCEN=3091     RCIE=508C     RCIF=500C     RCSTA=0018
; RCREG=001A    RC_OSC=FFFF   RD=0008       RE=0009
; RP0=5003      RP1=6003      RSEN=1091     RW=2094
; S=3094        SEN=0091      SPBRG=0099    SPEN=7018
; SREN=5018     SSPADD=0093   SSPBUF=0013   SSPCON=0014
; SSPCON2=0091  SSPEN=5014    SSPIE=308C    SSPIF=300C
; SSPM0=0014    SSPM1=1014    SSPM2=2014    SSPM3=3014
; SSPOV=6014    SSPSTAT=0094  STATUS=0003   SYNC=4098
; T0CS=5081     T0SE=4081     T0IE=500B     T0IF=200B
; T1CKPS0=4010  T1CKPS1=5010  T1CON=0010    T1OSCEN=3010
; T1SYNC=2010   T2CKPS0=0012  T2CKPS1=1012  T2CON=0012
; TMR0=0001     TMR1CS=1010   TMR1IE=008C   TMR1IF=000C
; TMR1H=000F    TMR1L=000E    TMR1ON=0010   TMR2=0011
; TMR2IE=108C   TMR2IF=100C   TMR2ON=2012   TO=4003
; TOUTPS0=3012  TOUTPS1=4012  TOUTPS2=5012  TOUTPS3=6012
; TRISA=0085    TRISB=0086    TRISC=0087    TRISD=0088
; TRISE=0089    TRISE0=0089   TRISE1=1089   TRISE2=2089
; TRMT=1098     TX89=6098     TXD8=0098     TXEN=5098
; TXIE=408C     TXIF=400C     TXREG=0019    TXSTA=0098
; WCOL=7014     WDT_ON=FFFF   WDT_OFF=FFFB  WRERR=318C
; WREN=218C     WRTEN_OFF=FDFF  WRTEN_ON=FFFF
; XT_OSC=FFFD   xUA=1094
; Z=2003
;
;PORT A
;	0 - .1's Digit Common
;	1 - 1's Digit Common
;	2 - 10's Digit Common
;	3 - 100's Digit Common
;
;PORT B
;	0 - LED a Segment              a
;	1 - LED b Segment            ------
;	2 - LED c Segment          f |     |b
;	3 - LED d Segment            |__g__|
;	4 - LED e Segment            |     |
;	5 - LED f Segment          e |     |c
;	6 - LED g Segment        dp   -----
;	7 - LED decimal point           d
;
;PORT C
;	0 - Hold/Contine
;	1 - Reset to 0
;	2 - PWM output
;	3 - test output bit
;	4 - increase LED brightness
;	5 - decrease LED Brightness
;	6 - USART Transmit
;	7 - USART Receive


PA_TEMP equ 6fh			;temp register to read porta
W_TEMP equ	070h		;temp register for interrupts
STATUS_TEMP equ 071h		;temp register for interrupts
PCLATH_TEMP equ 072h		;temp register for interrupts
Flags equ 073h			;flag register
Tmr5ms equ 0			;bit 0 5 ms timer flag
DebounceOn equ 1		;bit 1 Debounce Flag
ServiceKey equ 2		;bit 2 ServiceKey
KeyHit equ 3			;bit 3 Key Hit
NoEntry equ 4			;bit 4 No Entry
Hold_Cont equ 5			;bit 5 Hold/Continue (1 Hold, 0 Continue)
				;bit 6
				;bit 7
DISPLAY_HIGH EQU 074H		;display buffer high byte
DISPLAY_LOW EQU 075H		;display buffer low byte
TEMP_A equ 076h			;temporary storage location
DebounceCtr equ	077h		;counter for debounce
TEMP_B	equ 078h		;temporary register
PWM_CUR equ	079h		;current pwm value
CHAR_OUT_PTR equ 07ah		;pointer to character # to output via rs-232
Five_mS_Cont equ 61		;tmr0 constant to load for 5mS
BUFFER_OUT equ	20h		;start of rs-232 output buffer (bank 0)
BUFFER_PTR equ 30h		;pointer to rs-232 input buffer (bank 0)
BUFFER_IN equ 31h		;start of rs-232 input buffer   (bank 0)
BAUD_CONST equ 64		;constant for baud (19.2k high speed)
CR equ 0dh			;constant for carriage return
EEIF equ 400Dh			;define EE interrupt flag
BCLIF equ 300dh			;define Bus Collision int flag

	org 0000
	goto START			;jump to start routine

	org 0004
INT_SRV
	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 0 temp register
	movf pclath,w			;only required if usings pages 1,2 and/or 3
	movwf PCLATH_TEMP		;save pclath into w
	clrf	pclath			;page 0 regardless of current page
		;first check to see who caused the interrupt
	btfsc t0if			;was it timer 0?
	goto ServiceTMR0		;if so then jump
	movf CHAR_OUT_PTR,W		;move character pointer to W
	btfsc Z				;is it 0? if not then jump
	goto INT_SRV_1			;else jump
	btfsc TXIF			;was it TX clear to send?
	goto ServiceTX			;if so then jump
INT_SRV_1
	btfsc RCIF			;was it RX input received?
	goto ServiceRX			;if so then jump
	bcf intf			;clear RB0/INT flag
	bcf rbif			;clear RB Port change flag
	bcf pspif			;clear parallel slave port int flag
	bcf adif			;clear a/d int flag
	bcf sspif			;synchronous int flag
	bcf ccp1IF			;clear ccp1 int flag
	bcf tmr2if			;clear tmr2 int flag
	bcf tmr1if			;clear tmr1 int flag
	bcf bclif			;clear bus collision int flag
	bcf ccp2if			;clear ccp2 int flag
	bsf t0ie			;re-enable timer 0
	;
INT_SRV_EXIT
	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			;movew into status register
	swapf W_TEMP,F			;swap w_temp
	swapf W_TEMP,W			;swap w_temp into W
	retfie				;and return from interrupt

START
	call INIT_PORTS			;call to setup the ports
	call INIT_IRQ			;call to setup the interrupts

MAIN
	bcf RP0				;set to
	bcf RP1				;bank 0
	movlw 0				;set display to 0
	movwf DISPLAY_LOW
	movwf DISPLAY_HIGH

MAIN_1
	goto MAIN_1			;and just loop



INIT_PORTS
	;set Port A to digital outputs, Port B to outputs
	;set Port C to inputs (bits 0,1,4,5 key entry), USART (bits 6,7)
	bcf rp0				;point to
	bcf rp1				;bank 0
	movlw 0				;load 00 into W
	movwf Flags			;clear Flags
	movwf SSPCON			;clear SSPCON to disable SYNC Port
	movwf T1CON			;clear Timer 1 to disable
	movlw 1				;set rs-232 receive buffer
	movwf BUFFER_PTR		;pointer to 1st character
	clrf PORTA			;intitialize port a by clearing (bank 0:05)
					;data latches
	clrf CCP1CON			;ccp module is off (bank0:17
	clrf TMR2			;clear timer 2 (bank0:11)
	movlw 75			;set duty cycle to mid brightness
	movwf CCPR1L			;(bank0:15)
	movlw 1				;set PWM value
	movwf PWM_CUR			;and store
	bsf RP0				;select bank 1
	movlw 7fh			;load Period Timer 2 register
	movwf PR2			;(bank1:92h)
	movlw 07h			;configure all pins
	movwf ADCON1			;as digital (not analog)(bank1:9f)
	movlw 00h			;value used to initialize data direction
	movwf TRISA			;set all pins to outputs(bank1:85)
	movlw 00h			;value used to initialize data direction
	movwf TRISB			;set all pins to outputs (bank1:86)
	movlw 10110011b			;value used to initialize data direction
	movwf TRISC			;set pin 2 (pwm)& 6 (tx) as out, all other in (bank1:87)
	movlw 04h			;set 8-bit transmit, should be for using BRGH
;	movlw 00h			;set 8-bit transmit,
	movwf TXSTA			;asynchronous mode, high speed (bank1:98)
	movwf SSPCON2			;disable sync port
	movlw BAUD_CONST		;get the baud rate
	movwf SPBRG			;and set (bank1:99 )
	bsf TXEN			;enable transmissions
	bsf RCIE			;enable receive interrupts (bank1:8C  PIE1.5)
	bcf RP0				;point to bank 0
	bsf SPEN			;enable serial port (bank 0:18 RCSTA.7)
	bsf CREN			;8-bit receive, receiver enabled (bank0:18 RCSTA.4)
	movlw 2ch			;enable ccp1con
	movwf CCP1CON			;(bank0:17)
	bsf T2CON, 2			;turn on timer 2
	movlw 0				;set character pointer to 0
	movwf CHAR_OUT_PTR		;
	return				;return to caller

INIT_IRQ
	;setup timer 0 for a 5 ms interrupt.  Using a 20MHz oscillator
	;and a prescaler of 128, the timer should be pre loaded with a
	;value of 61.  This is calculated by 20MHz/4 = 5MHz.
	;5 MHz/128 prescaler = 25.6uS.  5ms/25.6uS = 195.  Finally
	;(256-61)*25.6us = 5ms.
	bsf rp0				;point to
	bcf rp1				;bank 1
	movlw	10000110B		;disable PB PU, Prescaler to Timer 0, 1:128
	movwf option			;and set in option register
	bcf rp0				;select bank 0
	movlw 01100000B			;enable tmr0 & Peripheral int
	movwf intcon			;and place in register
	movlw Five_mS_Cont		;preset value for timer 0
	movwf tmr0			;store
	retfie				;return to caller while enabling interrupts


ServiceTMR0
	movlw Five_mS_Cont		;get delay value for 5 ms
	movwf tmr0			;and load
	bcf t0if			;clear tmr0 interrupt flag
	bsf flags,0			;set 5 ms flag
	movf PORTA,W 			;read current digit select into W
	clrf PORTA 			;set to no digit selected
	andlw 0fh			;mask off high nibble
	movwf TEMP_A 			;save current digit select into Temp A
	rrf TEMP_A, 1 			;rotate right, and check for bit 0 -> C
	btfsc C		 		;by c=1?
	goto DISPLAY_1:10		;if set then jump to display .1's digit
	rrf TEMP_A, 1 			;rotate right, and check for bit 0 -> C
	btfsc C		 		;by c=1?
	goto DISPLAY_100		;if set then jump to display 100's digit
	rrf TEMP_A, 1 			;rotate right, and check for bit 0 -> C
	btfsc C		 		;by c=1?
	goto DISPLAY_10			;if set then jump to display 10's digit
	rrf TEMP_A, 1 			;rotate right, and check for bit 0 -> C
	btfsc C		 		;by c=1?
	goto DISPLAY_1		   	;if set then jump to display 1's digit
DISPLAY_1:10				;else display 1/10 digit by default
	movf DISPLAY_LOW, 0		;move 1 & 1/10 digit to W
	andlw 0fh			;mask off high nibble
	sublw 0dh			;is it the 'd' from 'hold'
	btfss Z				;if so skip next instruction
	goto DISPLAY_DP			;else add in the decimal point
	movf DISPLAY_LOW, 0		;move 1 & 1/10 digit to W
	andlw 0fh			;mask off high nibble
	call LedTable 			;get digit output
	movwf PORTB 			;drive leds
	movlw 8 			;set sink value in w
	movwf PORTA			;and activate display
	goto INT_SRV_EXIT		;goto exit ISR
DISPLAY_DP				;add in the decimal point
	movf DISPLAY_LOW, 0		;move 1 & 1/10 digit to W
	andlw 0fh			;mask off high nibble
	call LedTable 			;get digit output
	iorlw 10000000b			;OR the dp into the display
	movwf PORTB 			;drive leds
	movlw 8 			;set sink value in w
	movwf PORTA			;and activate display
	goto INT_SRV_EXIT		;goto exit ISR
DISPLAY_1				;display 1 digit
	swapf DISPLAY_LOW, 0		;swap 1 & 1/10 digit and move to W
	andlw 0fh			;mask off high nibble
	call LedTable 			;get digit output
	movwf PORTB 			;drive leds
	movlw 4 			;set sink value in w
	movwf PORTA			;and activate display
	goto INT_SRV_EXIT		;goto exit ISR
DISPLAY_10				;display 10 digit
	movf DISPLAY_HIGH, 0		;get 10 & 100 digit and move to W
	andlw 0fh			;mask off high nibble
	call LedTable 			;get digit output
	movwf PORTB 			;drive leds
	movlw 2 			;set sink value in w
	movwf PORTA			;and activate display
	goto INT_SRV_EXIT		;goto exit ISR
DISPLAY_100				;display 100 digit
	swapf DISPLAY_HIGH, 0		;swap 10 & 100 digit and move to W
	andlw 0fh			;mask off high nibble
	call LedTable 			;get digit output
	movwf PORTB 			;drive leds
	movlw 1 			;set sink value in w
	movwf PORTA			;and activate display
	goto SCANKEYS			;jump over LED Table

LedTable
	addwf PCL, F 			;add to PC low and save in PCL
	retlw 00111111b 		;led drive for 0       bit 7 6543210
	retlw 00000110b 		;led drive for 1 segement dp gfedcba
	retlw 01011011b 		;led drive for 2		a
	retlw 01001111b 		;led drive for 3      -----
	retlw 01100110b 		;led drive for 4    f|     |b
	retlw 01101101b 		;led drive for 5     |__g__|
	retlw 01111101b 		;led drive for 6     |     |
	retlw 00000111b 		;led drive for 7    e|     |c
	retlw 01111111b 		;led drive for 8      -----
	retlw 01100111b 		;led drive for 9  dp    d
	retlw 01110100b			;led drive for h
	retlw 01011100b			;led drive for o
	retlw 00000110b			;led drive for l
	retlw 01011110b			;led drive for d
	retlw 00000000b 		;blank led drive
LedIntensity
	addwf PCL, F 			;add to PC low and save in PCL
	retlw 10			;Minimum LED Intensity
	retlw 35
	retlw 255


	org 256
SCANKEYS
	btfss Flags, DebounceOn		;is the debounce on?
	goto SCAN_1			;if not the jump
	decfsz DebounceCtr		;else dec debounce counter
	goto INT_SRV_EXIT		;goto exit ISR
	bcf FLAGS, DebounceOn		;clear debounce flag
	goto INT_SRV_EXIT		;goto exit ISR
SCAN_1
	movf PORTC, 0			;read port C into W
	movwf TEMP_B			;and into TEMP_B
	andlw 00110011b			;mask off key bits
	xorlw 00110011b			;any bits low?
	btfsc Z				;if key pressed then skip
	goto SCAN_2			;else jump
	btfsc Flags, KeyHit		;is key hit flag set? Skip if not
	goto INT_SRV_EXIT		;else if set then goto exit ISR
	bsf Flags, KeyHit		;not set so set now
	btfss TEMP_B,0			;if Hold/Cont not set then jump
	goto SCAN_H:C			;else jump
	btfss TEMP_B,1			;if Zero not set then jump
	goto SCAN_ZERO			;else jump
	btfss TEMP_B,4			;if Brighten not set then jump
	goto SCAN_BRIGHT		;else jump
	btfss TEMP_B,5			;if Dim not set then jump
	goto SCAN_DIM			;else jump
	goto INT_SRV_EXIT		;goto exit ISR
SCAN_2
	bcf Flags, KeyHit		;clear key hit flag
	goto INT_SRV_EXIT		;goto exit ISR
SCAN_H:C
	btfss Flags, Hold_Cont		;are we in cont (0), or hold (1)
	goto SCAN_HOLD			;if 0 then change state to hold
SCAN_CONT
	bcf Flags,Hold_Cont		;set the Hold_Cont flag to Cont
	movlw 'C'			;load rs-232 buffer out
	movwf BUFFER_OUT		;with CONT
	movlw 'O'			;
	movwf BUFFER_OUT+1		;
	movlw 'N'			;
	movwf BUFFER_OUT+2		;
	movlw 'T'			;
	movwf BUFFER_OUT+3		;
	goto RS232_OUT			;and jump to start rs232 out
SCAN_HOLD
	bsf Flags,Hold_Cont		;set the Hold_Cont flag to Hold
	movlw 'H'			;load rs-232 buffer out
	movwf BUFFER_OUT		;with H O L D
	movlw 'O'			;
	movwf BUFFER_OUT+1		;
	movlw 'L'			;
	movwf BUFFER_OUT+2		;
	movlw 'D'			;
	movwf BUFFER_OUT+3		;
	goto RS232_OUT			;and jump to start rs232 out

SCAN_ZERO
	bcf Flags,Hold_Cont		;set the Hold_Cont flag to Continue
	movlw 'Z'			;load rs-232 buffer out
	movwf BUFFER_OUT		;with CONT
	movlw 'E'			;
	movwf BUFFER_OUT+1		;
	movlw 'R'			;
	movwf BUFFER_OUT+2		;
	movlw 'O'			;
	movwf BUFFER_OUT+3		;

RS232_OUT
	movlw 2				;set character pointer out to 2
	movwf CHAR_OUT_PTR		;
	bsf RP0				;bank 1
	bsf TXIE			;enable tx interrupts (bank1:8C  PIE1.4)
	bcf RP0				;bank 0
	movlw '$'			;load the $ into the transmit register
	movwf TXREG			;and send
	goto INT_SRV_EXIT		;goto exit ISR
SCAN_BRIGHT
	movf PWM_CUR,0			;get current PWM value into W
	xorlw 2				;is it already max value
	btfsc Z				;if so then skip next
	goto INT_SRV_EXIT		;if so then goto exit ISR
	incf PWM_CUR			;increment intensity counter
	movfw PWM_CUR			;mov value into W
	call LEDIntensity		;get new intensity
	bcf rp0				;point to
	bcf rp1				;bank 0
	movwf ccpr1l			;
	goto INT_SRV_EXIT		;if so then goto exit ISR

SCAN_DIM
	movf PWM_CUR,0			;get current PWM value into W
	xorlw 0				;is it already mim value
	btfsc Z				;if so then skip next
	goto INT_SRV_EXIT		;if so then goto exit ISR
	decf PWM_CUR			;increment intensity counter
	movfw PWM_CUR			;mov value into W
	call LEDIntensity		;get new intensity
	bcf rp0				;point to
	bcf rp1				;bank 0
	movwf ccpr1l			;
	goto INT_SRV_EXIT		;if so then goto exit ISR


ServiceTX
	;check bit position of CHAR_OUT_PTR as to which character to output
	;bit 1 is $, bit 2 is W, bit 3 is L, bit 4 -7 are commands (CONT, HOLD,
	;ZERO, bit 8 is CR
	btfsc CHAR_OUT_PTR,1		;check for bit 2 set
	goto TX_2			;else jump
	btfsc CHAR_OUT_PTR,2		;check for bit 3 set
	goto TX_3			;else jump
	btfsc CHAR_OUT_PTR,3		;check for bit 4 set
	goto TX_4			;else jump
	btfsc CHAR_OUT_PTR,4		;check for bit 5 set
	goto TX_5			;else jump
	btfsc CHAR_OUT_PTR,5		;check for bit 6 set
	goto TX_6			;else jump
	btfsc CHAR_OUT_PTR,6		;check for bit 7 set
	goto TX_7			;else jump
TX_8
	bsf rp0				;point to bank 1
	bcf TXIE			;disable TX interrupts
	bcf RP0				;point to bank 0
	movlw 0				;set character pointer to 0
	movwf CHAR_OUT_PTR		;
	movlw CR			;load W with a carriage return
	movwf TXREG			;and place in tx data register
	goto INT_SRV_EXIT		;goto exit ISR
TX_2
	movlw 'W'			;load ASCII 'W'
	movwf TXREG			;and place in tx data register
	bcf C				;clear the carry bit
	rlf CHAR_OUT_PTR		;move pointer
	goto INT_SRV_EXIT		;goto exit ISR
TX_3
	movlw 'L'			;load ASCII 'L'
	movwf TXREG			;and place in tx data register
	bcf C				;clear the carry bit
	rlf CHAR_OUT_PTR		;move pointer
	goto INT_SRV_EXIT		;goto exit ISR
TX_4
	movf BUFFER_OUT,0		;get first data character to output
	movwf TXREG			;and place in tx register
	bcf C				;clear the carry bit
	rlf CHAR_OUT_PTR		;move pointer
	goto INT_SRV_EXIT		;goto exit ISR
TX_5
	movf BUFFER_OUT+1,0		;get second data character to output
	movwf TXREG			;and place in tx register
	bcf C				;clear the carry bit
	rlf CHAR_OUT_PTR		;move pointer
	goto INT_SRV_EXIT		;goto exit ISR
TX_6
	movf BUFFER_OUT+2,0		;get third data character to output
	movwf TXREG			;and place in tx register
	bcf C				;clear the carry bit
	rlf CHAR_OUT_PTR		;move pointer
	goto INT_SRV_EXIT		;goto exit ISR
TX_7
	movf BUFFER_OUT+3,0		;get forth data character to output
	movwf TXREG			;and place in tx register
	bcf C				;clear the carry bit
	rlf CHAR_OUT_PTR		;move pointer
	goto INT_SRV_EXIT		;goto exit ISR

ServiceRX
	;check bit position of BUFFER_PTR as to where to place
	;character in buffer
	;bit 1 is $, bit 2 is W, bit 3 is L, bit 4 is 1st char of command
	;bit 5 is 2nd char of cmd, bit 6 is 3rd char of cmd
	;bit 7 is 4th char of cmd, bit 8 is CR

	btfsc BUFFER_PTR,0		;check for bit 1 set
	goto RX_1			;else jump
	btfsc BUFFER_PTR,1		;check for bit 2 set
	goto RX_2			;else jump
	btfsc BUFFER_PTR,2		;check for bit 3 set
	goto RX_3			;else jump
	btfsc BUFFER_PTR,3		;check for bit 4 set
	goto RX_4			;else jump
	btfsc BUFFER_PTR,4		;check for bit 5 set
	goto RX_5			;else jump
	btfsc BUFFER_PTR,5		;check for bit 6 set
	goto RX_6			;else jump
	btfsc BUFFER_PTR,6		;check for bit 7 set
	goto RX_7			;else jump
	goto RX_8			;else goto RX_8
RX_1
	movf RCREG,0			;get received data into W
	movwf BUFFER_IN			;and store data in buffer
	xorlw '$'			;is it a dollar sign?
	btfss Z				;if so then skip next step
	goto INT_SRV_EXIT		;goto exit ISR
	bcf C				;clear the carry bit
	rlf BUFFER_PTR			;else it is a $, so move pointer
	goto INT_SRV_EXIT		;goto exit ISR
RX_2
	movf RCREG,0			;get received data into W
	movwf BUFFER_IN+1		;and store data in buffer
	xorlw 'W'			;is it a W?
	btfss Z				;if so then skip next step
	goto RX_RESET			;goto reset RX due to wrong character
	bcf C				;clear the carry bit
	rlf BUFFER_PTR			;move pointer
	goto INT_SRV_EXIT		;goto exit ISR
RX_3
	movf RCREG,0			;get received data into W
	movwf BUFFER_IN+2		;and store data in buffer
	xorlw 'L'			;is it a L?
	btfss Z				;if so then skip next step
	goto RX_RESET			;goto reset RX due to wrong character
	bcf C				;clear the carry bit
	rlf BUFFER_PTR			;move pointer
	goto INT_SRV_EXIT		;goto exit ISR
RX_4
	movf RCREG,0			;get received data into W
	movwf BUFFER_IN+3		;and store data in buffer
	bcf C				;clear the carry bit
	rlf BUFFER_PTR			;move pointer
	goto INT_SRV_EXIT		;goto exit ISR
RX_5
	movf RCREG,0			;get received data into W
	movwf BUFFER_IN+4		;and store data in buffer
	bcf C				;clear the carry bit
	rlf BUFFER_PTR			;move pointer
	goto INT_SRV_EXIT		;goto exit ISR
RX_6
	movf RCREG,0			;get received data into W
	movwf BUFFER_IN+5		;and store data in buffer
	bcf C				;clear the carry bit
	rlf BUFFER_PTR			;move pointer
	goto INT_SRV_EXIT		;goto exit ISR
RX_7
	movf RCREG,0			;get received data into W
	movwf BUFFER_IN+6		;and store data in buffer
	bcf C				;clear the carry bit
	rlf BUFFER_PTR			;move pointer
	goto INT_SRV_EXIT		;goto exit ISR
RX_8
	movf RCREG,0			;get received data into W
	movwf BUFFER_IN+7		;and store data in buffer
	bcf C				;clear the carry bit
	rlf BUFFER_PTR			;move pointer

	;now check for which command has been sent
RC_CHECK
	movf BUFFER_IN+3,0		;get first command character
	xorlw 'H'			;is it an H?
	btfss Z				;if so then skip next step
	goto RC_CHECK_1			;not H so jump
	goto RC_HOLD			;is H so jump to check for HOLD
RC_CHECK_1
	movf BUFFER_IN+3,0		;get first data character
	andlw 0f0h			;mask off the low nibble
	sublw 030h			;is it 30h?
	btfss Z				;if so then skip next step
	goto RX_RESET			;if not 30h then jump
	movf BUFFER_IN+3,0		;get first data character
	andlw 0fh			;mask off the high nibble
	sublw 9				;subtract 9 from it
	btfss C				;check for borrow
	goto RX_RESET			;not 0-9 so jump to reset
RC_CHECK_2
	movf BUFFER_IN+4,0		;get second data character
	andlw 0f0h			;mask off the low nibble
	sublw 030h			;is it 30h?
	btfss Z				;if so then skip next step
	goto RX_RESET			;if not 30h then jump
	movf BUFFER_IN+4,0		;get second data character
	andlw 0fh			;mask off the high nibble
	sublw 9				;subtract 9 from it
	btfss C				;check for borrow
	goto RX_RESET			;not 0-9 so jump to reset
RC_CHECK_3
	movf BUFFER_IN+5,0		;get third data character
	andlw 0f0h			;mask off the low nibble
	sublw 030h			;is it 30h?
	btfss Z				;if so then skip next step
	goto RX_RESET			;if not 30h then jump
	movf BUFFER_IN+5,0		;get third data character
	andlw 0fh			;mask off the high nibble
	sublw 9				;subtract 9 from it
	btfss C				;check for borrow
	goto RX_RESET			;not 0-9 so jump to reset
RC_CHECK_4
	movf BUFFER_IN+6,0		;get forth data character
	andlw 0f0h			;mask off the low nibble
	sublw 030h			;is it 30h?
	btfss Z				;if so then skip next step
	goto RX_RESET			;if not 30h then jump
	movf BUFFER_IN+6,0		;get forth data character
	andlw 0fh			;mask off the high nibble
	sublw 9				;subtract 9 from it
	btfss C				;check for borrow
	goto RX_RESET			;not 0-9 so jump to reset
	movf BUFFER_IN+7,0		;get second command character
	xorlw CR			;is it an carriage return?
	btfss Z				;if so then skip next step
	goto RX_RESET			;else jump to reset buffer pointer
		;move Buffer 3-6 into display buffer
	swapf BUFFER_IN+3,0		;move low nibble into high nibble of W
	andlw 0f0h			;set low nibble to 0000
	movwf DISPLAY_HIGH		;and move into display storage
	movf BUFFER_IN+4,0		;move the 10's value into W
	andlw 0fh			;zero out the high nibble
	iorwf DISPLAY_HIGH,1		;or 100's high nibble with 10's low nibble
	swapf BUFFER_IN+5,0		;move low nibble into high nibble of W
	andlw 0f0h			;set low nibble to 0000
	movwf DISPLAY_LOW		;and move into display storage
	movf BUFFER_IN+6,0		;move the 1/10's value into W
	andlw 0fh			;zero out the high nibble
	iorwf DISPLAY_LOW,1		;or 1's high nibble with 1/10's low nibble
	goto RX_RESET			;and reset the rc buffer


RC_HOLD
	movf BUFFER_IN+4,0		;get second command character
	xorlw 'O'			;is it an O?
	btfss Z				;if so then skip next step
	goto RX_RESET			;else jump to reset buffer pointer
	movf BUFFER_IN+5,0		;get second command character
	xorlw 'L'			;is it an L?
	btfss Z				;if so then skip next step
	goto RX_RESET			;else jump to reset buffer pointer
	movf BUFFER_IN+6,0		;get second command character
	xorlw 'D'			;is it an D?
	btfss Z				;if so then skip next step
	goto RX_RESET			;else jump to reset buffer pointer
	movf BUFFER_IN+7,0		;get second command character
	xorlw CR			;is it an carriage return?
	btfss Z				;if so then skip next step
	goto RX_RESET			;else jump to reset buffer pointer
	movlw 0abh			;set high display buffer to point to 'ho'
	movwf DISPLAY_HIGH		;and store
	movlw 0cdh			;set low display buffer to point to 'ld'
	movwf DISPLAY_LOW		;and store
	goto RX_RESET			;and jump
RX_RESET
	movlw 1				;set rs-232 receive buffer
	movwf BUFFER_PTR		;pointer to 1st character
	goto INT_SRV_EXIT		;goto exit ISR




end

