; DMX Receiver with multiple phase controlled dimmer outputs
;	By David V. Fansler
;		2813 Gloucester Drive
;		Wilson, NC  27893
;		dfansler@dv-fansler.com
;
;		Created: January 30, 2007
;		Last Updated: March 16, 2007
;
;		This program is designed to receive DMX signals at 250kbs.  The code shall
;		count the number of DMX frames, until the frame number matches the base
;		address of the DMX unit.  It will then store as many of the subsequent
;		DMX frames as there are dimmers in the unit.  Selection of the unit's
;		DMX base address will be by attaching an outboard switch box.  The switch
;		box should be set for the unit's base address and how many concurrent address'
;		the unit will use.  When first powered up, the code will check for the presence
;		of the switch box.  If present, there are two possible actions - if A.1 is high then
;		the data will be read from the switches and stored in EEROM.  LEDs on the switch box
;		will then indicate the data written to the EEROM (as read from the EEROM).  If A.1
;		low, then the data will be read from the EEROM and displayed on the switch box.
;		If not present when the code starts, it will start looking for valid DMX packets.
;
;		This initial version will make no attemp to linearize output waveforms.
;
;		A TMR0 32.5us interrupt will update a counter.  If the counter value is equal to or
;		greater than the current DMX data for that channel, then the output will be taken
;		for the remainder of the half 60Hz wave cycle.
;
;
;		PIC16F877 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
;					Page 2  1000h - 17ffh
;					Page 3  1800h - 1fffh
;
;			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\16f877.inc'
	FUSES _HS_OSC
	FUSES _WDT_OFF
	FUSES _CP_OFF
;	FUSES _PWRT_OFF
	FUSES _BODEN_OFF
;	FUSES _MCLR_OFF
	FUSES _LVP_OFF
;=================================   	;=======================================
;  Main File Register Definitions	;  STATUS Register BIT Definitions
;=================================	;=======================================
;	INDF  EQU   0000h		IRP     EQU STATUS.7
;	INDIRECT   EQU 0000h		RP1     EQU STATUS.6
;	TMR0       EQU 0001h		RP0     EQU STATUS.5
;	PCL        EQU 0002h		NOT_TO  EQU STATUS.4
;	STATUS     EQU 0003h		NOT_PD  EQU STATUS.3
;	FSR        EQU 0004h		Z       EQU STATUS.2
;	PORTA      EQU 0005h		DC      EQU STATUS.1
;	RA         EQU 0005h		C       EQU STATUS.0
;	PORTB      EQU 0006h
;	RB         EQU 0006h		;=======================================
;	PORTC      EQU 0007h		;  INTCON Register BIT Definitions
;	RC         EQU 0007h 		;=======================================
;	PORTD      EQU 0008h		GIE     EQU INTCON.7
;	RD         EQU 0008h		PEIE    EQU INTCON.6
;	PORTE      EQU 0009h		T0IE    EQU INTCON.5
;	RE         EQU 0009h		INTE    EQU INTCON.4
;	PCLATH     EQU 000Ah		RBIE    EQU INTCON.3
;	INTCON     EQU 000Bh		T0IF    EQU INTCON.2
;	PIR1       EQU 000Ch		INTF    EQU INTCON.1
;	PIR2       EQU 000Dh		RBIF    EQU INTCON.0
;	TMR1L      EQU 000Eh
;	TMR1H      EQU 000Fh		;=======================================
;	T1CON      EQU 0010h		;  PIR1 Register BIT Definitions
;	TMR2       EQU 0011h		;=======================================
;	T2CON      EQU 0012h		PSPIF   EQU PIR1.7
;	SSPBUF     EQU 0013h		ADIF    EQU PIR1.6
;	SSPCON     EQU 0014h		RCIF    EQU PIR1.5
;	CCPR1L     EQU 0015h		TXIF    EQU PIR1.4
;	CCPR1H     EQU 0016h		SSPIF   EQU PIR1.3
;	CCP1CON    EQU 0017h		CCP1IF  EQU PIR1.2
;	RCSTA      EQU 0018h		TMR2IF  EQU PIR1.1
;	TXREG      EQU 0019h		TMR1IF  EQU PIR1.0
;	CCPR2L     EQU 001Bh
;	CCPR2H     EQU 001Ch		;=======================================
;	CCP2CON    EQU 001Dh		;  PIR2 Register BIT Definitions
;	ADRESH     EQU 001Eh		;=======================================
;	ADCON0     EQU 001Fh		EEIF    EQU PIR2.4
;	OPTION_REG EQU 0081h		BCLIF   EQU PIR2.3
;	OPTION     EQU 0081h		CCP2IF  EQU PIR2.0
;	TRISA      EQU 0085h
;	TRISB      EQU 0086h		;=======================================
;	TRISC      EQU 0087h		;  T1CON Register BIT Definitions
;	TRISD      EQU 0088h		;=======================================
;	TRISE      EQU 0089h		T1CKPS1    EQU T1CON.5
;	PIE1       EQU 008Ch		T1CKPS0    EQU T1CON.4
;	PIE2       EQU 008Dh		T1OSCEN    EQU T1CON.3
;	PCON       EQU 008Eh		NOT_T1SYNC EQU T1CON.2
;	SSPCON2    EQU 0091h		T1INSYNC   EQU T1CON.2
;	PR2        EQU 0092h		T1SYNC     EQU T1CON.2
;	SSPADD     EQU 0093h		TMR1CS     EQU T1CON.1
;	SSPSTAT    EQU 0094h		TMR1ON     EQU T1CON.0
;	TXSTA      EQU 0098h
;	SPBRG      EQU 0099h
;	ADRESL     EQU 009Eh		;=======================================
;	ADCON1     EQU 009Fh		;  T2CON Register BIT Definitions
;	EEDATA     EQU 010Ch		;=======================================
;	EEADR      EQU 010Dh		TOUTPS3    EQU T2CON.6
;	EEDATH     EQU 010Eh		TOUTPS2    EQU T2CON.5
;	EEADRH     EQU 010Fh		TOUTPS1    EQU T2CON.4
;	EECON1     EQU 018Ch		TOUTPS0    EQU T2CON.3
;	EECON2     EQU 018Dh		TMR2ON     EQU T2CON.2
;					T2CKPS1    EQU T2CON.1
;					T2CKPS0    EQU T2CON.0
;
;===================================	;=======================================
;  SSPCON Register BIT Definitions	;  CCP1CON Register BIT Definitions
;===================================	;=======================================
;	WCOL   EQU SSPCON.7		CCP1X      EQU  CP1CON.5
;	SSPOV  EQU SSPCON.6		CCP1Y      EQU  CCP1CON.4
;	SSPEN  EQU SSPCON.5		CCP1M3     EQU  CCP1CON.3
;	CKP    EQU SSPCON.4		CCP1M2     EQU  CCP1CON.2
;	SSPM3  EQU SSPCON.3		CCP1M1     EQU  CCP1CON.1
;	SSPM2  EQU SSPCON.2		CCP1M0     EQU  CP1CON.0
;	SSPM1  EQU SSPCON.1
;	SSPM0  EQU SSPCON.0
;
;=================================	;=======================================
;  RCSTA Register BIT Definitions	;  CCP2CON Register BIT Definitions
;=================================	;=======================================
;	SPEN    EQU   RCSTA.7		CCP2X                EQU        CCP2CON.5
;	RX9     EQU   RCSTA.6		CCP2Y                EQU        CCP2CON.4
;	RC9     EQU   RCSTA.6		CCP2M3               EQU        CCP2CON.3
;	NOT_RC8 EQU   RCSTA.6		CCP2M2               EQU        CCP2CON.2
;	SREN    EQU   RCSTA.5		CCP2M1               EQU        CCP2CON.1
;	CREN    EQU   RCSTA.4		CCP2M0               EQU        CCP2CON.0
;	ADDEN   EQU   RCSTA.3
;	FERR    EQU   RCSTA.2
;	OERR    EQU   RCSTA.1
;	RX9D    EQU   RCSTA.0
;	RCD8    EQU   RCSTA.0
;
;===================================	;=======================================
;  ADCON0 Register BIT Definitions	;  OPTION_REG Register BIT Definitions
;===================================	;=======================================
;	ADCS1    EQU  ADCON0.7		NOT_RBPU EQU  OPTION_REG.7
;	ADCS0    EQU  ADCON0.6		INTEDG   EQU  OPTION_REG.6
;	CHS2     EQU  ADCON0.5		T0CS     EQU  OPTION_REG.5
;	CHS1     EQU  ADCON0.4		T0SE     EQU  OPTION_REG.4
;	CHS0     EQU  ADCON0.3		PSA      EQU  OPTION_REG.3
;	GO       EQU  ADCON0.2		PS2      EQU  OPTION_REG.2
;	NOT_DONE EQU  ADCON0.2		PS1      EQU  OPTION_REG.1
;	GO_DONE  EQU  ADCON0.2		PS0      EQU  OPTION_REG.0
;	ADON     EQU  ADCON0.0
;
;===================================	;=======================================
;  TRISE Register BIT Definitions	;  PIE1 Register BIT Definitions
;===================================	;=======================================
;	IBF     EQU  TRISE.7		PSPIE   EQU  PIE1.7
;	OBF     EQU  TRISE.6		ADIE    EQU  PIE1.6
;	IBOV    EQU  TRISE.5		RCIE    EQU  PIE1.5
;	PSPMODE EQU  TRISE.4		TXIE    EQU  PIE1.4
;	TRISE2  EQU  TRISE.2		SSPIE   EQU  PIE1.3
;	TRISE1  EQU  TRISE.1		CCP1IE  EQU  PIE1.2
;	TRISE0  EQU  TRISE.0		TMR2IE  EQU  PIE1.1
;					TMR1IE  EQU  PIE1.0
;
;=================================	;=======================================
;  PIE2 Register BIT Definitions	;  PCON Register BIT Definitions
;=================================	;=======================================
;	EEIE    EQU  PIE2.4		NOT_POR EQU  PCON.1
;	BCLIE   EQU  PIE2.3		NOT_BO  EQU  PCON.0
;	CCP2IE  EQU  PIE2.0		NOT_BOR EQU  PCON.0
;
;=======================================
;  SSPCON2 Register BIT Definitions
;=======================================
;	GCEN    EQU  SSPCON2.7
;	ACKSTAT EQU  SSPCON2.6
;	ACKDT   EQU  SSPCON2.5
;	ACKEN   EQU  SSPCON2.4
;	RCEN    EQU  SSPCON2.3
;	PEN     EQU  SSPCON2.2
;	RSEN    EQU  SSPCON2.1
;	SEN     EQU  SSPCON2.0
;
;====================================	;=======================================
;  SSPSTAT Register BIT Definitions	;  TXSTA Register BIT Definitions
;====================================	;=======================================
;	SMP           EQU  SSPSTAT.7	CSRC     EQU  TXSTA.7
;	CKE           EQU  SSPSTAT.6	TX9      EQU  TXSTA.6
;	D             EQU  SSPSTAT.5	NOT_TX8  EQU  TXSTA.6
;	I2C_DATA      EQU  SSPSTAT.5	TX8_9    EQU  TXSTA.6
;	NOT_A         EQU  SSPSTAT.5	TXEN     EQU  TXSTA.5
;	NOT_ADDRESS   EQU  SSPSTAT.5	SYNC     EQU  TXSTA.4
;	D_A           EQU  SSPSTAT.5	BRGH     EQU  TXSTA.2
;	DATA_ADDRESS  EQU  SSPSTAT.5	TRMT     EQU  TXSTA.1
;	P             EQU  SSPSTAT.4	TX9D     EQU  TXSTA.0
;	I2C_STOP      EQU  SSPSTAT.4	TXD8     EQU  TXSTA.0
;	S             EQU  SSPSTAT.3
;	I2C_START     EQU  SSPSTAT.3	;=======================================
;	R             EQU  SSPSTAT.2	;  ADCON1 Register BIT Definitions
;	I2C_READ      EQU  SSPSTAT.2	;=======================================
;	NOT_W         EQU  SSPSTAT.2	ADFM     EQU  ADCON1.7
;	NOT_WRITE     EQU  SSPSTAT.2	PCFG3    EQU  ADCON1.3
;	R_W           EQU  SSPSTAT.2	PCFG2    EQU  ADCON1.2
;	READ_WRITE    EQU  SSPSTAT.2	PCFG1    EQU  ADCON1.1
;	UA            EQU  SSPSTAT.1	PCFG0    EQU  ADCON1.0
;	BF            EQU  SSPSTAT.0
;
;=======================================
;  EECON1 Register BIT Definitions
;=======================================
;	EEPGD  EQU  EECON1.7
;	WRERR  EQU  EECON1.3
;	WREN   EQU  EECON1.2
;	WR     EQU  EECON1.1
;	RD     EQU  EECON1.0
;
;=======================================
;  Configuration (FUSE) BIT Definitions
;=======================================
;	_CP_ALL         EQU   0FCFh
;	_CP_HALF        EQU   1FDFh
;	_CP_UPPER_256   EQU   2FEFh
;	_CP_OFF         EQU   3FFFh
;	_DEBUG_ON       EQU   37FFh
;	_DEBUG_OFF      EQU   3FFFh
;	_WRT_ENABLE_ON  EQU   3FFFh
;	_WRT_ENABLE_OFF EQU   3DFFh
;	_CPD_ON         EQU   3EFFh
;	_CPD_OFF        EQU   3FFFh
;	_LVP_ON         EQU   3FFFh
;	_LVP_OFF        EQU   3F7Fh
;	_BODEN_ON       EQU   3FFFh
;	_BODEN_OFF      EQU   3FBFh
;	_PWRTE_OFF      EQU   3FFFh
;	_PWRTE_ON       EQU   3FF7h
;	_WDT_ON         EQU   3FFFh
;	_WDT_OFF        EQU   3FFBh
;	_LP_OSC         EQU   3FFCh
;	_XT_OSC         EQU   3FFDh
;	_HS_OSC         EQU   3FFEh
;	_RC_OSC         EQU   3FFFh

