	list    p=PIC16C55
;*******************************************************************
;                           MC.ASM
; Data stream converter for VLA ACU and FRM
;*******************************************************************
;Copyright (C) 2003 Bob Broilo, National Radio Astronomy Observatory
;
;This program is free software;  you can redistribute it and/or
;modify it under the terms of the GNU General Public License
;as published by the Free Software Foundation;  either version 2
;of the License, or (at your option) any later version.
;
;This program is distributed in the hope that it will be useful,
;but WITHOUT ANY WARRANTY;  without even the implied warranty of
;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;GNU General Public License for more details.
;
;You should have received a copy of the GNU General Public License
;along with this program; if not, write to the Free Software
;Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
;
;Bob Broilo - bbroilo@nrao.edu
;PO Box 0, Socorro NM  87801
;
;*******************************************************************
; Write "S" or "Q" commands to ACU or FRM.  If "Q", reads "S" data
; back from ACU or FRM.
;
; Clock freq 8MHz => inst speed 2MHz => cycle time 0.5us
;
; Bob Broilo & El Blat
; Adapted from buffer.asm and enc1x.asm rev 11/3/2000
; 5/27/2004
;*******************************************************************
;
;
;*******************************************************************
; Macros
;*******************************************************************
DELAY	macro	arg
	variable i
i = 0
	while i < arg
	nop
i += 1
	endw
	endm
;
;*******************************************************************
; defines
;*******************************************************************
;
; status register
status  equ     03	; status register
scarry  equ     0       ;       s0      carry bit
sdigit  equ     1       ;       s1      digit carry bit
szero   equ     2       ;       s2      zero bit
;
; porta
mcp	equ     05      ; pins  porta - M&C port
rx	equ     0       ; 6     a0 I	M&C receive
tx_i	equ	1	; 7	a1 O	M&C transmit to ACU or FRM
par	equ	2	; 8	a2 O	M&C parity error
err	equ	3	; 9	a3 O	M&C timeout/general error
;
; portb
ctlp    equ     06      ; pins  portb - control port
i_err	equ	0	; 10	b0 O	interface error
test	equ	1	; 11	b1 O	test output for debugging
clk	equ	5	; 15	b5 I	Host clock input
wr_rdy	equ	6	; 16	b6 O	PIC Write Ready
rd_rdy	equ	7	; 17	b7 O	PIC Read Ready
;
; portc
datap   equ     07      ; 18-25 portc I/O - parallel data to/from MIB or PC
;
; registers
b1_add  equ	08	; Byte 1: antenna, DSA
b2_mux  equ	09	; Byte 2: Mux
b3_d1   equ	0A	; Byte 3: Data byte 1
b4_d2   equ	0B	; Byte 4: Data byte 2
b5_d3   equ	0C	; Byte 5: Data byte 3
parity	equ	0D	; Parity increment
; Status flag register
;sflag	equ	??	; status flag register
par_ct	equ	0E	; number of parity errors
temp	equ	0F	; temp register
ccount	equ	10	; count register
stemp	equ	11	; "S" temp register
scount	equ	12	; "S" count register
;
; defines
wdtpre  equ     B'00111111'     ; WDT prescaler value 1:128
trisa   equ     B'11110001'     ; set porta I/O: 7-4 n/c, 3-1 out, 0 in
trisb	equ	B'00111100'	; set portb I/O: 7-6 out, 5-2 in, 1-0 out
dataon  equ     B'00000000'     ; set portc I/O: bits 0-7 out
dataoff equ     B'11111111'     ; set portc I/O: bits 0-7 in (HiZ)
scode	equ	B'10110100'	; last eight bits of S, "S"=1010110100
qcode	equ	B'10010100'	; last eight bits of Q, "Q"=1010010100
;
;
;
;
;*******************************************************************
; Initialization
;*******************************************************************
start   clrwdt                  ; set up watchdog timer
	movlw wdtpre
	option
	movlw trisa             ; configure ports for I or O
	tris mcp
	movlw trisb
	tris ctlp
	movlw dataoff		; set port c for input
	tris datap
; set outputs to power-on defaults
	bcf ctlp,test		; turn off external wdt pulse
	bsf mcp,tx_i		; turn off M&C transmit line
	bsf mcp,err		; turn on M&C error signal
	bcf mcp,par		; turn off M&C parity error
	bcf ctlp,rd_rdy
	bcf ctlp,wr_rdy
	bsf ctlp,i_err
	clrw			; clear data registers
	clrf b1_add
	clrf b2_mux
	clrf b3_d1
	clrf b4_d2
	clrf b5_d3
	goto main
