TITLE   'PICBLOCK'
LIST P=16C84
LIST F=INHX8M
;
;       Decoder data --> PORTB.0
;       Card data -----> PORTA.0
;
ORG 0
; Registers
IND0            EQU     0
TMR0            EQU     1
PC              EQU     2
STATUS          EQU     3
FSR             EQU     4
PORTA           EQU     5
PORTB           EQU     6
TRISB           EQU     6
EEDATA          EQU     8
EEADR           EQU     9
PCLATH          EQU     10
INTCON          EQU     11
;
VC_data         EQU     12
Byte_count      EQU     13
Bit_count       EQU     14
Cla             EQU     15
Ins             EQU     16
P1              EQU     17
P2              EQU     18
Count           EQU     19
Del             EQU     20
SN1             EQU     21
SN2             EQU     22
;
; Macros
SAME            EQU     1                
Z               EQU     2

		GOTO    START

;******************************************************************************
;               Read byte from card or decoder.
;               Byte is passed on to decoder or card
;               or card to decoder, bit by bit.
;                       Exits with byte in reg. data.
;******************************************************************************
Read_byte 
		BTFSS   PORTB,0         ; Wait for start bit - decoder
		GOTO    To_Card         ; Decoder to card com
		BTFSS   PORTA,0         ; Wait for start bit - card
		GOTO    To_Dec          ; Card to decoder com
		GOTO    Read_byte       ; No start bit found
To_Dec          
		CALL    Half_delay      ; Half-bit delay - center of start bit
		BSF     STATUS,5        ; Change to page 1
		BCF     TRISB,0         ; PB.0 to output - to decoder
		BCF     STATUS,5        ; Back to page 0
		BCF     PORTB,0         ; Send start bit to decoder
		BTFSC   PORTA,0
		GOTO    Stop_cd
		MOVLW   8               ; Get number of data bits
		MOVWF   Bit_count       ; Store it
		CLRF    VC_data         ; Clear data register
		CALL    Bit_delay       ; 1-bit delay - centre of 1st bit
		BCF     STATUS,0        ; Clear carry bit
Nxt_Cbit           
		RLF     VC_data,SAME    ; Shift data bits left 1
		BTFSS   PORTA,0         ; Read card i/o, is it high ?
		GOTO    Cbit_0          ; ...no
		BSF     PORTB,0         ; Card i/o high, so send decoder a 1
		INCF    VC_data,SAME    ; Read a 1, so data LSB to 1
		GOTO    Rd_Cbit         ; Bit = 1
Cbit_0          
		BCF     PORTB,0         ; Read a 0, so send decoder a 0
Rd_Cbit           
		CALL    Bit_delay       ; Wait till centre of next bit
		DECFSZ  Bit_count,SAME  ; All bits read yet ?  
		GOTO    Nxt_Cbit        ; ...no, get next bit
		BTFSS   PORTA,0         ; 8 data bits read, read parity bit
		BCF     PORTB,0         ; Parity = 0, so send decoder a 0
		BTFSC   PORTA,0         ; Read parity bit again
		BSF     PORTB,0         ; Parity = 1, so send decoder a 1
		CALL    Bit_delay       ; Wait till centre of stop bit
		COMF    VC_data,SAME    ; Invert data
Stop_cd
		BSF     PORTB,0         ; Send decoder stop bit
		BSF     STATUS,5        ; Change to page 1
		BSF     TRISB,0         ; PB.0 to input
		BCF     STATUS,5        ; Back to page 0
		CALL    Bit_delay

		RETURN

;******************************************************************************
;               Decoder to card
;******************************************************************************
To_Card         CALL    Half_delay      ; Half-bit delay - center of start bit
		BSF     STATUS,5        ; Change to page 1          
		BCF     PORTA,0         ; PA.0 to output - to card   
		NOP
		BCF     STATUS,5        ; Back to page 0           
		BCF     PORTA,0         ; Send start bit to card  
		BTFSC   PORTB,0
		GOTO    Stop_dc
		MOVLW   8               ; Get number of data bits  
		MOVWF   Bit_count       ; Store it   
		CLRF    VC_data         ; Clear data register 
		CALL    Bit_delay       ; 1-bit delay - centre of 1st bit   
		BCF     STATUS,0        ; Clear carry bit          
Nxt_Dbit           
		RLF     VC_data,SAME    ; Shift data bits left 1      
		NOP
		BTFSS   PORTB,0         ; Read decoder i/o, is it high ?
		GOTO    Dbit_0          ; ... no         
		BSF     PORTA,0         ; Decoder i/o high, so send card a 1    
		INCF    VC_data,SAME    ; Read a 1, so data LSB to 1  
		GOTO    Rd_Dbit         ; Next bit      
Dbit_0          
		BCF     PORTA,0         ; Read a 0, so send card a 0   
Rd_Dbit         
		CALL    Bit_delay       ; Wait till centre of next bit  
		NOP
		DECFSZ  Bit_count,SAME  ; All bits read yet ? 
		GOTO    Nxt_Dbit        ; .. no, get next bit 
		BTFSS   PORTB,0         ; 8 data bits read, read parity bit  
		BCF     PORTA,0         ; Parity = 0, so send decoder a 0  
		BTFSC   PORTB,0         ; Read parity bit again      
		BSF     PORTA,0         ; Parity = 1, so send card a 1     
		CALL    Bit_delay       ; Wait till centre of stop bit 
		COMF    VC_data,SAME    ; Invert data    