;
;PORT A
NOR_CONFG	EQU 	PORTA.0		;H = normal, L = configure DMX address/# channels
WR_RD		EQU 	PORTA.1		;H = write configuration L = read configuration
FERR_LED	EQU 	PORTA.2		;Output to indicate framing error -> beginning of packet
DSP_EN		EQU	PORTA.3		;Diag Board Display Latch
GOOD_DATA_LED	EQU 	PORTA.3		;Output to indicate all data for this unit collected
EXT_DIAG	EQU 	PORTA.4		;Extended Diagnostic board connected
OERR_LED	EQU	PORTA.5		;Over Run Error LED Signal
;
;PORT B
B0		EQU	PORTB.0		;Zero crossing input
DMX_OUT_0	EQU	PORTB.1		;DMX output #0
DIGIT_1		EQU	PORTB.1		;enable for ext diag board digit 1 (sw/LED)
DMX_OUT_1	EQU	PORTB.2		;DMX output #1
DIGIT_2		EQU	PORTB.1		;enable for ext diag board digit 2 (sw/LED)
DMX_OUT_2	EQU	PORTB.3		;DMX output #2
DIGIT_3		EQU	PORTB.1		;enable for ext diag board digit 3 (sw/LED)
DMX_OUT_3	EQU	PORTB.4		;DMX output #3
DIGIT_4		EQU	PORTB.1		;enable for ext diag board digit 4 (sw/LED)
DMX_OUT_4	EQU	PORTB.5		;DMX output #4
DIGIT_5		EQU	PORTB.1		;enable for ext diag board digit 5 (sw/LED)
DMX_OUT_5	EQU	PORTB.6		;DMX output #5
DMX_OUT_6	EQU	PORTB.7		;DMX output #6
;
;PORT C
DMX_OUT_7	EQU	PORTC.0		;DMX output #7
DMX_OUT_8	EQU	PORTC.1		;DMX output #8
DMX_OUT_9	EQU	PORTC.2		;DMX output #9
DMX_OUT_10	EQU	PORTC.3		;DMX output #10
DMX_OUT_11	EQU	PORTC.4		;DMX output #11
DMX_OUT_12	EQU	PORTC.5		;DMX output #12
TX		EQU	PORTC.6		;TX Transmit
RX		EQU	PORTC.7		;RX Receive
;
;PORT D
DMX_OUT_13	EQU	PORTD.0		;DMX output #13
DMX_OUT_14	EQU	PORTD.1		;DMX output #14
DMX_OUT_15	EQU	PORTD.2		;DMX output #15
DMX_OUT_16	EQU	PORTD.3		;DMX output #16
DMX_OUT_17	EQU	PORTD.4		;DMX output #17
DMX_OUT_18	EQU	PORTD.5		;DMX output #18
DMX_OUT_19	EQU	PORTD.6		;DMX output #19
DMX_OUT_20	EQU	PORTD.7		;DMX output #20
;
;PORT E
DMX_OUT_21	EQU 	PORTE.0		;DMX output #21
DMX_OUT_22	EQU 	PORTE.1		;DMX output #22
DMX_OUT_23	EQU	PORTE.2		;DMX output #23
SW_EN		EQU 	PORTE.2		;Diag Board Switch Enable

