;************************************************************************
;                                                                     	*
;    Filename:	    dmx_basc.asm                                      	*
;    Date:          21/11/02                                          	*
;    File Version:   Version 2.1                                      	*
;                                                                     	*
;    Author:        Paul Harris                                       	*
;************************************************************************
;                                                                     	*
;    Notes:         This programme will take 4 analogue inputs       	*
;		     		and DMX data inputs                  	      		*
;                   And use them  it to phase control mains	      		*
;					If Basic =1 For Model with two Leds					*                    
;                   If basic =0 For Model with 7 Seg Display			*
;************************************************************************

	variable	basic=0				; If Basic =1 then basic version

	errorlevel 0, -302
	RADIX 	DEC		
	list      p=16f870            ; list directive to define processor
	#include <p16f870.inc>        ; processor specific variable definitions
	
	__CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _HS_OSC & _WRT_ENABLE_ON & _LVP_OFF & _DEBUG_OFF & _CPD_OFF 

; Programme constants

Start_Vector		EQU	.0
Interrupt_Vector	EQU .4
Common_Ram_Base	 	EQU	H'70'
Ram_Base	 		EQU	H'20'
Osc_Freq	 		EQU	.20000000	; Pic Frequency
Instruction_rate 	EQU Osc_Freq/.4	; Instruction Rate

; 	Phase control constants
Resolution	 		EQU	.256			; Analogue dimming resolution
Mains_freq	 		EQU	.100			; 100 Parts a second
Interupts_s	 		EQU Mains_freq*Resolution	; Interupts per second
Amount_to_cnt		EQU	Instruction_rate/Interupts_s	; number to count in timer0
Timer0_cnt	 		EQU	.256-Amount_to_cnt	; invert value to count (timer0 counts till overflow)
Delay_Value	 		EQU	.40

;	DMX Constants
Baud_Rate           EQU .250000
Baud_Rate_Constant  EQU (Osc_Freq/(.16*Baud_Rate))-.1
Number_Of_Channels  EQU .6
startcode			EQU	.0

;	Preset Constants
Max_Preset			EQU	.9		; Maxium Presets allowed (EEdata = max * 4 bytes)

; ***********	Define Flags   *************
;		IFlag
Break_Detected	equ 0	; Break detected
Start_Detected	equ 1	; Start Byte detected
Valid_Channel	equ 2	; Reached valid channels
No_DMX_Data		equ 7	; No recieved DMX Data

;		Flag

longcount	equ 0	; Long count flag (2.5s) when activated		
presetmode	equ 1	; Preset Mode on no DMX data
curve		equ 2	; S Curve selected
switch		equ 3	; Switch curve selected
DMX_Data	equ 4	; New DMX Data recieved
phase_done	equ 5	; Flag to show mains phase complete
dmx_error	equ 6	; Error detected in DMX tranmission
mains_fail	equ	7	; Maind Failure Flag

; 		Flag2
savepreset	equ 0	; save preset started flag 

;		DFlag	
dmx_recieve	equ 0	; Dmx recieve display
dmx_msb		equ 1	; Displaying DMX MSB
dmx_csb		equ 2	; Displaying DMX CSB
dmx_lsb		equ 3	; Displaying DMX LSB
preset_intro	equ 4	; Displaying Preset Intro

; control ports

#DEFINE		Zerocross	PORTB,0
#DEFINE		channel1op	PORTB,1
#DEFINE		channel2op	PORTB,2
#DEFINE		channel3op	PORTB,3
#DEFINE		channel4op	PORTB,4
#DEFINE     Data_Rec_LED    PORTC,4		; Not Used on 7 seg Pack  ***
#DEFINE		Data_Error_LED	PORTC,5		; Not Used on 7 seg Pack  ***
#DEFINE		display_clk		PORTC,5		; Not Used on Basic Version
#DEFINE		display_data	PORTC,4		; Not Used on basic Version


;***** VARIABLE DEFINITIONS
	CBLOCK Common_Ram_Base
	
	Int_W
	Int_Status
	Int_PCLath
	Int_FSR
	ee_address
	ee_data

	ENDC

	CBLOCK Ram_Base

;	Interupt Variables
	Iflag
	IH_Channel_Count_L
	IH_Channel_Count_H
	IH_Channels_Recieved
	IH_Temp
	IH_Long_Count		; Long duration count (2.5s)
	IH_Timer_Count
	IH_position_count
	IH_channel1cnt		; intertupt counts
	IH_channel2cnt
	IH_channel3cnt
	IH_channel4cnt

;	Programme variables
	countervalue		; Preset to load timer 1 from
	position_count		; Number of positions in last mains pulse
	Current_Preset		; Current Preset being displayed
	flag				; general flags
	flag2				; General flag
	dflag				; Display Flags
	Delay_Count			; Counter used in delay routien
	display_count		; Used for 7 Seg display
	displayvalue		; Used for 7 Seg display
	olddisplayvalue
	shadowa				; Port A shadow register
	oldporta			; Old Port a Value
	process_temp		; Process Tempory value
	tbllo				; Table Low Value
	NumH				; BIN -> BCD
	NumL				; BIN -> BCD
	Hund				; BIN -> BCD
	Tens_Ones			; BIN -> BCD
	dmx_hund			; BCD Value
	dmx_ten				; BCD Value
	dmx_one				; BCD Value
	DMX_Start_Addr_L	; DMX Start Address
    DMX_Start_Addr_H
    DMX_Start_Code		; DMX Start Code
    Channels			; Number of channels 
	
	channel1update		; Update values for interupt count
	channel2update
	channel3update
	channel4update
	
	Channel_Values : (Number_Of_Channels+2)
	
	ENDC