;
;
;*******************************************************************
; Subroutines
;*******************************************************************
;
;
;
;
;*******************************************************************
; rbyte - Receive byte from M&C bus
;*******************************************************************
; This routine samples the incoming data stream every 10us, reading
; 8 bits into temp and then checking the parity
;
rbyte   movlw 08                ; read eight bits		(1.5)(+50)
	movwf ccount		;				(2.0)
	bcf status,scarry	; make sure carry is zero	(2.5)
rloop   rlf temp,1		; scoot bit up			(3.0)
	btfsc mcp,rx		; check M&C line		(3.5)
	goto rhigh		; if high, increment		(4.0)
	DELAY 1			; if low, take up space		(4.5)
	goto rlow		; and continue			(5.0)
rhigh	incf temp,1		; if high, put '1' in byte	(5.0)
	incf parity,1		; if "1", increment parity	(5.5)
rlow	bsf ctlp,test		; *** pulse sync  ***		(6.0)
	bcf ctlp,test		; *** for testing ***
	DELAY 9			; wait for next bit		(7.0)
	decfsz ccount,1		; are we done?			(11.5)
	goto rloop		; if not, get next bit (2)	(12.0)
;
; if done, check parity bit, set parity error flag if error
	btfsc mcp,rx		; check M&C line		(12.5+7*10)
	incf parity,1		; if "1", increment parity	(83.0)
	btfss parity,0		; if even, parity error		(83.5)
	incf par_ct,1		; set parity error flag		(84.0)
	clrf parity		; reset parity			(84.5)
	retlw 0			; return to main (2)		(85.0)(+50)
;
;
;
;*******************************************************************
; wr_host - Give data to host at each CLK cycle
;*******************************************************************
; 
;
;write to host device
wr_host	btfsc ctlp,clk		; make sure host has clk low
	goto wr_host
	movlw dataon		; turn on port c for output
	tris datap
	movf b1_add,0		; get first byte to put into FIFO
	movwf datap		; put it out the port
	bsf ctlp,rd_rdy		; tell host data ready
	call waitclk
	movf b2_mux,0		; get second byte to put into FIFO
	movwf datap		; put it out the port
	call waitclk
	movf b3_d1,0		; get third byte to put into FIFO
	movwf datap		; put it out the port
	call waitclk
	movf b4_d2,0		; get fourth byte to put into FIFO
	movwf datap		; put it out the port
	call waitclk
	movf b5_d3,0		; get fifth byte to put into FIFO
	movwf datap		; put it out the port
	call waitclk
	movf par_ct,0		; get status byte to put into FIFO
	movwf datap		; put it out the port
	call waitclk
	movlw dataoff		; turn off portc
	tris datap
	bcf ctlp,rd_rdy		; no more data to read
	retlw 0
;
;
;
;*******************************************************************
; waitclk - wait for clk to go high, then low
;*******************************************************************
;
; 
waitclk	btfss ctlp,clk		; wait for host to read data (clk pulse)
	goto waitclk
wclka	btfsc ctlp,clk
	goto wclka
	retlw 0
;
;
;
;*******************************************************************
; sbyte - send a byte of data in temp to M&C, then send parity bit
;*******************************************************************
;
;entry point sbyte_s includes setup
sbyte_s	movlw 08		; eight bits plus parity	(2.0)
	movwf scount		;				(2.5)
	clrf parity		; reset parity counter		(3.0)
sbyte	btfsc stemp,7		; what is next bit		(3.5)(48.5)
	goto sbhigh		; if high, turn line on		(4.0)
	DELAY 1			; 				(4.5)
	bsf mcp,tx_i		; if low, turn line off		(5.0)*
	goto sbcont		; continue			(5.5)
sbhigh	bcf mcp,tx_i		; turn line on			(5.0)*
	DELAY 1			;				(5.5)
	incf parity,1		; update parity count		(6.0)
sbcont	rlf stemp,1		; get next bit			(6.5)
	DELAY 0A		;				(7.0)
	decfsz scount,1		; are we done?			(2.0)
	goto sbyte		;				(2.5)
	DELAY 1			;				(3.0)
;
; generate parity pulse
	btfss parity,0		; parity odd?			(3.5+80)
	goto parhigh		; if not, send "1"		(4.0)
	DELAY 1			;				(4.5)
	bsf mcp,tx_i		; if no parity, send "0"	(5.0)*
	goto parcont		;				(5.5)
parhigh	bcf mcp,tx_i		; if parity, turn on tx		(5.0)*
	DELAY 2			;				(5.5)