SWITCH_A1	equ 11111100b	;constant to turn on 1's rotary switch
SWITCH_A10	equ 11111010b	;constant to turn on 10's rotary switch
SWITCH_A100	equ 11110110b	;constant to turn on 100's rotary switch
SWITCH_C1	equ 11101110b	;constant to turn on channel 1's rotary switch
SWITCH_C10	equ 11011110b	;constant to turn on channel 10's rotary switch
SWITCH_OFF	equ 11111110b	;constant to turn off all rotary switches
BAUD_CONST 	equ 04		;constant for baud (250kbs high speed)
CR 		equ 0dh		;constant for carriage return
DMX_DATA_PTR	equ 20h		;FSR pointer for incoming DMX data
DMX_IN_DATA	equ 21h		;beginning of DMX Data Storaged
DMX_IN_END	equ 39h		;end of DMX Data Storage
B2_BCD_COUNT	equ 40h		;used in the binary to BCD routine
B2_BCD_TEMP	equ 41h		;used in the binary to BCD routine
H_BYTE		equ 42h		;used in the binary to BCD routine
L_BYTE		equ 43h		;used in the binary to BCD routine
R0		equ 44h		;used in the binary to BCD routine
R1		equ 45h		;used in the binary to BCD routine
R2		equ 46h		;used in the binary to BCD routine
ACCaLO		equ 47h		;used in the double precision add/subtract
ACCaHI		equ 48h		;used in the double precision add/subtract
ACCbLO		equ 49h		;used in the double precision add/subtract
ACCbHI		equ 4ah		;used in the double precision add/subtract
FSR_TEMP	equ 4bh		;used in binary to BCD routine
CHAR_OUT_PTR	equ 50h		;pointer for TX data (not used in DMX-512)
BUFFER_PTR	equ 51h		;point for RX Data
TEMP_A 		equ 52h		;temporary storage location - currently not used
TEMP_B		equ 53h		;temporary register - currently not used
TEMP_C		equ 54h		;temporary register - used with diag board
TEMP_D	 	equ 55h		;temporary register - used with diag board
TEMP_E	 	equ 56h		;temporary register - used with diag board
TEMP_F	 	equ 57h		;temporary register - used with diag board
TEMP_G	 	equ 58h		;temporary register - used with diag board
PA_TEMP 	equ 6fh		;temp register to read porta
W_TEMP 		equ 70h		;temp register for interrupts
STATUS_TEMP 	equ 71h		;temp register for interrupts
PCLATH_TEMP 	equ 72h		;temp register for interrupts
Flags 		equ 73h		;flag register
Tmr32us		equ Flags.0	;bit 0 32 us timer flag
DMX_MATCH      	equ Flags.1	;bit 1 Current DMX Frame = unit address
DMX_OERR       	equ Flags.2	;bit 2 Over run error on data - bad thing
DMX_BREAK	equ Flags.3	;bit 3 Framing error with data = 0 (beginning of Packet)
DMX_ADD_H      	equ Flags.4	;bit 4 Set for unit address over 255
DMX_FRM_H      	equ Flags.5	;bit 5 Set when the current DMX frame is over 255
DMX_DIAGX	equ Flags.6	;bit 6 In extended diagnostic mode
ZERO_X		equ Flags.7	;bit 7 Set when a zero crossing has occured
MULT_TEMP_L	equ 74h		;Used in BCD to binary conversion
MULT_TEMP_H	equ 75h		;Used in BCD to binary conversion
DMX_ADD		equ 78h		;Unit address
DMX_FRAME 	equ 79h		;Current DMX frame number
UNIT_CHNL	equ 7ah		;Number of unit DMX channels
CHNL_TEMP	equ 7bh		;Temp storage of # of unit DMX channels
DMX_DATA	equ 7ch		;Temp storage of incoming DMX data
CTR_32US	equ 7dh		;Counter for 32us time periods
BCD_L_BYTE	equ 7eh		;Used in BCD to binary conversion
BCD_H_BYTE	equ 7fh		;Used in BCD ti binary conversion
TMR0_Count 	equ 142		;tmr0 constant to load for 32.552us per interrupt was 110
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
INT_SRV_1
	btfsc rcif			;was it receive character interrupt?
	goto ServiceRX			;if so then jump
	btfsc t0if			;was it timer 0?
	goto ServiceTMR0		;if so then jump
	btfsc intf			;was it RB0/INT?
	goto ServicePB0			;if so then jump
INT_SRV_2
;	bcf rbif			;clear RB Port change flag
;	bcf pspif			;clear parallel slave port int flag (not on 28 pin)
;	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
;	bcf TXIF			;clear the TX Flag
	;
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
	movlw CHK_DIAG<			;move high byte of PC into W
	movwf PCLATH			;and into PCLATH
	call CHK_DIAG			;call to check for Diagnositics Board present
	call INIT_DATA			;call to setup the data
	call INIT_IRQ			;call to setup the interrupts
;	movlw DMX_DIAGX <		;move high byte of PC into W
;	movwf PCLATH			;and into PCLATH
	btfss DMX_DIAGX			;check for extended diagnostic board
	goto MAIN			;if not set, normal operation
DIAG_MAIN
	;routine will read the data at the address on the extended diagnostic board and
	;display on the numeric display.  Display will be updated twice a second.
	bsf RP0				;point to bank 1
	movlw 00000001B			;set port B to output (except B.0)
	movwf TRISB			;and set
	movlw 00000000B			;input value to W to make port D an output
	movwf TRISD			;set Port D to output
	movlw 00000011b			;set Port E to 0,1 in and 2 as out
	movwf TRISE			;and output
	bcf RP0				;point to bank 0
	bsf SW_EN			;make sure the switches are disabled
DIAG_MAIN_1	
;	call HALF_SEC_DELAY		;delay for 1/2 second
	movf DMX_IN_DATA, W		;get the first channel data
	movwf L_BYTE			;and store
	movlw 0				;set high byte
	movwf H_BYTE			;to 0
	call B2_BCD			;convert binary data to BCD, answer in R0, R1, R2
		;display the data for the selected channel
	movf R2, W			;get the 1's and 10's
	andlw 00001111b			;mask out the high nibble
	movwf PORTD			;and output
	movlw 11111100B			;toggle 1's display latch low to latch
	movwf PORTB			;output data
	bsf DSP_EN			;enable latches on diag board to display latches
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latch high to latch
	movwf PORTB			;output data
	movlw 11110000b			;set mask to show only the 10's nibble
	andwf R2, F			;mask out the 1's nibble
	swapf R2, W			;swap nibbles and place into W
	movwf PORTD			;and output to displays
	movlw 11111010B			;toggle 10's display latch low to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latch high to latch
	movwf PORTB			;output data
	movf R1, W			;get the 100's and 1000's
	andlw 00001111b			;mask out the high nibble
	movwf PORTD			;and output
	movlw 11110110B			;toggle 100's display latch low to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latch high to latch
	movwf PORTB			;output data
;	movf TEMP_B, W			;get channel count
;	andlw 11111000b			;mask off everything but the channel count
;	movwf L_BYTE			;and store
;	bcf C				;clear the C bit
;	rrf L_BYTE, F			;move byte 3 times to the right
;	rrf L_BYTE, F			;2nd time
;	rrf L_BYTE, F			;3rd time
;	movlw 0				;load high byte with 0
;	movwf H_BYTE			;and store
;	call B2_BCD			;convert binary data to BCD, answer in R0, R1, R2
;	movf R2, W			;get the 1's and 10's
;	andlw 00001111b			;mask out the high nibble
;	movwf PORTD			;and output
;	movlw 11101110B			;toggle 1's channel display latch low to latch
;	movwf PORTB			;output data
;	nop				;kill a moment of time
;	movlw 00111110B			;toggle display latch high to latch
;	movwf PORTB			;output data
;	movlw 11110000b			;set mask to show only the 10's nibble
;	andwf R2, F			;mask out the 1's nibble
;	swapf R2, W			;swap nibbles and place into W
;	movwf PORTD			;and output to displays
;	movlw 11011110B			;toggle 10's display latch low to latch
;	movwf PORTB			;output data
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latch high to latch
	movwf PORTB			;output data
	bcf DSP_EN			;and disable the latch
	goto DIAG_MAIN_1
	goto $				;loop here forever


MAIN
	;main only has to wait on a 32.5us clock tick.  When it arrives, then the value
	;of the 32.5us counter (which starts at 255 and counts down) is compared to the
	;received value of DMX data.  If the 32.5us counter is less than the received
	;data, then the cooresponding output should be turned on.
	btfss Tmr32us			;is the 32.5us flag on - if so skip next
	goto MAIN			;loop back
	bcf Tmr32us			;clear the 32us flag
	decfsz CTR_32US			;decrement the 32 us counter
	goto MAIN_1			;if counter is not zero then jump
	goto MAIN_MAX			;if counter is zero then jump
MAIN_1
	movf DMX_IN_DATA, W		;get the first channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_0			;else turn on channel
	movf DMX_IN_DATA+1, W		;get the second channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_1			;else turn on channel
	movf DMX_IN_DATA+2, W		;get the 3rd channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_2			;else turn on channel
	movf DMX_IN_DATA+3, W		;get the 4th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_3			;else turn on channel
	movf DMX_IN_DATA+4, W		;get the 5th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_4			;else turn on channel
	movf DMX_IN_DATA+5, W		;get the 6th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_5			;else turn on channel
	movf DMX_IN_DATA+6, W		;get the 7th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_6			;else turn on channel
	movf DMX_IN_DATA+7, W		;get the 8th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_7			;else turn on channel
	movf DMX_IN_DATA+8, W		;get the 9th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_8			;else turn on channel
	movf DMX_IN_DATA+9, W		;get the 10th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_9			;else turn on channel
	movf DMX_IN_DATA+10, W		;get the 11th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_10			;else turn on channel
	movf DMX_IN_DATA+11, W		;get the 12th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_11			;else turn on channel
	movf DMX_IN_DATA+12, W		;get the 13th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_12			;else turn on channel
	movf DMX_IN_DATA+13, W		;get the 14th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_13			;else turn on channel
	movf DMX_IN_DATA+14, W		;get the 15th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_14			;else turn on channel
	movf DMX_IN_DATA+15, W		;get the 16th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_15			;else turn on channel
	movf DMX_IN_DATA+16, W		;get the 17th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_16			;else turn on channel
	movf DMX_IN_DATA+17, W		;get the 18th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_17			;else turn on channel
	movf DMX_IN_DATA+18, W		;get the 19th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_18			;else turn on channel
	movf DMX_IN_DATA+19, W		;get the 20th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_19			;else turn on channel
	movf DMX_IN_DATA+20, W		;get the 21st channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_20			;else turn on channel
	movf DMX_IN_DATA+21, W		;get the 22nd channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_21			;else turn on channel
	movf DMX_IN_DATA+22, W		;get the 23rd channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_22			;else turn on channel
	movf DMX_IN_DATA+23, W		;get the 24th channel data
	subwf CTR_32US,W		;CTR_32US - Data Value
	btfss C				;if C = 1, do not turn on channel
	bsf DMX_OUT_23			;else turn on channel
	goto MAIN			;loop back