;**********************************************************************
		ORG     Start_Vector    	; processor reset vector
		nop			   				; Included for ICD
		clrf    PCLATH            	; ensure page bits are cleared
  		goto    Start              	; go to beginning of program


		ORG     Interrupt_Vector   	; interrupt vector location

		MOVWF   Int_W             	; Save PIC state
        SWAPF   STATUS,W
        CLRF    STATUS
        MOVWF   Int_Status
        MOVF    PCLATH,W
        MOVWF   Int_PCLath
        CLRF    PCLATH
        BCF     STATUS,IRP
        MOVF    FSR,W
        MOVWF   Int_FSR

IH_Interrupt_Poll
		btfsc 	INTCON,T0IF		; Test for timer0 interupt
		goto 	IH_Timer0		; Yes, Goto timer0 Handler
		btfsc 	PIR1,RCIF		; USART Interupt Pending ?
		goto	IH_Check_USART	; Yes, Goto Usart handler
		btfsc 	INTCON,INTF		; Test for RB0 Interupt
		goto 	IH_RB0
		btfsc	PIR1,TMR1IF		; Timer 1 interupt ??
		goto	IH_Timer1

IH_Exit  movf    Int_FSR,W		; Restore PIC state
         movwf   FSR
         movf    Int_PCLath,W
         movwf   PCLATH
         swapf   Int_Status,W
         movwf   STATUS
         swapf   Int_W,F
         swapf   Int_W,W
         retfie					; Return from interrupt

IH_Timer0
		movf 	countervalue,w
		movwf 	TMR0			; Reload counter0
								; Channel 1
		decf 	IH_channel1cnt,f; decrease channel 1 count
		btfsc 	STATUS,Z		; if zero then set output
		bcf 	channel1op		; set output
								; Channel 2
		decf 	IH_channel2cnt,f; decrease channel 2 count
		btfsc 	STATUS,Z		; if zero then set output
		bcf 	channel2op		; set output
								; Channel 3
		decf 	IH_channel3cnt,f; decrease channel 3 count
		btfsc 	STATUS,Z		; if zero then set output
		bcf 	channel3op		; set output
								; Channel 4
		decf 	IH_channel4cnt,f; decrease channel 4 count
		btfsc 	STATUS,Z		; if zero then set output
		bcf 	channel4op		; set output

		incf 	IH_position_count,f	; increse pulse count
		bcf 	INTCON,T0IF		; Clear interupt
		goto 	IH_Interrupt_Poll

IH_RB0	bsf 	STATUS,RP0		; change to bank 1
		btfsc 	OPTION_REG,INTEDG	; Test which edge of zerocross looking for
		goto 	IH_RB0_End		; 1 = rising edge

IH_RB0_Start
		bsf 	OPTION_REG,INTEDG	; set to look for Rising Edge
		bcf 	OPTION_REG,T0CS		; Enable timer 0
		bcf 	STATUS,RP0			; move back to bank 0
		bcf 	INTCON,INTF			; Clear interupt flag
		clrf 	IH_position_count	; clear pulse count
		bsf 	INTCON,T0IF			; Create timer Interupt
		clrf	TMR1L				; Clear Timer1
		clrf	TMR1H		
		bcf		flag,mains_fail		; and flags....
		
		btfsc 	PIR1,RCIF			; Is USART interrupt Pending ?
		goto 	IH_Check_USART		; Yes, Do USART rec bit before going to handler.
		incfsz 	IH_Timer_Count,f	; No, Increase No DMX Data Count	
		goto 	IH_Interrupt_Poll	; If NOT Zero then goto handler
	if basic == 1
		bcf 	Data_Rec_LED		; If Zero, Clear DMX data recieve LED
		bcf		Data_Error_LED		; And the DMX Error LED
	endif
		bcf		flag,DMX_Data		; Clear DMX recieve flag
		clrf	Iflag				; Clear any DMX data being recieved
		goto 	IH_Interrupt_Poll

IH_RB0_End
		bsf 	OPTION_REG,T0CS		; Disable Timer 0
		bcf 	INTCON,INTF			; Clear Interupt flag
		bcf 	OPTION_REG,INTEDG	; Set RB0 Interupt to falling edge
		bcf 	STATUS,RP0			; change to bank 0
		
		movlw	.254
		movwf 	PORTB				; clear ouputs
		movf 	channel1update,w	; reload channel count
		movwf 	IH_channel1cnt

		movf 	channel2update,w	; reload channel count
		movwf 	IH_channel2cnt
	
		movf 	channel3update,w	; reload channel count
		movwf 	IH_channel3cnt

		movf 	channel4update,w	; reload channel count
		movwf 	IH_channel4cnt

		movf 	IH_position_count,w	; save pulse count
		movwf 	position_count
		bsf 	flag,phase_done
		decfsz	IH_Long_Count,f		; Decrease Long Count
		goto 	IH_Interrupt_Poll
		bsf		flag,longcount		; set long count
		goto	IH_Interrupt_Poll	

IH_Check_USART
	   	bcf 	PIR1,RCIF			; Clear Interupt flag
		;bsf	Data_Rec_LED		; Set DMX Data LED
			
IH_Check_HW_Overrun
	    btfsc   RCSTA,OERR      ; Has a HW overrun occurred ?
        goto    IH_HW_Overrun   ; Yes, do a HW reset