parcont	retlw 0			;				(6.5)

;
;
;
;*******************************************************************
; Main
;*******************************************************************
;
; 
main	btfsc ctlp,clk		; make sure host has clk low
	goto main
	bsf ctlp,wr_rdy		; tell host we are ready for first byte
	call waitclk
;
; Read byte from host
	movf datap,0		; get data from port into w
	movwf temp		; store in temp
; "S"
	movlw 'S'		; ASCII "S": Command M&C
	subwf temp,0		; compare to "S"
	btfsc status,szero	; if equal (result 0), 
	goto send_s		; get data and send "S"
; "Q"
	movlw 'Q'		; ASCII "Q": Query M&C
	subwf temp,0		; compare to "Q"
	btfsc status,szero	; if equal
	goto send_q		; send "Q" and retrieve data
; "D"
	movlw 'D'		; ASCII "D": Diagnostic data
	subwf temp,0		; compare to "D"
	btfsc status,szero	; if equal
	goto diag		; send diagnostic data
; none of above
	bsf ctlp,i_err		; interface error, not recognized
	goto main		; keep looking
;
;
; Return Diagonostic information
;
diag	bcf ctlp,wr_rdy		; no longer accepting data from host
	bcf ctlp,i_err		; no more interface error
	movlw 6			; make test pattern 6, 5, 4, 3, 2, 1
	movwf b1_add
	movlw 5
	movwf b2_mux
	movlw 4
	movwf b3_d1
	movlw 3
	movwf b4_d2
	movlw 2
	movwf b5_d3
	movlw 1
	movwf par_ct
	call wr_host
;
; done, little bit of housekeeping stuff, then back to ready
	clrwdt			; reset watchdog
	clrw
	goto main
;
;
; "Q" Code
;
; Transmit "Q"
send_q	bcf ctlp,wr_rdy		; no longer accepting data from host
	bcf ctlp,i_err		; no more interface error
	bcf mcp,tx_i		; send first two bits, first 1	(0.0)
	DELAY 9			; stays high for 5us		(0.5)
	bsf mcp,tx_i		; then second bit, 0		(5.0)
	DELAY 2			; stays low for 5us		(5.5)
	movlw 08		; send eight bits		(6.5)
	movwf ccount		;				(7.0)
	movlw qcode		; load up last eight bits of "Q" code
	movwf temp		;				(8.0)
qloop	btfsc temp,7		; what is next bit		(8.5)(13.5)
	goto qhigh		; if high, turn line on		(9.0)
	DELAY 1			;
	bsf mcp,tx_i		; if low, turn line off		(10.0)
	goto qcont		; continue			(10.5)
qhigh	bcf mcp,tx_i		; turn line on			(10.0)
	DELAY 3			;
qcont	rlf temp,1		; get next bit			(11.5)
	decfsz ccount,1		; are we done?			(12.0)
	goto qloop		;				(12.5)
	bsf mcp,tx_i		; make sure xmit is off
;
; Wait for "S" code
waits	clrf temp
	clrf parity
	clrf par_ct		; clear parity error count
;
; ACU
; S: xxx_-_-_--_-__xxxx
;        1010110100
; FRM
; S: xx---_-_--_-__xxxx
;      111010110100
; If input=high:FRM
; If input=low:ACU
; => look for falling edge, detect
eeep2	btfss mcp,rx		; make sure we're high to see falling edge
	goto eeep2
;
eeep0   btfsc mcp,rx		; wait for falling edge
	goto eeep0		; (2)
				; at this point:
				; best case detection = 5.5us
				; worst case detection = 7.5us
				;  => sample btw 1.5-3.5us after edge
;
; Read next eight bits at 5us/bit, put in b1_add
	movlw 08		; set up to read eight bits	(6.5)
	movwf ccount		;				(7.0)
	DELAY 1			;				(7.5)
	bcf status,scarry	; make sure carry is zero	(8.0)
	bcf mcp,err		; got valid "S", turn off err	(8.5)
rsloop	bsf ctlp,test		; *** pulse sync  ***		(9.0) (14.0)
	bcf ctlp,test		; *** for testing ***
	DELAY 2
	rlf temp,1		; scoot bit up			(11.0)
	btfsc mcp,rx		; want to test at 1.5-3.5us	(11.5)
	incf temp,1		; if high, put '1' in byte	(12.0)
	decfsz ccount,1		; are we done?			(12.5)
	goto rsloop		; if not, get next bit (2)	(13.0)