MAIN_MAX
	btfss Zero_X			;has a zero crossing happened?
	goto MAIN_MAX			;if not loop back
	bcf Zero_X			;else clear zero crossing flag
	movlw 00h			;turn off all outputs
	movwf PORTB			;clear port B
	movwf PORTC			;clear port C
	movwf PORTD			;clear port D
	movwf PORTE			;clear port E
	movlw 255			;load the 32us counter
	movwf CTR_32US			;with 255
	bcf GOOD_DATA_LED		;turn off LED
	bcf FERR_LED	 		;turn off LED
	goto MAIN			;loop back

	org 200h
CHK_DIAG
	;Check A.0 - if low then set diag flag to high.  Check A.4 - if high the basic diagnostic
	;board is connected. If A.1 is low then the extended diagnostic board is connected.
	;Set B.1-B.7 to outputs, D.0-D.7 to outputs and E.0 to input.
	bcf DMX_DIAGX			;clear the diagnostic flag
	bsf SW_EN			;disable switch inputs
	bcf DSP_EN			;disable LED output latches
	movf PORTA,W			;Read port A
	movwf TEMP_G			;store temporarly
	btfsc TEMP_G,0			;is a diagnostic board connected? Low if so.
	return				;if high, no diagnostic board so return
	btfss TEMP_G,4			;Diag board found, basic or extended?
	goto DIAG_EXT			;low so it is the extended board
DIAG_BASIC	;first clear the LEDs of any data
	movlw 0				;load W with 0
	movwf PORTB			;set port B ouputs to low
	movwf PORTD			;set port D outputs to low
	bsf DSP_EN			;output data to LEDs
	nop				;kill a moment of time
	bcf DSP_EN			;latch data
	btfss WR_RD			;is the mode read or write/read
	goto DIAG_BASIC_DSP		;if low just display data
		;change ports B.1-B7 and D.0-D7 to inputs to read jumpers
	bsf RP0				;point to bank 1
	movlw 11111111b			;set port b to intputs
	movwf TRISB			;set
	movwf TRISD			;also set port D to inputs
	bcf RP0				;point to bank 0
		;read the jumpers (D.0-D.7 is low address, B.1 is high address bit)
		;                 (B.3-B.7 is channel count)
	bcf DMX_ADD_H			;clear the high bit of DMX address
	bcf SW_EN			;enable data
	nop				;kill a moment of time
	movf PORTB,W			;get the DMX upper bit and channel count
	movwf TEMP_B			;and store in TEMP_B
	comf TEMP_B,F			;invert and store back in TEMP_B
	btfsc TEMP_B,1			;was the high DMX address bit set?
	bsf DMX_ADD_H			;if so set DMX high bit flag
	movf PORTD,W			;read the switches into W
	movwf TEMP_A			;store the data
	comf TEMP_A,F			;invert the data and store
	btfss Z				;was the address 0? if not then do next
	goto DIAG_BASIC_1		;if not 0 then jump
	btfss DMX_ADD_H			;low address byte was 0, was high address bit zero?
	goto BAD_ADD_BASIC		;address was 0,so jump to error routine
DIAG_BASIC_1
	clrf C				;clear C
	rrf TEMP_B, F			;rotate channel count to the right
	rrf TEMP_B, F			;for a total
	rrf TEMP_B, F			;of three times
	movlw 00011111B			;mask off the channel count
	andwf TEMP_B,W			;store into W
	btfsc Z				;is the count 0?
	goto BAD_CHNL_BASIC		;if so then jump
	sublw 24			;subtract (literal - W) 24 - channel count
	btfss C				;if C = 1 channel count = or less than 24
	goto BAD_CHNL_BASIC		;C=0, too many channels requested
		;check for address + channels > 511
	movf TEMP_A, W			;get low byte of DMX address
	movwf ACCaLO			;and store in ACCa low byte
	movlw 0				;load ACCa high byte with 0
	movwf ACCaHI			;
	movwf ACCbHI			;ACCb high byte also to zero
	btfsc DMX_ADD_H			;is the high bit of the dmx address set?
	bsf ACCaHI,0			;if so then set bit 0 of ACCaHI
	movf PORTB,W			;good data, so get Channel Count and high bit of DMX Address again
	movwf TEMP_B			;and store in TEMP_B
	comf TEMP_B,F			;invert and store back in TEMP_B
	clrf C				;clear C
	rrf TEMP_B, F			;rotate channel count to the right
	rrf TEMP_B, F			;for a total
	rrf TEMP_B, F			;of three times
	movlw 00011111B			;mask off the channel count
	andwf TEMP_B,W			;store into W
	movwf ACCbLO			;and store in ACCb low byte
	call D_ADD			;and add the values together (result in ACCb)
	movf ACCbHI, W			;get the high byte into W
	sublw 1				;subtract (1 - W), if neg then error
	btfss C				;if set then address + channel < 512
	goto BASIC_ADD_CHNL_ERR		;else jump
	movf PORTB,W			;good data, so get Channel Count and high bit of DMX Address again
	movwf TEMP_B			;and store in TEMP_B
	comf TEMP_B,F			;invert and store back in TEMP_B
	bsf SW_EN			;disable outputs latches on jumpers
	call WRITE_EEROM			;and write data to EEROM
		;display the data from the EEROM (in TEMP_A & TEMP_B)
		;set B.1-B7 and D0.-D7 to outputs
DIAG_BASIC_DSP
	call READ_EEROM			;read data from EEROM
	bsf RP0				;point to bank 1
	movlw 00000001b			;set B.1-B.7 to outputs
	movwf TRISB			;and set
	movlw 00000000b			;set port D to output
	movwf TRISD			;and set
	bcf RP0				;point to bank 1
	movf TEMP_A, W			;get low address byte
	movwf PORTD			;and output
	movf TEMP_B, W			;get high bit and channel count
	movwf PORTB			;and output
	bsf DSP_EN			;open the data latch
	nop				;kill a moment of time
	bcf DSP_EN			;latch the data
	goto $				;loop here forever
BASIC_ADD_CHNL_ERR
		;channel count + address >511
		;make address and channel LEDs blink with the error LED
	bsf SW_EN			;disable outputs latches on jumpers
	bsf RP0				;point to bank 1 - clr displays, then read switches
	movlw 00000001B			;set port B to output (except B.0)
	movwf TRISB			;and set
	movlw 00000000b			;get value to set port D to output
	movwf TRISD			;set Port D to output
	bcf RP0				;point to bank 0
BASIC_ADD_CHNL_ERR_1
	movlw 11111111b			;load W with value to turn the address LEDs on
	movwf PORTD			;and output
	movlw 11111110B			;turn on error, channel & high bit address LED
	movwf PORTB			;output data
	bsf DSP_EN			;enable latches on diag board to display latches
	nop				;kill a moment of time
	bcf DSP_EN			;and disable the latch
	call HALF_SEC_DELAY		;delay for about 1/2 second
	movlw 00000000b			;load W with value to turn off address LEDs
	movwf PORTD			;and output
	movlw 00000100B			;turn off high address bit & channel LEDs
	movwf PORTB			;output data
	bsf DSP_EN			;enable latches on diag board to display latches
	nop				;kill a moment of time
	bcf DSP_EN			;and disable the latch
	call HALF_SEC_DELAY		;delay for about 1/2 second
	goto BASIC_ADD_CHNL_ERR_1	;loop back forever

BAD_CHNL_BASIC		;channel count to high (or 0) - turn on the red LED on the diag board
	bsf SW_EN			;disable outputs latches on jumpers
	bsf RP0				;point to bank 1
	movlw 00000001h			;set port B to output (except B.0)
	movwf TRISB			;set port
	movlw 00000000b			;set port D to outputs
	movwf TRISD			;set port
	bcf RP0				;point to bank 0
	movlw 00000000b			;turn off address leds
	movwf PORTD			;and output
BAD_CHNL_BASIC_1
	movlw 00000100B			;load data to turn on error led
	movwf PORTB			;and output
	bsf DSP_EN			;latch led data into diag board
	nop				;kill some time
	bcf DSP_EN			;clear latch signal
	call HALF_SEC_DELAY		;delay for about 1/2 second
	movlw 11111100B			;load data to turn on error led and channel LED's
	movwf PORTB			;and output
	bsf DSP_EN			;latch led data into diag board
	nop				;kill some time
	bcf DSP_EN			;clear latch signal
	call HALF_SEC_DELAY		;delay for about 1/2 second
	goto BAD_CHNL_BASIC_1		;loop here forever

BAD_ADD_BASIC		;address count to high (0r 0) - turn on the red LED on the diag board
	bsf SW_EN			;disable outputs latches on jumpers
	bsf RP0				;point to bank 1
	movlw 00000001h			;set port B to output (except B.0)
	movwf TRISB			;set port
	movlw 00000000h			;set port D to output
	movwf TRISD			;set port
	bcf RP0				;point to bank 0
	movlw 00000000B			;load data to turn on error led
	movwf PORTB			;and output
BAD_ADD_BASIC_1
	movlw 00000100B			;load data to turn on error led
	movwf PORTB			;and output
	movlw 00000000b			;turn off address leds
	movwf PORTD			;and output
	bsf DSP_EN			;latch led data into diag board
	nop				;kill some time
	bcf DSP_EN			;clear latch signal
	call HALF_SEC_DELAY		;delay for about 1/2 second
	movlw 00000110B			;load data to turn on error led
	movwf PORTB			;and output
	movlw 11111111b			;turn on address leds
	movwf PORTD			;and output
	bsf DSP_EN			;latch led data into diag board
	nop				;kill some time
	bcf DSP_EN			;clear latch signal
	call HALF_SEC_DELAY		;delay for about 1/2 second
	goto BAD_ADD_BASIC_1		;loop back