IH_Check_9th_bit
		clrf	IH_Timer_Count		; Clear Timer count
		btfss 	RCSTA,RX9D			; Dose 9th Bit of data = 1, eg Break
		goto 	IH_Wait_Break		; Yes, start receiving again

IH_Check_SW_Overrun
	    btfsc   RCSTA,FERR         	; Has a framing error occurred ?
        goto    IH_SW_Overrun		; Yes, do a Usart reset

IH_Test_Flags
		btfsc 	Iflag,Valid_Channel	; Test to see if receiving valid channels
		goto	IH_Valid_Channel	; Yes, get next channel
		btfsc	Iflag,Start_Detected	; Test to see it start byte has arrived
		goto	IH_Wait_Channel		; Yes, Check Channel counts
		btfsc	Iflag,Break_Detected	; Test to see if break has arrived
		goto	IH_Wait_Start		; Yes, wait for start byte

IH_Wait_Break
		clrf	Iflag				; Clear all interupt flags
		movf	RCREG,w				; Move recieved data in to w
		btfsc	RCSTA,RX9D			; Test if break has arrived
		goto	IH_Interrupt_Poll	; No,  Break not detected
		btfsc	STATUS,Z			; Yes, Dose detected break =0 ?
		bsf 	Iflag,Break_Detected	; Yes, set flag to indicate break arrived
		goto	IH_Interrupt_Poll

IH_Wait_Start
		clrf	IH_Channels_Recieved	; Clear number of channels recieved
		clrf	IH_Channel_Count_L		; Clear Low channel count
		clrf	IH_Channel_Count_H		; Clear High channel count
		bsf		Iflag,Start_Detected	; Set flag to indicate Start Byte arrived
		movf	RCREG,w					; Check start code = 0
		btfss	STATUS,Z				;
		clrf	Iflag					; if No then clear flags and wait for next break
		goto	IH_Interrupt_Poll

IH_Wait_Channel
		movf	RCREG,w					; Store Recieved value in temp
		movwf	IH_Temp
		incf	IH_Channel_Count_L,f	; Increase channel count
		btfsc	STATUS,Z				; for both Low and High bytes
		incf	IH_Channel_Count_H,f	;
		movf	IH_Channel_Count_H,w	; Compare the high byte of channel count to 			
		xorwf	DMX_Start_Addr_H,w		; DMX start address
		btfss	STATUS,Z				; If Not equal then exit
		goto	IH_Interrupt_Poll
		movf	IH_Channel_Count_L,w	; Compare the low byte of channel count to 
		xorwf	DMX_Start_Addr_L,w		; DMX Start address
		btfss	STATUS,Z				; if not equal then exit
		goto	IH_Interrupt_Poll
		bsf		Iflag,Valid_Channel		; if address equal then set valid channels		
		movf	IH_Temp,w
		movwf	Channel_Values			; Store value in first channel
		incf	IH_Channels_Recieved,f	; and increase count
		goto	IH_Interrupt_Poll

IH_Valid_Channel
		movlw	Channel_Values			; Load address of memory block
		addwf	IH_Channels_Recieved,w	; add channel offset
		movwf	FSR						; and move in to FSR
		movf	RCREG,w					; Store result in the 	
		movwf	INDF					; channel position in memory
		movf	IH_Channels_Recieved,w	;
		incf	IH_Channels_Recieved,f	; Increase count (Note No effect on w !)
		xorwf	Channels,w				; Check if all channels recieved
		btfss	STATUS,Z				; 
		goto	IH_Interrupt_Poll		; No, then return to interupt poll
		clrf	Iflag					; Yes, Clear flags and wait for break
	if basic == 1
		bsf		Data_Rec_LED			; Set DMX Data LED
	endif
		bsf		flag,DMX_Data			; Set DMX Data recieve flag
		goto 	IH_Interrupt_Poll		; exit back to Handler		

IH_HW_Overrun
    	bcf		RCSTA,CREN            	; Reset UART
        bsf  	RCSTA,CREN            	; receive logic
        bsf  	flag,dmx_error        	; Turn on hardware overrun LED
	if basic == 1
		bsf		Data_Error_LED			; Turn on DMX Error led
	endif
		goto 	IH_Check_9th_bit

IH_SW_Overrun
	    bcf     RCSTA,CREN            	; reset UART
        bsf     RCSTA,CREN            	; receive logic
		bsf		flag,dmx_error			; Turn on software Overrun Led
	if basic == 1	
		bsf		Data_Error_LED			; Turn on DMX Error led
	endif
		goto    IH_Test_Flags

IH_Timer1						; Mains Phase Fail
		bcf		PIR1,TMR1IF		; Clear interupt flag
		bsf		flag,mains_fail	; Set Mains Fail Flag
		movlw	.254
		movwf 	PORTB				; clear ouputs
		goto	IH_Exit

; ---------------------------------------------------------------------------

seg_table					; Table for 7 Segment display
		addwf	PCL,f			; Place before possible programme
		retlw .129 	; 0
		retlw .243 	; 1
		retlw .73 	; 2
		retlw .97 	; 3
		retlw .51 	; 4		; Web Site Version
		retlw .37 	; 5
		retlw .7 	; 6
		retlw .241 	; 7
		retlw .1 	; 8
		retlw .49 	; 9
		retlw .67 	; d
		retlw .17 	; A
		retlw .25 	; P
		retlw .13 	; E
		retlw .79 	; c
		retlw .23 	; h
		retlw .255 	; <OFF>


		
