	list		P=16C54
	#include	<p16c5x.inc>

	__CONFIG	_CP_OFF & _WDT_ON & _HS_OSC

CPU     EQU     1654
SIM     EQU     0               ;Change timing constants for simulator

	IF	(CPU==1654) || (CPU==1655)
_RESVEC EQU     01FFH           ;16c54 start address
	ENDIF

	IF	CPU==1656
_RESVEC EQU     03FFH           ;16C56 start address
	ENDIF

	IF	CPU==1657
_RESVEC EQU     07FFH           ;16C57 start address
	ENDIF

;*** Reset Vector ***

	ORG     _RESVEC         ;
RESVEC  			;
	GOTO    INIT            ;

;*** Initialize Program ***

	ORG     0

;The following are variables I'll need
Address		EQU	08h	;Address of DMX device to send to
Counter		EQU	09h	;General counter, used throughout the program
CByte		EQU	0Ah	;Current Byte (Frame) being sent on DMX
CData		EQU	0Bh	;Current Data ???
CBit		EQU	0Ch	;Current Bit being sent
BOOL		EQU	0Dh	;A byte for Boolean storage

;The following are definitions for each bit in BOOL
AddressE	EQU	00h	;Current address extension, set for addresses between 255 and 511
CByteE		EQU	01h	;Current byte extension, set for addresses between 255 and 511

;The following are definitions of each pin in PORTA
DataPin		EQU	00h	;Port A, Bit 0, Pin 17.  Data in/out for RS-485.
				;Used here for output.
Upper512	EQU	02h	;Port A, Bit 2, Pin 1.  When high, send to upper 256 channels.
Monitor		EQU	03h	;Port A, Bit 3, Pin 2.  Monitor pin.  Blink an LED so 
				;they know it's working properly.  Perhaps to be used for Debug also.

INIT	movlw	0F6h		;Set all bits except bits 3 & 0
	tris	PORTA		;Set bits 3 and 0 as output (clear bit three and zero)
	bsf	PORTA, Monitor	;Turn the Monitor LED off
	movlw	0FFh	
	tris	PORTB		;Set all PORTB to input
	goto	MAIN

MAIN	movf	PORTB, W	;Move Port B to W	
	movwf	Address		;Move W to Address Register
	bcf	BOOL, AddressE	;Clear the Address Extension Bit
	btfsc	PORTA, Upper512	;If Upper512 is not set(high) then skip the next command
	bsf	BOOL, AddressE	;Set the Address Extension Bit
	
StartPacket
	clrwdt
	movlw	00h
	movwf	CByte		;Set current byte to 0
	bcf	BOOL, CByteE	;Set current byte extension to zero (first 256 channels)
	bcf	PORTA, DataPin	;Need to hold pin low for 88uS at the start of each packet
	movlw	058h		;Wait 88uS
	call	WaituS		;"""" """"
	bsf	PORTA, DataPin	;Bring the pin high for at least 8us
	movlw	008h		;Wait 8uS
	call	WaituS		;
	
	movlw	000h		;\Send the obligatory Null Value
	call	SendByte	;/
	movlw	000h		;\Set CByte to 0
	movwf	CByte		;/
	bcf	BOOL, CByteE	;Set the CByte Extension to 0

StartFrame
	incfsz	CByte, F	;Increment CByte
	goto 	nxt		;Go to the next frame sending if CByte is not zero
;	goto	nxtHigh		;If CByte is zero, we'll need to see if CByte extension is 1
	
nxtHigh	btfsc	BOOL, CByteE	;\If the CByte Extension is 1, then we've done all 512 dimmers
	goto	StartPacket	;/and should go to the next packet
	bsf	BOOL, CByteE	;Otherwise, just set the bit for next time
nxt	movf	Address, W	;Move intended address to w
	xorwf	CByte,w		;Exclusive or current channel with W
	btfss	STATUS, Z	;If anything is left in w, then they don't match
	goto	nxtbyte		;And you can go ahead and do the next byte
	movf	BOOL, W		;Otherwise, put the BOOL bits into W
	andlw	02h		;Single out the CByte extension
	btfsc	STATUS, Z	;If it's not zero, goto HighFound
	goto	HighFound	;
	btfsc	BOOL, AddressE	;\If it is zero, then see if AddressE is one.
	goto	nxtbyte		;/If addressE is one, they don't match, send a regular byte
	movf	PORTB, W	;\If addressE is zero, they match, send the dipswitch byte.
	call	SendByte	;/
	goto	StartFrame
	
HighFound
	btfsc	BOOL, AddressE;	;\if AddressE is zero, send a regualr byte
	goto	nxtbyte		;/
	movf	PORTB, W	;\If AddressE is one, then they match.  Send PortB
	bsf	PORTA, Monitor	;|Set the LED to on
	call	SendByte	;|
	bcf	PORTA, Monitor	;/Set the LED to off
	goto	StartFrame

nxtbyte	movlw	0AAh		;
	call	SendByte
	goto 	StartFrame
	
	
	;movf	PORTB, W
	;call	SendByte

	

	
	;bcf	PORTA, Monitor	;Set the LED to on
	;movlw	0ffh
	;call	WaituS
	;call	WaituS
	;bcf	PORTA, Monitor	;Set the LED to on
	;bsf	PORTA, Monitor	;Set the LED to off

	;goto	StartFrame

	;btfsc	BOOL, AddressE	;If AddressE is clear, skip the next command
	;bcf	PORTA, Monitor	;Set the LED to on

Endless	clrwdt
	goto	Endless
	
;Send Byte
;Input	W
;Uses	CData, CBit
;Output	W=0
;
;When called, sends the byte contained in W over the data pin with 
;1 Start Bit (low)
;8 Data Bits 
;2 Stop Bits (high)
;At a rate of 4uS per bit, or 250,000 bps

SendByte
	movwf	CData		;Put the byte to be sent in CData
	movlw	08h		;\Put 8 into CBit, so we can count the bit down
	movwf	CBit		;/
	
	bcf	PORTA, DataPin	;Set DataPin low for Start Bit
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop

loopSB	nop
	nop
	nop
	nop
	rlf	CData, F
	btfsc	STATUS, C
	call	SetHigh
	btfss	STATUS, C
	call	SetLow
	nop
	decfsz	CBit, F
	goto 	loopSB
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	bsf	PORTA, DataPin	;Set the datapin high for two stop bits
	movlw	08h		;\We'll wait 8uS before returning to make sure the stop bit 
	call	WaituS		;/is at least 8uS long before the next byte
	retlw	00h		;return 0
	
SetHigh	nop
	nop
	nop
	bsf	PORTA,DataPin
	retlw	00h	

SetLow	nop
	bcf	PORTA,DataPin
	nop
	nop
	retlw	00h


;Wait MicroSecond
;Input	W
;Uses	Counter
;Output	W = 0
;
;When called, it returns exactly 5*W instruction cycles after being called.
;This is used for uS timing on a 20MHz clock.
;Thus, the instruction
;call Waitus
;Will take 2 instructions
;This will return and go to the statement after the call 5*W instructions later.
;So 5*W + 2 instructions will complete whenever Call WaituS is called.


WaituS	movwf	Counter		;This will count W microseconds, and return exactly on the Wth uS
	decf	Counter,F
	nop
loopWS:	nop
	nop	
	decfsz	Counter,F
	goto 	loopWS
	nop
	retlw	00h

	end