HALF_SEC_DELAY
	;a non-interrupt drive delay of 1/2 second
	movlw 100			;load a few registers with 255
	movwf TEMP_A			;
	movlw 100			;load a few registers with 255
	movwf TEMP_B			;
	movlw 100			;load a few registers with 255
	movwf TEMP_C			;
HSD_1
	movlw 100			;load a few registers with 255
	movwf TEMP_B			;
HSD_2
	movlw 100			;load a few registers with 255
	movwf TEMP_C			;
HSD_3
	decfsz TEMP_C			;decrement TEMP_C
	goto HSD_3			;if not zero then loop back
	decfsz TEMP_B			;after 255 counts in TEMP_C decrement TEMP_B
	goto HSD_2			;if TEMP_B not zero then loop back for another 255 count of TEMP_C
	decfsz TEMP_A			;if TEMP_B =0 then decrement TEMP_A - if not zero then loop back
	goto HSD_1			;255 more of TEMP_A
	return				;else return

DIAG_EXT
		;extended diagnostic board found
		;first clear the LEDs of any data
	bsf RP0				;point to bank 1 - clr displays, then read switches
	movlw 00000011b			;set port E 0,1 to inputs and 2 as output
	movwf TRISE			;and and set
	movlw 00000001B			;set port B to output (except B.0)
	movwf TRISB			;and set
	movlw 00000000b			;get value to set port D to output
	movwf TRISD			;set Port D to output
	bcf RP0				;point to bank 0
	movf PORTE,W			;get data from Port E
	movwf TEMP_G			;and store
	btfss TEMP_G, 0			;is E.0 high, if so skip next
	bsf DMX_DIAGX			;set the extended diagnostic flag
	movlw 00001111b			;load W with value to blank displays
	movwf PORTD			;and output
	movlw 00000000B			;toggle display latches low to latch
	movwf PORTB			;output data
	bsf DSP_EN			;enable latches on diag board to display latches
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latches high to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	bcf DSP_EN			;and disable the latch
	btfsc DMX_DIAGX			;is the extended diagnostic flag set?
	goto DIAG_EXT_1			;if set then jump
	btfss WR_RD			;is the mode read or write/read
	goto DIAG_EXTED_DSP		;if low just display data

DIAG_EXT_1
		;Numeric Displays are blank, change Port D to input to read the switches
	bsf RP0				;point to bank 1
	movlw 11111111b			;set port D as input
	movwf TRISD			;set port
	bcf RP0				;point to bank 0
	bcf SW_EN			;enable data from switches
	movlw SWITCH_A1			;enable data from 1's switch
	movwf PORTB			;and output
	nop				;kill a moment of time
	movf PORTD, W			;read the 1's address switch data
	movwf TEMP_C			;and store in TEMP_C
	comf TEMP_C, W			;invert and put in W
	andlw 0fh			;mask off the upper nibble
	movwf TEMP_C			;and store
	movlw SWITCH_A10		;turn off 1's switch and turn 10's switch on
	movwf PORTB			;and output
	nop				;kill a moment of time
	movf PORTD, W			;read the 10's address switch data
	movwf TEMP_D			;and store
	comf TEMP_D, W			;invert and put in W
	andlw 0fh			;mask off the upper nibble
	movwf TEMP_D			;and store
	movlw SWITCH_A100		;turn off 10's switch and turn 100's switch on
	movwf PORTB			;and output
	nop				;kill a moment of time
	movf PORTD, W			;read the 100's address switch data
	movwf TEMP_E			;and store
	comf TEMP_E, W			;invert and put in W
	andlw 0fh			;mask off the upper nibble
	movwf TEMP_E			;and store
	movlw SWITCH_C1			;turn off 100's switch and turn channel 1's switch on
	movwf PORTB			;and output
	nop				;kill a moment of time
	movf PORTD, W			;read the 1's channel switch data
	movwf TEMP_F			;and store
	comf TEMP_F, W			;invert andput in W
	andlw 0fh			;mask off the upper nibble
	movwf TEMP_F			;and store
	movlw SWITCH_C10		;turn off channel 1's switch and turn channel 10's switch on
	movwf PORTB			;and output
	nop				;kill a moment of time
	movf PORTD, W			;read the 10's channel switch data
	movwf TEMP_G			;and store
	comf TEMP_G, W			;invert and put in W
	andlw 0fh			;mask off the upper nibble
	movwf TEMP_G			;and store
	movlw SWITCH_OFF		;turn off all rotary switches
	movwf PORTB			;and output
	bsf SW_EN			;disable switch output
	call BCD_TO_BINARY		;convert adress data to binary
	movf BCD_H_BYTE, W		;move high byte of address to W
	sublw 1				;is it greater than 1?
	btfss C				;if C=1 then value is less than 512, OK
	goto EXT_ADD_ERR		;if C=0 then value is over 512, goto error
	movf BCD_L_BYTE,F		;move the value to itself to check for zero
	btfss Z				;if zero skip next
	goto CK_DIAG_EXTD		;not zero so jump
	movf BCD_H_BYTE,F		;move the value to itself to check for zero
	btfsc Z				;if not zero then skip next
	goto EXT_ADD_ERR		;DMX address is zero so jump to error on address
CK_DIAG_EXTD
	btfsc DMX_DIAGX			;is the extended diagnostic flag set?
	goto EXTD_DIAG			;if set then jump to extended diagnositic setup
SET_CHNL_EXTD
	movf TEMP_F,W			;get the channel count low byte
	movwf TEMP_C			;and store in TEMP_C
	movf TEMP_G,W			;get the channel count high byte
	movwf TEMP_D			;and store in TEMP_D
	movlw 0				;clear out TEMP_E
	movwf TEMP_E			;
	movf BCD_L_BYTE,W		;move the converted address into W
	movwf TEMP_A			;and store in TEMP_A
	movf BCD_H_BYTE,W		;move high byte into W
	movwf TEMP_B 			;and store in TEMP_B
	call BCD_TO_BINARY		;convert channel data to binary
	movf BCD_L_BYTE,F		;move the value to itself to check for zero
	btfss Z				;if zero skip next
	goto EXTD_ADD_PLUS_CHNL		;not zero so jump
	movf BCD_H_BYTE,F		;move the value to itself to check for zero
	btfsc Z				;if not zero then skip next
	goto EXT_CHN_ERR		;DMX channel count is zero so jump to error on channel

EXTD_ADD_PLUS_CHNL	; check for address + channel count > 511
	movf BCD_L_BYTE, W		;move the binary channel count to W
	movwf ACCaLO			;and then into register for addition
	movf BCD_H_BYTE, W		;move the binary channel count to W
	movwf ACCaHI			;and then into register for addition
	movf TEMP_A, W			;move the binary DMX address to W
	movwf ACCbLO			;and then into register for addition
	movf TEMP_B, W			;move the binary DMX address to W
	movwf ACCbHI			;and then into register for addition
	call D_ADD			;and add the values together (result in ACCb)
	movf ACCbHI, W			;get the high byte into W
	sublw 1				;subtract (1 - W), if neg then error
	btfss C				;if set then address + channel < 512
	goto EXTD_ADD_CHNL_ERR		;else jump
	clrf C				;clear the C bit
	rlf TEMP_B, F			;move once left and put back into TEMP_B
SET_CHNL_EXTD_1
	movf BCD_L_BYTE,W		;move the binary channel count to W
	sublw 24			;subtract binary channel count from 24(max channel count)
	btfss C				;if C=1 then value is less than 25, OK
	goto EXT_CHN_ERR		;if C=0 then value is over 24, goto error
	bcf C				;clear the Carry bit
	rlf BCD_L_BYTE, F		;rotate the value 3 places to the left
	rlf BCD_L_BYTE, F		;second time
	rlf BCD_L_BYTE, W		;third time and into W
	iorwf TEMP_B,F			;OR channel count (high nibble) with high bit of address (B0)
	call WRITE_EEROM		;write data to EEROM

DIAG_EXTED_DSP
	;read the EEROM data and display on numeric displays
	;must convert data from binary to BCD
	;data is in TEMP_A & TEMP_B after READ_EEROM
	;TEMP_A = low byte of unit address, TEMP_B.1 high address bit
	;TEMP_B.3-.7 contain channel count
	call READ_EEROM			;read data from EEROM - store in TEMP_A & TEMP_B on return
	movf TEMP_A, W			;get low address value
	movwf L_BYTE			;and store
	movf TEMP_B, W			;get high address bit
	andlw 00000010b			;mask off all but the high address bit
	movwf H_BYTE			;and store
	bcf C				;clear the C bit
	rrf H_BYTE, F			;move byte once to the right
	call B2_BCD			;convert binary data to BCD, answer in R2, R1, R0