; ---------------------------------------------------------------------------
Start   clrf 	PORTA           ; \
        movlw	.254            ;  Clear ports
        movwf	PORTB			;
		clrf 	PORTC           ; /
		clrf 	flag			; Clear flag register
		clrf	flag2
		clrf 	Iflag			; Clear Interupt flag
		clrf	dflag			; Clear Display Flags
		clrf	DMX_Start_Addr_L; Clear DMX Address
		clrf	DMX_Start_Addr_H;
		clrf	Current_Preset
		clrf	olddisplayvalue
		clrf	STATUS			; Clear status
		
		bsf   	STATUS,RP0      ; Set up port I/O directions
        movlw 	B'11111111'		; 1 = Input    0 = Output
        movwf 	TRISA			; Make PORTA all input
        movlw 	B'00000001'
        movwf 	TRISB			; Make PORTB all Output expect PB0
        movlw 	B'000000000'	; Set AN0 - AN4 As analogue inputs left justified
        movwf 	ADCON1
		movlw 	B'11001000'		; set up options - Timer0 from instruction cycle clock with
		movwf 	OPTION_REG		; no prescaler

Get_DMX_Address
		movlw	B'10001111'		; Set Up Switch directions
		movwf	TRISC
		bcf		STATUS,RP0		; Go back to bank 0
		nop
		movlw	B'00010000'		; Enable first bank of switches
		movwf	PORTC
		call	Delay			; Go for a little delay
		movf	PORTC,w			; Read Port C
		andlw	B'00001111'		; Mask un required bits
		movwf	DMX_Start_Addr_L; Store in addrees Low
		
		movlw	B'00100000'		; Get next bank of switches
		movwf	PORTC		
		call	Delay
		swapf	PORTC,w			; Read switches and swap nibbles
		andlw	B'11110000'		; Mask undesirables
		iorwf	DMX_Start_Addr_L,f	; Store Higher nibble
		
		movlw	B'01000000'		; Get final bank of switches
		movwf	PORTC
		call	Delay
		movf	PORTC,w			; get switches
		andlw	B'00001111'		; mask narstry bits
		movwf	process_temp
		andlw	B'00001110'		; store other switch settings in flags.
		movwf	flag
		btfsc	process_temp,0	; look for high address bit.
		incf	DMX_Start_Addr_H,f	; and set if required
				
		clrf	PORTC			; Clear Port C
		movf	DMX_Start_Addr_H,w
		movwf	NumH			; Load BIN -> BCD Converter
		movf	DMX_Start_Addr_L,w
		movwf	NumL
		call 	bin2dec999fast	; Get BCD version of DMX Start Address	
	if basic == 1				; ONLY DO FOR BASIC PACK
		bcf 	Data_Rec_LED	; Turn off Data Recieve LED
		bcf		Data_Error_LED	; Turn Off DMX Error LED
	endif

store_Number_channels
		movlw	Number_Of_Channels	
		movwf	Channels	; Load Number of channels to recieve and store

; Initialize UART
		bsf     STATUS,RP0
        movlw   Baud_Rate_Constant
        movwf   SPBRG
        bsf     TXSTA,BRGH
        bcf     TXSTA,SYNC
        bsf     PIE1,RCIE
        bcf     STATUS,RP0
        bsf     RCSTA,RX9
        bsf     RCSTA,CREN
        bsf     RCSTA,SPEN
		movlw 	B'10000001'		; Switch on the ADC channel RA0 20Mhz crystal
		movwf 	ADCON0
		movlw 	Timer0_cnt
		movwf 	countervalue	; load counter reload variable
		movwf 	TMR0			; Load counter
		bsf 	OPTION_REG,T0CS	; Disable timer 0
		movlw	B'00110001'		; Setup Timer1
		movwf	T1CON			; 1:8 Prescale - internal osc...
		clrf	TMR1L			; Clear Timer
		clrf	TMR1H
		bsf		STATUS,RP0		; Bank 1
		bsf		PIE1,TMR1IE		; Enable Timer 1 Interupt
		bcf		STATUS,RP0

; Interrupts
		clrf 	INTCON
		bsf		INTCON,PEIE
		bsf 	INTCON,INTE		; Enable RB0 Interupt
		bsf		INTCON,T0IE		; Enable Timer0 Interrupts
		bsf 	INTCON,GIE		; Enable global interrupts

; -----------------------------------------------------------------
Main			
		btfsc	flag,mains_fail		; Is Mains Ok ??????
		call	D_Mains_Fail		; No,

		btfsc 	flag,DMX_Data		; Is DMX Data being recieved ?
		goto 	load_update_reg		; Yes, then just updata channels
	
	if basic == 0					; ONLY DO FOR Normal PACK	
		btfsc	flag,presetmode		; Is preset mode selected ???   ***
		goto	preset_mode			; Yes,				***
	endif	
	
Get_Analogue_Values					; No, get Analogue values
		movlw 	B'10000001'			; select Channel 1 in A2D
		movwf 	ADCON0
		call 	Delay
		bsf 	ADCON0,GO			; start ADC conversion
		nop
		nop
wait1	btfsc 	ADCON0,GO			; Loop till conversion complete
		goto 	wait1
		movf 	ADRESH,w			; get and
		movwf 	Channel_Values		; store channel 1 
		nop

		movlw 	B'10001001'			; select Channel 2 in A2D
		movwf 	ADCON0
		call 	Delay
		bsf 	ADCON0,GO			; start ADC conversion
		nop
		nop
