;
; File: receiver.asm -- receiver module for cable tester
;
; (C) 1996 Maurizio Fabbri, Fabio Raso, Luigi Rizzo
; Dipartimento di Ingegneria dell'Informazione
; via Diotisalvi 2 -- 56126 PISA (ITALY)
; email: luigi@iet.unipi.it

	device  pic16c84
	config  CP=off,WDT=off,PWRT=off,OSC=hs

nuovo	equ	1
include "defs.inc"

; on_1 targer, on_0 target sample the input line and jump to target
; if the desired value is found. Make the program easier to read.
on_1	macro	;	on_1 target
	movf PORTB, W	; W <- sample portb
	andwf maskB, W	; W <- mask & W, set Z flag
	btfss STATUS, Zbit
	goto \1	
	endm

on_0	macro	;	on_1 target
	movf PORTB, W	; W <- sample portb
	andwf maskB, W	; W <- mask & W, set Z flag
	btfsc STATUS, Zbit
	goto \1	
	endm

;--- port usage: portb: input data/ display output
;    port A: display cathodes (via transistors)
DISPLAY1	equ	1
DISPLAY2	equ	2
;--- receiver-specific registers

ctr1	equ	0x10	; two generic counters
ctr2	equ	0x11

broken	equ	0x14	; 1 for each broken line
bitptr	equ	0x15	; bit under test (0..7)
maskB	equ	0x16	; corresponding mask

digits	equ	0x17	; what goes in digits ? (2 4-bit nibbles)

BufP0	equ	0x20	; what is received on this bit ? [ 8 bytes ]
; -- up to BufP7 equ 0x27

    org 0
    goto start	; start a new test


; total delay (incl. call+ret) 4*W + 3
wdelay			; a simple delay routine using W
    addlw -1		; 4 ck/loop + 5 last one (incl.ret)
    btfss STATUS,Zbit     ; salta se Zbit = 1
    goto wdelay
    return

	scrambler

;--- bit2display 0..9 -> 0..9

bin2display	; up to 16 codes
    andlw	0xf	; mask
    addwf PCL,F
    ;       -gfedcba	; segments
    retlw B'00111111'	; digit 0	(unused)
    retlw B'00000110'	; digit 1
    retlw B'01011011'	; digit 2
    retlw B'01001111'	; digit 3
    retlw B'01100110'	; digit 4
    retlw B'01101101'	; digit 5
    retlw B'01111101'	; digit 6
    retlw B'00000111'	; digit 7
    retlw B'01111111'	; digit 8
    retlw B'00000000'	; blank (digit 9 is unused)
stuck1	equ	0x0a
    retlw B'00000001'	; stuck 1
unconn	equ	0x0b
    retlw B'01000000'	; unconnected - 
stuck0	equ	0x0c
    retlw B'00001000'	; stuck 0
    retlw B'00111000'	; L
    retlw B'01111001'	; E
    retlw B'01110011'	; P

;--- a quick test to see if everything ok (BufP[i] = i)
; returns Z set if everything is OK
tutto_ok
    bsf STATUS,Cbit
    movf broken,0	; test broken
    andlw  0xFF
    btfss STATUS,Zbit
    return	; with Z clear.

    return
	; scan for BufP[i] = i
    ldc 8, ctr2	; number of pins
ok_loop
    decf ctr2, W
    addlw BufP0	; prepare to read
    movwf FSR
    movf INDIR, W	; load test result
    andlw 0x7	; mask
    subwf ctr2, W	; indir - W 
    return	; with Z clear if false
    return	; with Z set if true

; display a couple of digits. uses ctr1 as a counter.
display ldc 0xff, ctr1	; number of cycles ?
refreshDisplay
    movf digits,W
    call bin2display
    bcf	PORTA,DISPLAY2
    movwf PORTB
    bsf PORTA,DISPLAY1
    movlw 0xff
    call wdelay
    swapf digits,W
    call bin2display
    bcf PORTA,DISPLAY1   
    movwf PORTB
    bsf PORTA,DISPLAY2
    movlw 0xff             ; attesa display2 --> display1 ...
    call wdelay            ; ... circa 60 micro sec.
    loop ctr1, refreshDisplay
    return

;---
;    test_line tests a specific line, with mask in maskB
;    bitptr also contains the index
;
;	uses ctr2, ctr1 as loop counters

test_line
    
    ;    Each bit is sent every 28 cycles, each line carries 8 bits
    ;    followed by about 56 bits of silence (for a cycle time of
    ;    64 bits). To avoid false detections, we should do as follows:
    ;       1) wait at most 10 bit times for the line to become '1'
    ;       2) wait for at least 40 bits of '1' or go to step 1
    ;    if the above does not complete in more than 6 phases at 1,
    ;    give up and mark the line as broken.

	ldc 0x0a, ctr2	; how many times wait for '1' period ? max 10
	goto w_hi

w_l_again loop ctr2, w_hi
	movf maskB,0	; too many retries, abort
	iorwf broken, 1	; mark as broken
	retlw unconn

	; wait at most 10 bit times for the line to become '1'
	; w_hi_l takes 7 cycles, so 0x30 is more than safe