test:		;display the unit address
	bsf RP0				;point to bank 1
	movlw 00000001B			;set port B to output (except B.0)
	movwf TRISB			;and set
	movlw 00000000B			;input value to W to make port D an output
	movwf TRISD			;set Port D to output
	bcf RP0				;point to bank 0
	movf R2, W			;get the 1's and 10's
	andlw 00001111b			;mask out the high nibble
	movwf PORTD			;and output
	movlw 11111100B			;toggle 1's display latch low to latch
	movwf PORTB			;output data
	bsf DSP_EN			;enable latches on diag board to display latches
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latch high to latch
	movwf PORTB			;output data
	movlw 11110000b			;set mask to show only the 10's nibble
	andwf R2, F			;mask out the 1's nibble
	swapf R2, W			;swap nibbles and place into W
	movwf PORTD			;and output to displays
	movlw 11111010B			;toggle 10's display latch low to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latch high to latch
	movwf PORTB			;output data
	movf R1, W			;get the 100's and 1000's
	andlw 00001111b			;mask out the high nibble
	movwf PORTD			;and output
	movlw 11110110B			;toggle 100's display latch low to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latch high to latch
	movwf PORTB			;output data
	movf TEMP_B, W			;get channel count
	andlw 11111000b			;mask off everything but the channel count
	movwf L_BYTE			;and store
	bcf C				;clear the C bit
	rrf L_BYTE, F			;move byte 3 times to the right
	rrf L_BYTE, F			;2nd time
	rrf L_BYTE, F			;3rd time
	movlw 0				;load high byte with 0
	movwf H_BYTE			;and store
	call B2_BCD			;convert binary data to BCD, answer in R0, R1, R2
	movf R2, W			;get the 1's and 10's
	andlw 00001111b			;mask out the high nibble
	movwf PORTD			;and output
	movlw 11101110B			;toggle 1's channel display latch low to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latch high to latch
	movwf PORTB			;output data
	movlw 11110000b			;set mask to show only the 10's nibble
	andwf R2, F			;mask out the 1's nibble
	swapf R2, W			;swap nibbles and place into W
	movwf PORTD			;and output to displays
	movlw 11011110B			;toggle 10's display latch low to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latch high to latch
	movwf PORTB			;output data
	bcf DSP_EN			;and disable the latch
;	goto test:
	goto $				;loop here forever

EXTD_ADD_CHNL_ERR
		;make address and channel display blinking -
	bsf RP0				;point to bank 1 - clr displays, then read switches
	movlw 00000001B			;set port B to output (except B.0)
	movwf TRISB			;and set
	movlw 00000000b			;get value to set port D to output
	movwf TRISD			;set Port D to output
	bcf RP0				;point to bank 0
EXTD_ADD_CHNL_ERR_1
	movlw 00001101b			;load W with value to display -
	movwf PORTD			;and output
	movlw 00000000B			;toggle address & channel display latches low to latch
	movwf PORTB			;output data
	bsf DSP_EN			;enable latches on diag board to display latches
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latches high to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	bcf DSP_EN			;and disable the latch
	call HALF_SEC_DELAY		;delay for about 1/2 second
	movlw 00001111b			;load W with value to display nothing
	movwf PORTD			;and output
	movlw 00000000B			;toggle address & channel display latches low to latch
	movwf PORTB			;output data
	bsf DSP_EN			;enable latches on diag board to display latches
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latches high to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	bcf DSP_EN			;and disable the latch
	call HALF_SEC_DELAY		;delay for about 1/2 second
	goto EXTD_ADD_CHNL_ERR_1	;loop back forever

EXT_ADD_ERR
		;make address displays blinking -
	bsf RP0				;point to bank 1 - clr displays, then read switches
	movlw 00000001B			;set port B to output (except B.0)
	movwf TRISB			;and set
	movlw 00000000b			;get value to set port D to output
	movwf TRISD			;set Port D to output
	bcf RP0				;point to bank 0
EXT_ADD_ERR_1
	movlw 00001101b			;load W with value to display -
	movwf PORTD			;and output
	movlw 00110000B			;toggle address display latches low to latch
	movwf PORTB			;output data
	bsf DSP_EN			;enable latches on diag board to display latches
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latches high to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	bcf DSP_EN			;and disable the latch
	call HALF_SEC_DELAY		;delay for about 1/2 second
	movlw 00001111b			;load W with value to display nothing
	movwf PORTD			;and output
	movlw 00110000B			;toggle address display latches low to latch
	movwf PORTB			;output data
	bsf DSP_EN			;enable latches on diag board to display latches
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latches high to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	bcf DSP_EN			;and disable the latch
	call HALF_SEC_DELAY		;delay for about 1/2 second
	goto EXT_ADD_ERR_1		;loop back forever

EXT_CHN_ERR
		;make channel displays blinking -
	bsf RP0				;point to bank 1 - clr displays, then read switches
	movlw 00000001B			;set port B to output (except B.0)
	movwf TRISB			;and set
	movlw 00000000b			;get value to set port D to output
	movwf TRISD			;set Port D to output
	bcf RP0				;point to bank 0
EXT_CHN_ERR_1
	movlw 00001101b			;load W with value to display -
	movwf PORTD			;and output
	movlw 00001110B			;toggle channel display latches low to latch
	movwf PORTB			;output data
	bsf DSP_EN			;enable latches on diag board to display latches
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latches high to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	bcf DSP_EN			;and disable the latch
	call HALF_SEC_DELAY		;delay for about 1/2 second
	movlw 00001111b			;load W with value to display nothing
	movwf PORTD			;and output
	movlw 00001110B			;toggle channel display latches low to latch
	movwf PORTB			;output data
	bsf DSP_EN			;enable latches on diag board to display latches
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latches high to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	bcf DSP_EN			;and disable the latch
	call HALF_SEC_DELAY		;delay for about 1/2 second
	goto EXT_CHN_ERR_1		;loop back forever

EXTD_DIAG
	;extended diagnostic mode where the DMX channel indicated on the diagnostic board
	;is read from the DMX stream and displayed on the numeric displays
	;the address to monitor is currently held in binary form in BCD_L_BYTE & BCD_H_BYTE
	;where BCD_L_BYTE holds the low byte and bit 0 of BCD_H_BYTE holds the high bit
		;extended diagnostic board found
		;first clear the LEDs of any data
	bsf RP0				;point to bank 1 - clr displays, then read switches
	movlw 00000001B			;set port B to output (except B.0)
	movwf TRISB			;and set
	movlw 00000000b			;get value to set port D to output
	movwf TRISD			;set Port D to output
	bcf RP0				;point to bank 0
	movlw 00001111b			;load W with value to blank displays
	movwf PORTD			;and output
	movlw 00000000B			;toggle display latches low to latch
	movwf PORTB			;output data
	bsf DSP_EN			;enable latches on diag board to display latches
	nop				;kill a moment of time
	movlw 00111110B			;toggle display latches high to latch
	movwf PORTB			;output data
	nop				;kill a moment of time
	bcf DSP_EN			;and disable the latch
	return				;return to caller



	org 500h
INIT_PORTS
	;Start by setting Port A.0, .1 as digital inputs and A.2-A.5 to outputs - Check A.0,
	;if low then enter the configuration setup.  If A.1 is high then Ports B, D, E, will
	;be set to outputs and the EEROM data will be displayed.  If A.1 is low the  Ports
	;B, D and E are all set to be inputs.  Port D will input the unit address low 8 bits,
	;which will be stored in 00h EEROM.  Port B will use B.1 to set the 9th bit of the unit
	;address, and B.4-B.7 for the number of DMX channels in the unit.  Port B data will be
	;stored in 01H EEROM.  Following the data being written, Ports B, D, and E will be set to
	;outputs and the contents of the EEROM will be read and displayed on the switch box LEDs.
	;
	;Should A.0 be read high, then normal operation will ensue.  Port A.0,.1 will remain
	;as a digital inputs, A.2-A.5 will be ouputs, Port B - B.0 as an input/interrupt
	;for the zero crossing, B.1-B.7 as DMX outputs base+0 -> 6.  Port C - C.7 for
	;RX input, C.6 as TX output, C.0-C.5 as DMX outputs base+7 -> 12.  Port D is all
	;DMX outputs base+13 -> 20.  Port E is all DMX outputs base+21 ->23 (24 DMX outputs total).
	;
	bcf rp0				;point to
	bcf rp1				;bank 0
	clrf Flags			;clear Flags
	clrf SSPCON			;clear SSPCON to disable SYNC Port
	clrf T1CON			;clear Timer 1 to disable
	clrf T2CON			;clear Timer 2 to disable
	clrf CCP1CON			;ccp module 1 is off (bank0:17
	clrf CCP2CON			;ccp module 2 is off
	clrf TMR2			;clear timer 2 (bank0:11)
	clrf PORTA			;intitialize port a by clearing (bank 0:05) data latches
	bsf RP0				;point to bank 1
	movwf SSPCON2			;disable sync port
	movlw 06h			;configure all pins
	movwf ADCON1			;as digital (not analog)(bank1:9f)
	movlw 00010011b			;value used to initialize data direction
	movwf TRISA			;set all pins to outputs, except A.0&.1 as input(bank1:85)
	movlw 00000001b			;value used to initialize port B data direction
	movwf TRISB			;set bit 0 to input, all others to outputs (bank1:86)
	movlw 10000000b			;value used to initialize data direction
	movwf TRISC			;set all pins to outputs (bank1:87)
	movlw 00000000b			;value used to initialize data direction
	movwf TRISD			;set port D to outputs
	movwf TRISE			;set port E to output
	bcf RP0				;point to bank 0
	movlw 0				;load W with 0
	movwf PORTB			;set port B ouputs to low
	movwf PORTC			;set port C outputs to low
	movwf PORTD			;set port D outputs to low
	movwf PORTE			;set port E outputs to low
	bsf RP0				;point to bank 1
	movlw 00000100b			;set 8-bit mode, BRGH high, TX disabled
	movwf TXSTA			;asynchronous mode, high speed (bank1:98)
	movlw 00000000b
	movlw BAUD_CONST		;get the baud rate
	movwf SPBRG			;and set (bank1:99 )
	bcf TXEN			;disable TX
	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)
	return				;return to caller