wait2	btfsc 	ADCON0,GO			; Loop till conversion complete
		goto 	wait2
		movf 	ADRESH,w			; get and
		movwf 	(Channel_Values+1)	; store channel 2 
		nop

		movlw 	B'10010001'			; select Channel 3 in A2D
		movwf 	ADCON0
		call	Delay
		bsf 	ADCON0,GO			; start ADC conversion
		nop
		nop
wait3	btfsc 	ADCON0,GO			; Loop till conversion complete
		goto 	wait3
		movf 	ADRESH,w			; get and
		movwf 	(Channel_Values+2)	; store channel 3 
		nop

		movlw 	B'10011001'			; select Channel 4 in A2D
		movwf 	ADCON0
		call 	Delay
		bsf 	ADCON0,GO			; start ADC conversion
		nop
		nop
wait4	btfsc 	ADCON0,GO			; Loop till conversion complete
		goto 	wait4
		movf 	ADRESH,w			; get and
		movwf 	(Channel_Values+3)	; store channel 4 
		
load_update_reg		
		movf 	Channel_Values,w	; copy and invert value from Channel 1
		call	process_curve		; Get value form curve
		movwf 	channel1update
				
		movf 	(Channel_Values+1),w; copy and invert value from Channel 2
		call	process_curve		; Get value from curve
		movwf 	channel2update	
		
		movf 	(Channel_Values+2),w; copy and invert value from Channel 3
		call	process_curve		; Get Value from curve
		movwf 	channel3update
			
		movf 	(Channel_Values+3),w; copy and invert value from Channel 4
		call	process_curve		; Get value from curve
		movwf 	channel4update
				
		clrf	PCLATH				; Clear PCLATH from scurve.		
		btfss 	flag,phase_done		; is phase complete ??
		goto 	Main				; No,
		call 	find_countervalue	; Yes, update counter value
	
	if basic == 0					; ONLY DO FOR Normal PACK
		call 	display				; Do display                ***
	endif

		goto 	Main

; *******************************************************
; *		Preset Mode				*
; *******************************************************
preset_mode
		bsf		STATUS,RP0			; Move to bank 1
		movlw	B'00000110'			; Set port A as digital inputs.
		movwf	ADCON1
		bcf		STATUS,RP0			; return to bank 0
		nop							; delay to reset porta
		nop
		movf	PORTA,w				; copy port A in to shadowa
		movwf	shadowa
		xorwf	oldporta,w			; look for changes
		andwf	shadowa,w			; look for rising edge only.
		movwf	oldporta			; and store in oldporta !
		btfsc	oldporta,4			
		call	channel5
		btfsc	oldporta,5
		call 	channel6
		movf	shadowa,w
		movwf	oldporta
		btfss	flag2,savepreset	; if save preset active then 
		goto 	load_update_reg
		bsf		STATUS,RP0			; move to bank 1
		movlw	B'00000010'			; set PORTA back to Analogue
		movwf	ADCON1	
		bcf		STATUS,RP0			; return to bank 0
		nop							; Delay to reset
		nop				
		goto	Get_Analogue_Values ; display analogue values		

channel5
		btfsc	flag2,savepreset	; Is save preset in progress
		goto	save_to_ee			; Yes, 
		btfsc	shadowa,5			; No, both buttons pressed ??
		goto	save_preset			; Yes,
		movf	Current_Preset,w	; No, Load Current Preset in to Status register
		movlw	Max_Preset+1		; set up w with new value		
		btfsc	STATUS,Z			; current preset = 0 ??
		movwf	Current_Preset		; Yes, reload with maxium value then
		decf	Current_Preset,f	; No, decrease current preset
		goto	update_preset

channel6
		btfsc	flag2,savepreset		; Is save preset in progress
		goto	save_to_ee			; Yes,
		btfsc	shadowa,4			; No, Both buttons presed ?
		goto	save_preset			; Yes,
		incf 	Current_Preset,f	; No, Increse present preset
		movf	Current_Preset,w
		sublw	Max_Preset			; subtract max preset from preset
		btfsc	STATUS,C			; To Large ??
		goto	update_preset
		clrf	Current_Preset

update_preset
		movf	Current_Preset,w	; Move current preset to ee_address (in all Mem)
		movwf	ee_address
		rlf		ee_address,f			; * 4.
		rlf		ee_address,f		
		call	ee_read				; Get channel 1 value
		movwf	(Channel_Values)
		incf	ee_address,f	
		call	ee_read				; Get channel 2 value
		movwf	(Channel_Values+1)
		incf	ee_address,f
		call	ee_read				; Get channel 3 Value
		movwf	(Channel_Values+2)
		incf	ee_address,f
		call	ee_read				; Get channel 4 Value
		movwf	(Channel_Values+3)
		return
save_preset
		bsf		flag2,savepreset			; Set save preset mode
		return

save_to_ee
		btfss	shadowa,4			; Check CH5 is selected.
		return						; No,
		btfss	shadowa,5			; Check CH6 is selected
		return						; No,
		movf	Current_Preset,w	; Yes, Both channels
		movwf	ee_address			; set up EEaddress with current preset
		rlf		ee_address,f		;          * 4
		rlf		ee_address,f
		movf	(Channel_Values),w
		movwf	ee_data
		call	ee_write			; save Channel 1 Value
		incf	ee_address,f
		movf	(Channel_Values+1),w
		movwf	ee_data
		call	ee_write			; save Channel 2 Value
		incf 	ee_address,f
		movf	(Channel_Values+2),w
		movwf	ee_data
		call 	ee_write			; Save Channel 3 Value
		incf	ee_address,f
		movf	(Channel_Values+3),w
		movwf	ee_data
		call	ee_write			; save Channel 4 Value
		bcf		flag2,savepreset		; Clear flag
		clrf	oldporta			; to prevent rerunning
		return