;
; Check to see if bits are last eight of "S"
	movlw scode 		; last eight bits of "S"	(13.5+7*5=48.5)
	subwf temp,0		; subtract from just read	(49.0)
	btfss status,szero	; if temp=scode, keep reading	(49.5)
	goto serror		; not "S", keep looking		(50.0)
;	bcf mcp,err		; clear error signal
;
; Read in the M&C data, 10us/bit
	call rbyte              ; read byte from M&C		(50.5)
	movf temp,0		;				(136.0)
	movwf b1_add		; first byte, address		(136.5)
	clrf temp		;				(137.0)
	DELAY 6			;				(137.5)
	call rbyte		; read next byte		(140.5)
	movf temp,0
	movwf b2_mux		; second byte, mux
	clrf temp
	DELAY 6
	call rbyte
	movf temp,0
	movwf b3_d1		; third byte, data byte one
	clrf temp
	DELAY 6
	call rbyte
	movf temp,0
	movwf b4_d2		; fourth byte, data byte two
	clrf temp
	DELAY 6
	call rbyte
	movf temp,0
	movwf b5_d3		; fifth byte, data byte three
;
	call wr_host		; let host read data
	clrwdt			; don't watchdog out
;
; done, little bit of housekeeping stuff, then back to ready
	clrwdt			; reset watchdog
	clrw
	subwf par_ct,0		; see if parity error count is zero
	btfss status,szero
	goto par_off		; if so, turn off light
	bsf mcp,par		; if not, turn on light
	goto main
par_off	bcf mcp,par
	goto main
;
serror	bsf mcp,err		; set error line
	goto main		; go back to looking for "S"
;
;
; "S" Code
;
; read in five bytes of data
send_s	call waitclk		; wait for next clock pulse
	movf datap,0		; get data from port into w
	movwf b1_add
	call waitclk		; wait for next clock pulse
	movf datap,0		; get data from port into w
	movwf b2_mux
	call waitclk		; wait for next clock pulse
	movf datap,0		; get data from port into w
	movwf b3_d1
	call waitclk		; wait for next clock pulse
	movf datap,0		; get data from port into w
	movwf b4_d2
	call waitclk		; wait for next clock pulse
	movf datap,0		; get data from port into w
	movwf b5_d3
	bcf ctlp,i_err		; no more interface error
;
; ack "S", set up for sbyte routine
	bcf ctlp,wr_rdy		; no longer accepting data from host
	movlw 08		; eight bits plus parity
	movwf scount
	clrf parity		; reset parity counter
	movf b1_add,0		; first byte
	movwf stemp
;
; send "S"
	bcf mcp,tx_i		; send first two bits, first 1	(0.0)
	DELAY 9			; stays high for 5us		(0.5)
	bsf mcp,tx_i		; then second bit, 0		(5.0)
	movlw 08		; send eight bits		(5.5)
	movwf ccount		;				(6.0)
	movlw scode		; load up last eight bits of "S" code
	movwf temp		;				(7.0)
	DELAY 1			;				(7.5)
tsloop	DELAY 1			;				(8.0)(13.0)
	btfsc temp,7		; what is next bit		(8.5)
	goto shigh		; if high, turn line on		(9.0)
	rlf temp,1		; get next bit			(9.5)
	bsf mcp,tx_i		; if low, turn line off		(10.0)(15.0)
	goto scont		; continue			(10.5)
shigh	bcf mcp,tx_i		; turn line on			(10.0)(15.0)
	rlf temp,1		; get next bit			(10.5)
	DELAY 1			;				(11.0)
scont	decfsz ccount,1		; are we done?			(11.5)
	goto tsloop		;				(12.0) 
;
; send data to M&C
	call sbyte		; send first byte		(2.5+45)
	movf b2_mux,0		; prep second byte		(7.5+45+90)
	movwf stemp		;				(8.0)
	DELAY 5			;				(8.5)
	call sbyte_s		; send it			(1.0)
	movf b3_d1,0		; prep third byte		(7.5)
	movwf stemp		;				(8.0)
	DELAY 5			;				(8.5)
	call sbyte_s		; send it			(1.0)
	movf b4_d2,0		; prep fourth byte		(7.5)
	movwf stemp		;				(8.0)
	DELAY 5			;				(8.5)
	call sbyte_s		; send it			(1.0)
	movf b5_d3,0		; prep fifth byte		(7.5)
	movwf stemp		;				(8.0)
	DELAY 5			;				(8.5)
	call sbyte_s		; send it			(1.0)
;	
	DELAY 0F		;				(7.5)
	bsf mcp,tx_i		; turn TX line off		(15.0)
	goto main
;
	END