INIT_IRQ
	;Setup of  timer 0 for a 32.552us interrupt, using a 20MHz oscillator
	;and a prescaler of 1:1, the timer should be pre loaded with a
	;value of 93.  This is calculated by 20MHz/4 = 5MHz.
	;5 MHz/1:1 prescaler = 0.2uS.  32.552us/0.2uS = 163.  Finally
	;(256-93)*0.2us = 32.552us.
	bsf rp0				;point to
	bcf rp1				;bank 1
	clrf PIE1
	movlw	11001000B		;disable PB PU,enable PB0 int, Prescaler to WDT (1:1)
	movwf OPTION_REG		;and set in option register
	bcf rp0				;select bank 0
	movlw 01110000B			;enable tmr0 & Peripheral int
	movwf intcon			;and place in register
	movlw TMR0_Count		;preset value for timer 0
	movwf TMR0			;store
	retfie				;return to caller while enabling interrupts

INIT_DATA
	;Clear the outputs and the storage data locations for incoming data.
	;Read EEROM to get the unit address and number of channels
	btfsc DMX_DIAGX			;is the extended diagnostic flag set?
	goto INIT_DATA_DIAGX		;if so then jump
	movlw 0				;set the outputs to all 0
	movwf PORTB			;clear port B
	movwf PORTC			;clear port C
	movwf PORTD			;clear port D
	movwf PORTE			;clear port E
	call READ_EEROM			;get the unit address and channel count
;	movlw 1				;****************test load*********************
;	movwf TEMP_A			;****************test load*********************
	movf TEMP_A,W			;move unit address into W
	movwf DMX_ADD			;and then into DMX_ADD
	bcf DMX_ADD_H			;clear the high bit of the unit address
;	movlw 10111000b			;****************test load*********************
;	movwf TEMP_b			;****************test load*********************
	btfsc TEMP_B, 1			;is bit 1 clear - if so skip next
	bsf DMX_ADD_H			;else set the unit address high bit
	movlw 0f8h			;load mask
	andwf TEMP_B, F			;only the upper 4 bits used
	bcf C				;clear the carry bit
	rrf TEMP_B, F			;move it 3 places to the right (one)
	rrf TEMP_B, F			;two
	rrf TEMP_B, W			;three
	movwf UNIT_CHNL			;and save in UNIT_CHNL
	movlw DMX_IN_DATA		;get the address of the first storage location
	movwf FSR			;and store for indirect addressing
	movlw 24			;load the maximum channel count
	movwf CHNL_TEMP			;and store in temp location
	movlw 0				;load 0 into W
INIT_DATA_1
	movwf INDF			;and store data in buffer
	incf FSR, F			;point to next storage location
	decfsz CHNL_TEMP		;decrement the channel counter, if 0 then skip next
	goto INIT_DATA_1		;loop back until all locations have been cleared
	return
INIT_DATA_DIAGX
	;the extended diagnostic flag is set so use current switch setting as to which channel
	;to monitor and display on the numeric display.
		;setup the frame number and channel count for diagnostics
	movf BCD_L_BYTE,W		;move unit address into W
	movwf DMX_ADD			;and then into DMX_ADD
	bcf DMX_ADD_H			;clear the high bit of the unit address
	btfsc BCD_H_BYTE, 0		;is bit 0 clear - if so skip next
	bsf DMX_ADD_H			;else set the unit address high bit
	movlw 1				;set the channel count to 1
	movwf UNIT_CHNL			;and save in UNIT_CHNL
	movf UNIT_CHNL,W		;get the unit channel count
	movwf CHNL_TEMP			;and store in temp location
		;setup where to place incoming data
	movlw DMX_IN_DATA		;get the address of the first storage location
	movwf FSR			;and store for indirect addressing
	movlw 0				;load 0 into W
	movwf INDF			;and store data in buffer
	return				;return to caller

	org 600h
ServiceTMR0		;32.5ms timer - set flag to indicate 32.5ms period
	movlw TMR0_Count		;get delay value for 32.5 ms
	movwf tmr0			;and load
	bcf t0if			;clear tmr0 interrupt flag
	bsf Tmr32us			;set 32.5 ms flag
	bcf FERR_LED
	goto INT_SRV_EXIT		;goto exit ISR

ServicePB0		;zero crossing of 60Hz wave has caused an interrupt
			;first reset TMR0 and clear 32us flag
	bcf intf			;clear the PB0 interrupt flag
	bsf Zero_X			;set zero crossing flag
	goto INT_SRV_1			;goto exit ISR

RS232_OUT		;send first character via RS232 and enable TX interrupts
			;********* No TX done in DMX-512 ************
	movlw 21h			;set character pointer to begin of buffer
	movwf CHAR_OUT_PTR		;
	movwf FSR			;use indirect addressing to point to buffer beginning
	bsf RP0				;bank 1
	bsf TXIE			;enable tx interrupts (bank1:8C  PIE1.4)
	bcf RP0				;bank 0
	movf INDF			;get character from buffer
	movwf TXREG			;load the char into the transmit register and send
	inc CHAR_OUT_PTR		;point to next character
	return				;return to caller

ServiceTX
	movf CHAR_OUT_PTR		;get current buffer location
	movwf FSR			;and store
	movf INDF			;get character from buffer
	btfsc Z				;is it 0 - if so do next step
	goto TX_1			;jump if zero
	movf INDF			;get character from buffer
	movwf TXREG			;and place in tx data register
	goto INT_SRV_EXIT		;goto exit ISR
TX_1
	bsf rp0				;point to bank 1
	bcf TXIE			;disable TX interrupts
	bcf RP0				;point to bank 0
	movf INDF			;get character from buffer
	movwf TXREG			;and place in tx data register
	goto INT_SRV_EXIT		;goto exit ISR

ServiceRX
	;When a RX interrupt occurs, 1st check for an overrun error - if one
	;has occured then clear the flags and light the error LED.
	;If no overrun has occured, check for a framing error - this will
	;indicate the beginning of a packet, IF the incoming data was 0.
	;If a FERR with data of 0 has occured, then set the BREAK flag,
	;turn off the FERR LED, clear the frame counter and the high bit for
	;counting frames.  Check again for an overrun - if an overrun has
	;occured, the read the RX data twice to clear the buffer, disable and
	;then enable the continous receive bit, clear the BREAK flag and
	;turn on the OERR LED.
	btfsc OERR			;has an over run occured?
	goto ServiceRX_OERR		;if so then jump
	btfsc FERR			;has a framing error occured?
	goto ServiceRX_FERR		;if so then jump
	movf RCREG,W			;no errors, so get the data
	movwf DMX_DATA			;and store
	btfss DMX_BREAK			;is the beginning of frame flag set?
	goto INT_SRV_EXIT		;no beginning of frame - useless data
	btfsc DMX_MATCH			;have we reached the beginning unit address already
	goto ServiceRX_DATA		;if so then jump
	movf DMX_ADD, W			;get the unit address (low byte)
	subwf DMX_FRAME, W		;subtract DMX_FRAME - DMX_ADD
	btfss Z				;are they equal? If so skip next
	goto ServiceRX_INC		;not equal, increment frame counter
	btfss DMX_FRM_H			;has the frame count passed 255?
	goto DMX_FRM_0			;if not jump
DMX_FRM_1		;low address bytes match, frame count has exceeded 255
	btfsc DMX_ADD_H			;is the unit address over 255?
	goto ServiceRX_MATCH		;if so then jump
	bcf DMX_BREAK			;error condition, clear the break flag
	goto INT_SRV_EXIT		;and exit ISR
DMX_FRM_0		;low address bytes match, frame count less than 255
	btfsc DMX_ADD_H			;is the unit address over 255?
	goto ServiceRX_INC		;not equal, increment frame counter
ServiceRX_MATCH		;addresses match, set the match flag
	bsf DMX_MATCH			;set match address flag
	movlw DMX_IN_DATA		;get the address of the first storage location
	movwf FSR			;and store for indirect addressing
	movf UNIT_CHNL,W		;get the unit channel count
	movwf CHNL_TEMP			;and store in temp location
ServiceRX_DATA		;load current data into storage
;	btfss t0if			;has timer 0 reached 0?
;	goto ServiceRX_FERR_1		;if not then jump
;	movlw TMR0_Count		;get delay value for 32.5 ms
;	movwf tmr0			;and load
;	bcf t0if			;clear tmr0 interrupt flag
;	bsf Tmr32us			;set 32.5 ms flag
;	bcf FERR_LED
	bsf GOOD_DATA_LED		;turn on LED
	movf DMX_DATA,W			;get received data into W
	movwf INDF			;and store data in buffer
	incf FSR, F			;point to next storage location
	decfsz CHNL_TEMP		;decrement the channel counter, if 0 then skip next
	goto INT_SRV_EXIT		;goto exit ISR
	bcf DMX_BREAK			;all data received, clear the break flag
;	bcf GOOD_DATA_LED		;turn off LED
	goto INT_SRV_EXIT		;goto exit ISR
ServiceRX_INC
	incf DMX_FRAME,F		;increment the frame counter
	btfsc Z				;did it roll over from 255 -> 0?
	bsf DMX_FRM_H			;if so, set the frame counter high bit
	goto INT_SRV_EXIT		;and exit ISR