; *********************************************************
; *                  Display Errors						  *
; *   Input - flags	             Output - Nothing	  	  *
; *********************************************************
D_Mains_Fail
	if basic == 1
		bsf 	Data_Rec_LED		; Switch On Both LEDs
		bsf		Data_Error_LED		; 	
	else
		movlw	.15					; Display a F for Mains Fail
		call	seven_seg

	endif
		bcf		INTCON,T0IE			; Disable Timer0 Interrupts
D_No_Mains_Loop						; No Mains Loop........
		btfsc	flag,mains_fail
		goto	D_No_Mains_Loop
		call	Delay
		bsf		INTCON,T0IE			; Enable Timer0 Interrupts
		return

; ***********************************************
; *        Display Routien                      *
; * Input - Control flags     output - Nothing  *
; ***********************************************

display
		btfsc	flag,DMX_Data		; Dmx Currently ??
		goto	dmx_display			; Yes,
		movlw	B'11110000'			; No, Clear dmx part of dflag
		andwf	dflag,f
		bcf		flag,dmx_error		; clear dmx error flag
		btfsc	flag,presetmode		; In Preset Mode Currently
		goto	preset_display		; Yes,

analogue_display				; No,
		movlw	.11			; Display A
		goto 	seven_seg

dmx_display
		bcf		dflag,preset_intro
		btfsc	flag,dmx_error		; Dmx error recieved ??
		goto	display_error		; Yes,
		btfsc	dflag,dmx_lsb		; Displaying LSB ??
		goto	display_d			; Yes,
		btfsc	dflag,dmx_csb		; Displaying CSB ??
		goto 	display_lsb			; Yes,
		btfsc	dflag,dmx_msb		; Displaying MSB ??
		goto	display_csb			; Yes,
		btfsc	dflag,dmx_recieve	; Displaying New d ??
		goto	display_msb			; Yes,
		clrf	IH_Long_Count
		bcf		flag,longcount		; Clear and reset Long Count
		bsf		dflag,dmx_recieve
		movlw	.10					; display d.
		goto	seven_seg

display_msb
		btfss	flag,longcount		; Has long count finished ??
		return						; No,
		clrf	IH_Long_Count		; Yes, reset long count
		bcf		flag,longcount	
		bsf		dflag,dmx_msb		; set display flag
		movf	dmx_hund,w			; and display
		goto 	seven_seg

display_csb
		btfss	flag,longcount		; Has long count finished ??
		return						; No,
		clrf	IH_Long_Count		; Yes, reset long count
		bcf		flag,longcount	
		bsf		dflag,dmx_csb		; set display flag
		movf	dmx_ten,w			; and display
		goto 	seven_seg

display_lsb
		btfss	flag,longcount		; Has long count finished ??
		return						; No,
		clrf	IH_Long_Count		; Yes, reset long count
		bcf		flag,longcount	
		bsf		dflag,dmx_lsb		; set display flag
		movf	dmx_one,w			; and display
		goto 	seven_seg

display_d
		btfss	flag,longcount		; Has long count finished ??
		return
		movlw	.10					; Value for d
		goto	seven_seg			; And display

display_error	movlw	.13			; Value for E
		goto	seven_seg			; and display

preset_display
		btfsc	flag2,savepreset	; Preset Save taking Place ??
		goto 	display_save		; Yes,
		btfsc	dflag,preset_intro	; Done Intro Yet ??
		goto	display_current_preset	; Yes,

display_p
		bsf		dflag,preset_intro	;
		clrf	IH_Long_Count		; clear and reset long count.
		bcf		flag,longcount 
		movlw	.12					; Value for p
		goto	seven_seg

display_current_preset
		btfss	flag,longcount		; Wait for long count
		return
		movf	Current_Preset,w	; display current preset (0 - 9)
		goto 	seven_seg			

display_save	movlw	.14			; Save chacture = c
		goto	seven_seg												
		


; ***********************************************
; *          7 Segment Display Drive		*
; *	Input - w	    Output = Nothing    *
; ***********************************************
seven_seg
		movwf	displayvalue
		xorwf	olddisplayvalue,w	; Has display value changed ?
		btfsc	STATUS,Z		; 
		return				; No,	
						; Yes, Display neww value
		movf	displayvalue,w		
		movwf	olddisplayvalue		; Update old display value
		call 	seg_table
		movwf	displayvalue
		movlw	.8
		movwf	display_count
seven_loop
		bcf		display_clk		; End of clock pulse
		nop
		btfsc	displayvalue,0		; Set next data output
		bsf		display_data
		btfss	displayvalue,0
		bcf		display_data
		nop
		nop
		rrf		displayvalue,f		; set up next data value
		nop
		bsf		display_clk		; start of clock pulse
		nop
		nop
		decfsz	display_count,f		; all data done yet ??
		goto 	seven_loop
		
		return

; *************************************************
; *        Find counter value required		  *
; * Input - position_count  output - countervalue *
; *************************************************

find_countervalue				; find amount left on counter and adjust counter
								; value to make counter = 255 at end.
		bcf 	flag,phase_done	; do this only after new mains cycle.
		btfss 	position_count,7; if position count >128 then decrese count		
		goto 	lower_count		; else increase count

higher_count	movf 	position_count,w		
		sublw 	.255			; Sutract 254 from positioncount
		btfsc 	STATUS,C		; if < 0 then 			
		incf 	countervalue,f	; increase count
		return