Stop_dc                
		BSF     PORTA,0         ; Send card stop bit   
		BSF     STATUS,5        ; Change to page 1             
		BSF     PORTA,0         ; PA.0 to input   
		BCF     STATUS,5        ; Back to page 0            
		RETURN

;******************************************************************************
;               Send 00 in place of remaining E0 string
;******************************************************************************
Send_00         
		BTFSC   PORTB,0         ; Wait for start bit from decoder
		GOTO    Send_00
		CALL    Half_delay      ; Half-bit delay - center of start bit
		BSF     STATUS,5        ; Change to page 1          
		BCF     PORTA,0         ; PA.0 to output - to card   
		BCF     PORTA,1
		BCF     STATUS,5        ; Back to page 0           
		BCF     PORTA,0         ; Send start bit to card  
		
		BTFSC   PORTB,0
		GOTO    Stop_dc0
		
		MOVLW   8               ; Get number of data bits  
		MOVWF   Bit_count       ; Store it   
		NOP 
		CALL    Bit_delay       ; 1-bit delay - centre of 1st bit   
		BCF     STATUS,0        ; Clear carry bit          
NEXT0           NOP                     ; NOPs to preserve bit timing   
		BSF     PORTA,1         ; Scope monitor bit
		NOP      
		NOP         
		BSF     PORTA,0         ; Send card a 0 ( inverse )    
		NOP
		NOP   
		NOP   
		CALL    Bit_delay       ; Wait till centre of next bit  
		BCF     PORTA,1         ; For scope
		DECFSZ  Bit_count,SAME  ; All bits read yet ? 
		GOTO    NEXT0           ; .. no, get next bit 
		NOP
		NOP  
		NOP   
		NOP     
		CALL    Bit_delay       ; Wait till centre of stop bit 
		NOP 
Stop_dc0               
		BSF     PORTA,0         ; Send card stop bit   
		BSF     STATUS,5        ; Change to page 1             
		BSF     PORTA,0         ; PA.0 to input   
		BCF     STATUS,5        ; Back to page 0            
		RETURN

;******************************************************************************
;               Delay for 48uS or 89uS
;******************************************************************************
Half_delay           
		MOVLW   0xE
		GOTO    Delay

Bit_delay       
		MOVLW   0x1A
Delay           
		MOVWF   Del
Del_loop           
		DECFSZ  Del,SAME
		GOTO    Del_loop
		RETURN
;*****************************************************************************
;                                 Start of program 
;*****************************************************************************
START           CLRF    Cla
		CLRF    Ins
		CLRF    P1
		CLRF    P2

;******************************** Main program loop **************************
MAIN
		MOVF    Ins,W
		MOVWF   Cla
		MOVF    P1,W
		MOVWF   Ins
		MOVF    P2,W
		MOVWF   P1
		CALL    Read_byte
		MOVF    VC_data,W
		MOVWF   P2
		BTFSS   STATUS,Z       ; Check P2 = 0
		GOTO    MAIN
		MOVF    Cla,W
		XORLW   0x53            ; Check for Vcrypt class code
		BTFSS   STATUS,Z
		GOTO    MAIN            ; Loop round until class 53h found
		MOVF    P1,SAME
		BTFSS   STATUS,Z        ; Check for P1 = 0
		GOTO    MAIN            ; Not header - try again
		CALL    Read_byte       ; Read byte count
		MOVF    VC_data,W
		MOVWF   Byte_count      ; Store byte count
		INCF    Byte_count,SAME
		CALL    Read_byte       ; Transfer ins back
		MOVLW   0x74            ; Instruction 74h ?
		XORWF   Ins,W
		BTFSC   STATUS,Z
		GOTO    Ins74
		GOTO    MAIN

;************** Instruction code 74h - message from station *****************
Ins74          
		MOVLW   0x1F
		MOVWF   Count
		CALL    Read_byte       ; Read 1st byte
		BTFSS   VC_data,3       ; Check for E8 or E0 1st byte
		GOTO    block
No_block        
		CALL    Read_byte       ; Read/send remaining 31 bytes
		DECFSZ  Count,SAME
		GOTO    No_block
		GOTO    MAIN
block                
		MOVLW   0xA
		MOVWF   Count
block10
		CALL    Read_byte       ; Read/send 1st 10 bytes
		DECFSZ  Count,SAME
		GOTO    block10
		CALL    Read_byte       ; Get E0 S/N 5th digit (1)
		MOVF    VC_data,W
		MOVWF   SN1
		CALL    Read_byte       ; Get E0 S/N 5th digit (2)
		MOVF    VC_data,W
		MOVWF   SN2
		CALL    Read_byte       ; Get E0 S/N 5th digit (3)
		MOVF    VC_data,W
		XORWF   SN2,SAME
		BTFSS   STATUS,Z        ; Does digit 3 = digit 2 ?
		GOTO    E0_ok
		XORWF   SN1,SAME
		BTFSS   STATUS,Z        ; Does digit 3 = digit 1 ?
		GOTO    E0_ok
					; 3 consecutive bytes are the same
		MOVLW   0x12            ; 18 bytes left in E0 string
		MOVWF   Count
Kill_E0
		CALL    Send_00         ; Kill remaining 18 bytes
		DECFSZ  Count
		GOTO    Kill_E0
		GOTO    MAIN
E0_ok
		MOVLW   0x12            ; 18 bytes left in E0 string
		MOVWF   Count
No_kill
		CALL    Read_byte       ; Pass on remaining 18 bytes
		DECFSZ  Count
		GOTO    No_kill
		GOTO    MAIN

END