ServiceRX_FERR
	bcf OERR_LED			;turn off the over run LED
	bcf GOOD_DATA_LED		;turn off good data LED
	bsf FERR_LED			;turn on the framing error LED
	movf RCREG,W			;get the data
	btfsc Z				;was it 0?
	bsf DMX_BREAK			;if so, then set flag to show it
	clrf DMX_FRAME			;clear the frame counter
	bcf DMX_FRM_H			;clear high bit of frame counter
	bcf DMX_MATCH			;clear the address match flag
;	btfss t0if			;has timer 0 reached 0?
;	goto ServiceRX_FERR_1		;if not then jump
;	movlw TMR0_Count		;get delay value for 32.5 ms
;	movwf tmr0			;and load
;	bcf t0if			;clear tmr0 interrupt flag
;	bsf Tmr32us			;set 32.5 ms flag
;	bcf FERR_LED
ServiceRX_FERR_1
	btfsc OERR			;was there an over run with the frame error?
	goto ServiceRX_OERR		;if so jump
	goto INT_SRV_EXIT		;else goto exit ISR

ServiceRX_OERR
	movf RCREG, W			;clear out the RX buffer
	movf RCREG, W			;by reading it twice
	bcf CREN			;disable continous receive
	bsf CREN			;enable continous receive
	bsf OERR_LED			;turn on the over run LED
	bcf FERR_LED			;turn off the framing error LED
	bcf GOOD_DATA_LED		;turn off the good data LED
	bcf DMX_BREAK			;clear the beginning of frame flag
	goto INT_SRV_EXIT		;and jump to ISR exit

	org 700h
READ_EEROM
	;this routine reads the starting DMX channel and the number of channels
	;from eerom and to monitor and places it into TEMP_A and TEMP_B
	bcf RP0				;point to
	bsf RP1				;bank 2
	movlw 0				;point to low rode data in EEROM (00)
	movwf EEADRH			;High Address
	movwf EEADR			;Low Address to read
	bsf RP0				;point to bank 3
	bcf EEPGD			;point to Data memory
	bsf RD 				;Start read operation
	bcf RP0				;point to bank 2
	movf EEDATA, W			;move eedata into W
	movwf TEMP_A			;and into TEMP_A
	movlw 0				;point to high rode data in EEROM (01)
	movwf EEADRH			;High Address
	movlw 1				;point to high rode data in EEROM (01)
	movwf EEADR			;Low Address to read
	bsf RP0				;point to bank 3
	bcf EEPGD			;point to Data memory
	bsf RD 				;Start read operation
	bcf RP0				;point to bank 2
	movf EEDATA, W			;move eedata into W
	movwf TEMP_B			;and into TEMP_B
	bcf RP1				;point to bank 0
	return				;and return to caller

WRITE_EEROM
	;This routine writes the current content of TEMP_A and
	;TEMP_B into storage in the EEROM.
	;Normally this is a 2 step routine, here and an interrupt function.
	;Since this is a non-interrupt section of code, all writes to the EEROM
	;will be handled here, using a polling method.  The low byte
	;is written first.
WRITE_TEMP_A
	bsf RP0				;point to
	bsf RP1				;bank 3
WRITE_TEMP_A_1
	btfsc WR			;wait for write to finish
	goto WRITE_TEMP_A_1		;loop back if still writing
	bcf RP0				;point to bank 2
	movlw 0				;set write address to 00
	movwf EEADR			;low address
	movwf EEADRH			;high address
	movf TEMP_A,W			;move TEMP_A into W
	movwf EEDATA			;and into SFR
	bsf RP0				;point to bank 3
	bcf EEPGD			;point to Data memory
	bsf WREN			;enable writes
	movlw 55h			;write 55h to EECON2
	movwf EECON2			;
	movlw 0aah			;write aah to EECON2
	movwf EECON2			;
	bsf WR				;start write operation
	bcf WREN			;Disable writes
WRITE_TEMP_B
	bsf RP0				;point to
	bsf RP1				;bank 3
WRITE_TEMP_B_1
	btfsc WR			;wait for write to finish
	goto WRITE_TEMP_B_1		;loop back if still writing
	bcf RP0				;point to bank 2
	movlw 1				;set write address to 01
	movwf EEADR			;low address
	movlw 0				;set high address
	movwf EEADRH			;high address
	movf TEMP_B,W			;move TEMP_B into W
	movwf EEDATA			;and into SFR
	bsf RP0				;point to bank 3
	bcf EEPGD			;point to Data memory
	bsf WREN			;enable writes
	movlw 55h			;write 55h to EECON2
	movwf EECON2			;
	movlw 0aah			;write aah to EECON2
	movwf EECON2			;
	bsf WR				;start write operation
	bcf WREN			;Disable writes
	bsf RP0				;point to
	bsf RP1				;bank 3
WRITE_TEMP_B_2
	btfsc WR			;wait for write to finish
	goto WRITE_TEMP_B_2		;loop back if still writing
	bcf RP0				;point to
	bcf RP1				;bank 0
	return				;and return to caller


BCD_TO_BINARY
		;Convert the BCD code in Temp_C(1s), Temp_D(10s) and Temp_E(100s)
		;into binary.  Answer is stored in BCD_H_BYTE (256-65,000)
		;and BCD_L_BYTE (0-255).
        clrf    BCD_H_BYTE		;Clear high value
        movf    TEMP_E,W		;Move hundreds digit
        movwf   BCD_L_BYTE		;to low value
        call    Mult_x_10		;Multiply result by ten
        movf    TEMP_D,W		;Add tens digit
        addwf   BCD_L_BYTE,F		;to result
        call    Mult_x_10		;Multiply result by ten
        movf    TEMP_C,W		;Add ones digit
        addwf   BCD_L_BYTE,F		;to result
        btfsc   C			;Has the result overflowed ?
        incf    BCD_H_BYTE,F		;Yes, increment high byte
        return

MULT_X_10
        movf    BCD_L_BYTE,W		;Save
        movwf   Mult_Temp_L		;original
        movf    BCD_H_BYTE,W		;values
        movwf   Mult_Temp_H		;
        bcf     C			;Clear status
        rlf     BCD_L_BYTE,F		;Rotate to
        rlf     BCD_H_BYTE,F		;multiply by two
        bcf     C			;Clear status
        rlf     BCD_L_BYTE,F		;Rotate to
        rlf     BCD_H_BYTE,F		;multiply by two
        movf    Mult_Temp_L,W		;Load original low byte
        addwf   BCD_L_BYTE,F		;Add to new low byte
        btfss   C			;Did a carry occur?
        goto    CONTINUE		;No, continue....
        incf    BCD_H_BYTE,F		;Yes, increment high byte
CONTINUE
        movf    Mult_Temp_H,W		;Load original high byte
        addwf   BCD_H_BYTE,F		;Add to new high byte
        bcf     C			;Clear status
        rlf     BCD_L_BYTE,F		;Rotate to
        rlf     BCD_H_BYTE,F		;multiply by two
        return				;Data is now multiplied by ten

B2_BCD
	;routine to convert L_BYTE, H_BYTE from binary to BCD.  RO contains the 10,000's nibble
	;(right justified), R2 contains the 1000s and 100s nibbles and r3 contains the 10's and
	;1's nibbles.
	movf FSR, W			;get current FSR value
	movwf FSR_TEMP			;and store
	bcf C				;clear the C bit
	movlw 10h			;set the count to 16
	movwf B2_BCD_COUNT		;and store
	clrf R0				;clear the final storage registers
	clrf R1				;
	clrf R2				;last one
loop16
	rlf L_BYTE, F			;rotate low byte left once
	rlf H_BYTE, F			;rotate high byte left once
	rlf R2, F			;rotate high answer byte once left
	rlf R1, F			;rotate mid answer byte once left
	rlf R0, F			;rotate low answer byte once left
	decfsz B2_BCD_COUNT, F		;decrement count
	goto adjDEC			;if not zero then jump
	movf FSR_TEMP, W			;get old FSR value
	movwf FSR			;and restore
	retlw 0				;else return to caller
adjDEC
	movlw R2			;get the address of highest answer byte
	movwf FSR			;and store in FSR
	call adjBCD			;and call routine
	movlw R1			;get the address of middle answer byte
	movwf FSR			;store into FSR
	call adjBCD			;and call routine
	movlw R0			;get the address of lowest answer byte
	movwf FSR			;store into FSR
	call adjBCD			;and call routine
	goto loop16			;then loop back
adjBCD
	movlw 3				;load W with 3
	addwf 0,W			;add it to 0
	movwf B2_BCD_TEMP		;and store
	btfsc B2_BCD_TEMP, 3		;test the 4th bit
	movwf 0				;if set then move into reg 0
	movlw 30h			;load 30h into W
	addwf 0,W			;and add to register 0
	movwf B2_BCD_TEMP		;get B2_BCD_TEMP into W
	btfsc B2_BCD_TEMP, 7		;check bit 7
	movwf 0				;if set then get reg 0
	retlw 0				;and return

D_SUB
	call NEG_A			;first negate ACCa, then add
D_ADD
	movf ACCaLO, W			;get low byte into W
	addwf ACCbLO, F			;add LSB
	btfsc C				;add in carry
	incf ACCbHI, F			;by incrementing hi byte
	movf ACCaHI, W			;move high byte to W
	addwf ACCbHI, F			;and add other high byte
	retlw 0				;return to caller

NEG_A
	comf ACCaLO, F			;invert ACC lob byte
	incf ACCaLO, F			;then increment by one
	btfsc Z				;is it zero?
	decf ACCaHI, F			;if so subtract one from the high byte
	comf ACCaHI, F			;then invert the high byte
	retlw 0				;return to caller
end