w_hi	ldc 0x30, ctr1
w_hi_l	on_1 w_l_2
	loop ctr1, w_hi_l	; wait again...

	movf maskB, W	; 1 not found, mark as stuck 0 and return.
	iorwf broken, F	; mark as broken
	retlw stuck0

	; wait for bit to stay up for a sufficient time, >= 48 bits.
	; the loop w_l_3 is 7 clocks, so ctr1 about (48*28/7) = 192
	; or less if ever.
w_l_2	ldc 0xc0, ctr1
w_l_3	on_0 w_l_again
	loop ctr1, w_l_3

	; ok, '1' for a sufficient time, now wait for 0 again.
	; Cannot fail here, but wait at most 20 bit times. This time
	; the cycle is 6 clocks, hence ctr1 = (20*28/6) = 93. The error
	; on the start bit is at most 6 clocks, i.e. 1/4 bit time.
	; From there on, we can simply accumulate bits.

	ldc 0x5d, ctr1
	movf maskB,W	; W <- mask
w_l_4	andwf PORTB,W	; W <- portb & mask,  set Z
	btfsc STATUS, Zbit	; Z set if bit = 0 (found)
	goto start_found
	loop ctr1, w_l_4

	movf maskB,W
	iorwf broken,1	; '0' not found. Mark as broken and stuck to 1
	retlw stuck1

start_found:	; here we are 4..10 cycles into the start bit.
	; wait an additional 7 cycles, then sample every 28

	ldc 7, ctr2  ; mask for out data, now ctr2 is a bit counter,
	clrf  ctr1 ; and ctr1 an accumulator
	movlw 0x6
	call wdelay ; 27 cycles

get_bit nop
	nop
	nop
	bcf   STATUS, Cbit	; clear carry
	movf maskB,W		; load mask in W.
	andwf PORTB,W	; sample portb, mask & set Z
	btfss STATUS, Zbit	; Z set if bit = 0
	bsf   STATUS, Cbit	; was 1, set carry
	rlf   ctr1, F	; accumulate
	movlw 0x3
	call wdelay	; 15 clocks
	loop ctr2, get_bit
	incf  ctr1, 0	; now ctr1 contains the code, inc & store in W
	andlw 0xf
	return

;---- main program ----
;
; Input lines are assumed to be connected to the sender, where
; they are all but one hold to '1'. On the remaining line,
; a code is cyclically transmitted indicating which line is
; this at the remote end.

start	clrf bitptr		; same (index)
	clrf broken     ; bitmap of broken lines
	bsf STATUS,RP0bit	; page 1
	bcf OPTION_REG, 7	; pull up enabled
	ldc 1, TRISA		; set RA0 as input, rest output
	ldc 0xff, TRISB		; port B input
	bcf STATUS,RP0bit   ; page 0
	clrf PORTA          ; display off

wire	movf	bitptr, W
	call make_mask
	movwf maskB         ; line currently under test.
	call test_line	; test input lines, one at a time. result in W
	movwf digits	; used as a temp. buffer
	movf bitptr,W	; W <- &BufP[ bitptr ]
	addlw BufP0	; store result
	movwf FSR
	movf digits,W	; W <- digits
	movwf INDIR

	incf bitptr, F	; this also clears carry, which must be 0
	movf bitptr, W
	andlw 0x7
	btfss STATUS,Zbit	; if carry set, we are done
	goto wire

;--- when the test is over, show the results. ---

show	;btfsc PORTA,TastoV   ; first, wait for a keypress.
	;goto show

	bsf STATUS,RP0bit	; page 1
	clrf TRISB		; portb = out
	bcf STATUS,RP0bit	; page 0

	ldc 5, ctr2	; shows the result this many times.

;	call tutto_ok	; quick check if all ok (Z set if true)
;	btfss STATUS,Zbit
	goto nook

	ldc 0x28, ctr2	; since the loop is shorter...
infinitoSi  ; all ok. Display "SI" forever
	ldc 0x51, digits	; SI
	call display
	decfsz ctr2, F
	goto infinitoSi
	goto dormi

nook	clrf bitptr	; T_OK
nook_lp movf bitptr,0	; read a digit
	addlw BufP0
	movwf FSR
	movf INDIR,0	; read BufP[i]
	andlw 0xf		; mask
	movwf digits
	swapf bitptr,W
	addlw 0x10
	andlw 0xf0
	iorwf digits,F	; store
	call display
	incf bitptr,1
	movf bitptr,0
	xorlw 0x8
	btfss STATUS, Zbit
	goto nook_lp
	decfsz ctr2, F
	goto nook

dormi
	ldc 0x95, digits	; ' S'
	call display
	ldc 0x5D, digits	; 'SL'
	call display
	ldc 0xdE, digits	; 'LE'
	call display
	ldc 0xEE, digits	; 'EE'
	call display
	ldc 0xEF, digits	; 'EP'
	call display
	bsf STATUS,RP0bit
	movlw	0xff	; ports off
	movwf	TRISA
	movwf	TRISB
	bcf STATUS,RP0bit
	sleep
    end