lower_count	movf 	position_count,w		
		sublw 	.1				; Sutract 2 from positioncount
		btfss 	STATUS,C		; if > 0 then 			
		decf 	countervalue,f	; decrease count
		return

; ******************************************************
; *		EEREAD                                 *
; *                                                    *
; * ee_address = Address in EEPROM  w = data read      *
; ******************************************************

ee_read	
		bsf		STATUS,RP1		; Move to bank 2
		movf	ee_address,w
		movwf	EEADR			; Store eeaddress in correct location	
		bsf 	STATUS,RP0		; Go to Bank 3
		bcf		EECON1,EEPGD	; Point to Data Memory
		bsf 	EECON1,RD		; Start EEprom read cycle
		bcf 	STATUS,RP0		; Back to bank 2
		movf 	EEDATA,w
		bcf 	STATUS,RP1		; Bank to bank 0
		return

; ******************************************************
; *              EEWRITE                               *
; *                                                    *
; *  EEadr = Address in EEPROM eedata = data to write  *
; ******************************************************

ee_write
		bcf		PIR2,EEIF		; clear EE interupt flag
		bsf		STATUS,RP1		; Move to bank 2
		bcf		STATUS,RP0		;
		movf	ee_address,w
		movwf	EEADR			; Save eeaddress
		movf	ee_data,w
		movwf 	EEDATA			; save eedata		
		bsf 	STATUS,RP0		; Move to bank 3
		bcf		INTCON,GIE		; Disable interupts
		bcf		EECON1,EEPGD	; Access Data Memory
		bsf 	EECON1,WREN		; put WREN
		movlw 	H'55'
		movwf 	EECON2
		movlw	H'AA'
		movwf 	EECON2
		bsf 	EECON1,WR		; write cycle started
		bcf		STATUS,RP0		; goto Bank 0
		bcf		STATUS,RP1
wr1		clrwdt
		btfss 	PIR2,EEIF		; wait for EE write interupt flag
		goto 	wr1				; write cycle wait
		bsf		INTCON,GIE		; Enable all interupts
		return

; ***********************************************
; * Fast binary to decimal conversion (0..999)	*
; *						*
; *  Input: NumH:NumL				*
; * Output Hund:Tens_Ones (packed BCD)		*
; *						*
; * Size: 59 instructions			*
; * Execution time (with return): 60		*
; *						*
; * 8-July-2000 by Nikolai Golovchenko		*
; * Based on 8bit BIN2BCD of Scott Dattalo	*
; ***********************************************
bin2dec999fast
        swapf	NumL,w		;Add the upper and lower nibbles
        addwf	NumL,w		;to get the one's digit
        andlw	0x0F
        skpndc				;Go through a binary to bcd
        addlw	0x16		;conversion for just the one's
        skpndc				;digit
        addlw	0x06
        addlw	0x06
        skpdc
        addlw	-0x06

        btfsc	NumL,4   	;bit 4 is a special case
        addlw	0x16 - 1 + 0x6
        skpdc
        addlw	-0x06		;now adjust the ten's digit
        btfsc	NumL,5		;2^5 = 32, so add 3 to the ten's
        addlw	0x30		;digit if bit 5 is set
        btfsc	NumL,6		;2^6 = 64, so add 6
        addlw	0x60		;if bit 6 is set
		btfsc	NumL,7		;2^7 = 128, so add 2 (the ten's
		addlw	0x20		;digit) if bit 7 is set
		addlw	0x60		;convert the ten's digit to bcd
		clrf	Hund
		rlf		Hund,f		;if there's a carry, then the input
		btfss	Hund,0		;was greater than 99.
		addlw	-0x60
		movwf	Tens_Ones
		movlw	0x66		;2^8 = 256, so add 0x56 to Tens_Ones
		btfsc	NumH,0
		movlw	0x56 + 0x66	;add 0x66 for decimal adjust
		addwf	Tens_Ones,f
		skpnc
		incf	Hund,f
		clrw
		skpc
		iorlw	0x60
		skpdc
		iorlw	0x06
		subwf	Tens_Ones,f
		movlw	0x66		;2^9 = 512, so add 0x12 to Tens_Ones
		btfsc	NumH,1
		movlw	0x12 + 0x66
		addwf	Tens_Ones,f
		skpnc
		incf	Hund,f
		clrw
		skpc
		iorlw	0x60
		skpdc
		iorlw	0x06
		subwf	Tens_Ones,f
		btfsc	NumL,7		;finish with hundreds
		incf	Hund,f
		movlw	2
		btfsc	NumH,0
		addwf	Hund,f
		movlw	5
		btfsc	NumH,1
		addwf	Hund,f

split
		movf	Hund,w
		movwf	dmx_hund
		movf 	Tens_Ones,w
		andlw 	0Fh
		movwf	dmx_one
		swapf	Tens_Ones,w
		andlw	0Fh
		movwf	dmx_ten
		        
		return

; *******************************************************
; *		Delay Loop 				*
; *     No Input		No Output		*
; *******************************************************
Delay
		movlw	Delay_Value
		movwf	Delay_Count
Delay_Loop
		decfsz 	Delay_Count,f
		goto 	Delay_Loop
		return		

; *******************************************************
; *             Process Required Curve			*
; *   Input - w     controls in flag   output in w	*
; *         Inverts input to output
; *******************************************************
process_curve
	
		movwf	process_temp		; Save value in w
		btfsc	flag,switch			; Switching required ??
		goto	process_switching	; yes,
		btfsc	flag,curve			; Cuve or linear ??
		goto 	process_scurve		; Curve
process_linear
		comf	process_temp,w		; invert value in to w
		btfsc	STATUS,Z			; If zero then
		movlw	.1					; make value = 1
		return		

process_switching
		btfss	process_temp,7		; Look for 50 % value
		retlw	.254				; < 50 % ( inverted value) 
		retlw	.1					; > 50 % ( inverted value)

process_scurve						; Do table lookup.
		movwf	tbllo				; Store low table value
		movlw	HIGH (tablestart)	; Get High Table value
		movwf	PCLATH				; store High Table value
		movlw	Low (tablestart)	; add lower offset to low value
		addwf	tbllo,w				;
		btfsc	STATUS,C			; Carry from the addition ?
		incf	PCLATH,f			; yes,
		;movf	tbllo,w
		;call 	do_table		
		;clrf	PCLATH
		;return
		;addwf 	PCL,f				; Do Jump

		movwf	PCL					; Do Jump
tablestart	
		retlw .255
		retlw .249
		retlw .243
		retlw .238
		retlw .234
		retlw .230
		retlw .227
		retlw .223
		retlw .221
		retlw .218
		retlw .215
		retlw .213
		retlw .211
		retlw .209
		retlw .207
		retlw .205
		retlw .203
		retlw .202
		retlw .200
		retlw .198
		retlw .197
		retlw .195
		retlw .194
		retlw .193
		retlw .191
		retlw .190
		retlw .189
		retlw .188
		retlw .187
		retlw .185
		retlw .184
		retlw .183
		retlw .182
		retlw .181
		retlw .180
		retlw .179
		retlw .178
		retlw .177
		retlw .176
		retlw .175
		retlw .175
		retlw .174
		retlw .173
		retlw .172
		retlw .171
		retlw .170
		retlw .169
		retlw .169
		retlw .168
		retlw .167
		retlw .166
		retlw .166
		retlw .165
		retlw .164
		retlw .163
		retlw .163
		retlw .162
		retlw .161
		retlw .161
		retlw .160
		retlw .159
		retlw .159
		retlw .158
		retlw .157
		retlw .157
		retlw .156
		retlw .155
		retlw .155
		retlw .154
		retlw .154
		retlw .153
		retlw .152
		retlw .152
		retlw .151
		retlw .151
		retlw .150
		retlw .149
		retlw .149
		retlw .148
		retlw .148
		retlw .147
		retlw .147
		retlw .146
		retlw .145
		retlw .145
		retlw .144
		retlw .144
		retlw .143
		retlw .143
		retlw .142
		retlw .142
		retlw .141
		retlw .141
		retlw .140
		retlw .139
		retlw .139
		retlw .138
		retlw .138
		retlw .137
		retlw .137
		retlw .136
		retlw .136
		retlw .135
		retlw .135
		retlw .134
		retlw .134
		retlw .133
		retlw .133
		retlw .132
		retlw .132
		retlw .131
		retlw .131
		retlw .130
		retlw .130
		retlw .129
		retlw .129
		retlw .128
		retlw .128
		retlw .127
		retlw .127
		retlw .126
		retlw .126
		retlw .125
		retlw .125
		retlw .124
		retlw .124
		retlw .123
		retlw .123
		retlw .122
		retlw .122
		retlw .121
		retlw .121
		retlw .120
		retlw .120
		retlw .119
		retlw .119
		retlw .118
		retlw .118
		retlw .117
		retlw .117
		retlw .116
		retlw .116
		retlw .115
		retlw .115
		retlw .114
		retlw .114
		retlw .113
		retlw .113
		retlw .112
		retlw .112
		retlw .111
		retlw .111
		retlw .110
		retlw .110
		retlw .109
		retlw .109
		retlw .108
		retlw .108
		retlw .107
		retlw .107
		retlw .106
		retlw .106
		retlw .105
		retlw .105
		retlw .104
		retlw .104
		retlw .103
		retlw .103
		retlw .102
		retlw .102
		retlw .101
		retlw .100
		retlw .100
		retlw .99
		retlw .99
		retlw .98
		retlw .98
		retlw .97
		retlw .97
		retlw .96
		retlw .95
		retlw .95
		retlw .94
		retlw .94
		retlw .93
		retlw .92
		retlw .92
		retlw .91
		retlw .91
		retlw .90
		retlw .89
		retlw .89
		retlw .88
		retlw .87
		retlw .87
		retlw .86
		retlw .85
		retlw .85
		retlw .84
		retlw .83
		retlw .83
		retlw .82
		retlw .81
		retlw .81
		retlw .80
		retlw .79
		retlw .78
		retlw .78
		retlw .77
		retlw .76
		retlw .75
		retlw .74
		retlw .74
		retlw .73
		retlw .72
		retlw .71
		retlw .70
		retlw .69
		retlw .68
		retlw .68
		retlw .67
		retlw .66
		retlw .65
		retlw .64
		retlw .63
		retlw .62
		retlw .61
		retlw .59
		retlw .58
		retlw .57
		retlw .56
		retlw .55
		retlw .54
		retlw .52
		retlw .51
		retlw .50
		retlw .48
		retlw .47
		retlw .45
		retlw .43
		retlw .42
		retlw .40
		retlw .38
		retlw .36
		retlw .34
		retlw .32
		retlw .30
		retlw .27
		retlw .25
		retlw .22
		retlw .19
		retlw .16
		retlw .12
		retlw .8
		retlw .3
		retlw .0
		retlw .0
		retlw .0
		retlw .0
		retlw .0
		END                       ; directive 'end of program'
