	LIST P=16C55
        ERRORLEVEL  -302
; LANC explorer
; allows user to test various LANC codes - both 1st and 2nd bytes can be
; set to any value, and command can be sent once, or sent repetitive
;
; This version is set to display the codes being sent on a 16 character LCD
; display.
; physical connections:
; A0, pin 6	LANC to camera
; C7..C0	data bus to LCD
; B7		E to LCD
; B6		R/W to LCD
; B5		RS to LCD
; B3		byte 2 decrease
; B2		byte 2 increase
; B1		byte 1 decrease
; B0		byte 1 increase
; A3		send repetitive
; A2		send once

;display format
; address 0 - sending indicator - toggle between 0x20 and 0x0
; address 2,3 command byte 1
; address 5,6 command byte 2


       include <p16c5x.inc>
;defintions
same	equ	1
INPUT	equ	0		;bit to use for reading LANC - used 2x
OUTPUT	equ	0		;bit to use for writing LANC - used 2x
DEBUG	equ	1		;bit 1 output for debugging
TRIS_READ_LANC	equ	0fdh	;A0,2,3 in A1 out (debug bit)
TRIS_WRITE_LANC	equ	0fch	;A2,3 in -  0 out 1 out
TRIS_READ_SWITCHES	equ	00fh	;0,1,2,3 in 4,5,6,7 outputs
BIT_TIME	equ	.31	;for 4 MHz - used 2x
; on my SONY CCD-TR6, values from 33 to 28 worked - mid range
; is 30 or 31

B1UP	EQU	0
B1UP_P	EQU	PORTB
B1DN	EQU	1
B1DN_P	EQU	PORTB
B2UP	EQU	2
B2UP_P	EQU	PORTB
B2DN	EQU	3
B2DN_P	EQU	PORTB

DEBUG	EQU	1
DEBUG_P	EQU	PORTA
SEND1	EQU	2
SEND1_P	EQU	PORTA
SENDX	EQU	3
SENDX_P	EQU	PORTA

;port definitions
LCD_DATA         EQU     PORTC
LCD_CNTL         EQU     PORTB

; LCD Display Commands and Control Signal names.
E		EQU	7		; LCD Enable control line
RW		EQU	6		; LCD Read/Write control line
RS		EQU	5		; LCD Register Select control line


;RAM defines	can use 0x08 to 0x1f without resorting to banking
counter		EQU	0x08
counter2	EQU	0x09
bit_counter	EQU	0x0a
bits_to_send	EQU	0x0b

byte_to_write	EQU	0x0c
command_byte_1	EQU	0x0d
command_byte_2	EQU	0x0e
byte_number	EQU	0x0f
command_pass	EQU	0x10

msd		EQU	0x11	;Holds Most Significant Digit in delay counter
lsd		EQU	0x12	;Holds Least Significant Digit in delay counter
temp		EQU	0x13	
char		EQU	0x14	;Holds value to send to LCD module.
last_val_0	EQU	0x15	;last value written to first char pos in LCD
				; toggle between 0x20 and 0x00 after each 
				; send_5
b1up		EQU	0x16
b1dn		EQU	0x17
b2up		EQU	0x18
b2dn		EQU	0x19
send1		EQU	0x1A
sendx		EQU	0x1B


	org	0	     ; RESET vector location
RESET	goto	START

;vector table for far calls
delay_771		goto	delay_771_f
send_cmd		goto	send_cmd_f
send_char		goto	send_char_f
wait_for_interframe	goto	wait_for_interframe_f
send_command_5		goto	send_command_5_f
convert_to_hex		goto	convert_to_hex_f

START				; POWER_ON Reset (Beginning of program)
	goto	init_f		; ends with "goto main"
	
main    
	call	wait_for_interframe	;do all switch reading in the 
					; 6 ms (4 left after this routine)
					; between frames .... this is
					; lots of time... each machine cycle is 
					; 1 us - so we have ~4000 to use...

	goto	scan_switches_f		;ends with 'goto main'


; end of main section

;----------------------------------------------------------------
scan_switches_f
; switch var values: 0 = not pressed
;		1 = was open, now pressed	BIT 0
;		2 = was pressed, still pressed	BIT 1
;		4 = was pressed, now clear	BIT 2

t0
	btfsc	B1UP_P, B1UP
	goto	t0_0		;key not pressed

t0_1				;is pressed now
	btfsc	b1up, 1		; was key previously pressed?
	goto	t1		;yes - no need for processing - goto next
	
	clrf	b1up
	bsf	b1up, 0		; set b1up to 1
	goto	t1

t0_0				;is not pressed now 
	btfss	b1up, 1		;was pressed?
	goto	t1
	
	clrf	b1up
	bsf	b1up, 2		;set b1up to 4 - was pressed, now clear

;==================================
t1
	btfsc	B1DN_P, B1DN
	goto	t1_0			;key not pressed

t1_1				;is pressed now
	btfsc	b1dn, 1		; was key previously pressed?
	goto	t2		;yes - no need for processing - goto next
	
	clrf	b1dn
	bsf	b1dn, 0		; set b1dn to 1
	goto	t2

t1_0				;is not pressed now 
	btfss	b1dn, 1		;was pressed?
	goto	t2
	
	clrf	b1dn
	bsf	b1dn, 2		;set b1dn to 4 - was pressed, now clear

;==================================
t2
	btfsc	B2UP_P, B2UP
	goto	t2_0			;key not pressed

t2_1				;is pressed now
	btfsc	b2up, 1		; was key previously pressed?
	goto	t3		;yes - no need for processing - goto next
	
	clrf	b2up
	bsf	b2up, 0		; set b2up to 1
	goto	t3

t2_0				;is not pressed now 
	btfss	b2up, 1		;was pressed?
	goto	t3
	
	clrf	b2up
	bsf	b2up, 2		;set b2up to 4 - was pressed, now clear

;==================================
t3
	btfsc	B2DN_P, B2DN
	goto	t3_0			;key not pressed

t3_1				;is pressed now
	btfsc	b2dn, 1		; was key previously pressed?
	goto	t4		;yes - no need for processing - goto next
	
	clrf	b2dn
	bsf	b2dn, 0		; set hat_ to 1
	goto	t4

t3_0				;is not pressed now 
	btfss	b2dn, 1		;was pressed?
	goto	t4
	
	clrf	b2dn
	bsf	b2dn, 2		;set hat_right to 4 - was pressed, now clear

;==================================
t4
	btfsc	SEND1_P, SEND1
	goto	t4_0			;key not pressed

t4_1				;is pressed now
	btfsc	send1, 1		; was key previously pressed?
	goto	t5			;yes - no need for processing - goto next
	
	clrf	send1
	bsf	send1, 0	; set send1 to 1
	goto	t5

t4_0				;is not pressed now 
	btfss	send1, 1	;was pressed?
	goto	t5
	
	clrf	send1
	bsf	send1, 2	;set send1 to 4 - was pressed, now clear

;==================================
t5
	btfsc	SENDX_P, SENDX
	goto	t5_0			;key not pressed
	; get here if SENDX == 0

t5_1				;is pressed now
	btfsc	sendx, 1	; was key previously pressed?
	goto	t6		;yes - no need for processing - goto next
	; get here if sendx != 2
	
	clrf	sendx
	bsf	sendx, 0	; set sendx to 1
	goto	t6

t5_0				;is not pressed now 
	btfss	sendx, 1	;was pressed?
	goto	t6
	;get here if sendx == 2
	
	clrf	sendx
	bsf	sendx, 2	;set sendx to 4 - was pressed, now clear

;==================================
t6
;time to digest what we have...
;+++++++++++++++++
p1
	btfss	b1up, 0
	goto	p2		;b1up not newly pressed

	incf	command_byte_1, 1	
	rlf	b1up, same
	goto	proc_out
;+++++++++++++++++
p2
	btfss	b1dn, 0
	goto	p3		;b1dn not newly pressed

	decf	command_byte_1, 1
	rlf	b1dn, same
	goto	proc_out
;+++++++++++++++++
p3
	btfss	b2up, 0
	goto	p4		;b2up not newly pressed

	incf	command_byte_2, 1
	rlf	b2up, same
	goto	proc_out
;+++++++++++++++++
p4
	btfss	b2dn, 0
	goto	p5		;b2dn not newly pressed

	decf	command_byte_2, 1
	rlf	b2dn, same
	goto	proc_out

;+++++++++++++++++
p5
	btfss	send1, 0
	goto	p6		;send1 not newly pressed

	call	send_command_5
	rlf	send1, same
	goto	proc_out

;+++++++++++++++++
p6
	btfsc	sendx, 1	;sendx not still down?
	goto	p6_yes
	;get here is sendx != 2
	
	btfsc	sendx, 0	;sendx not newly pressed?
	goto	p6_yes
	;get here if sendx != 1
	goto	p7
	
p6_yes	; get here if sendx == 1 || == 2
	btfss	sendx, 0	;is first press?
	goto	no_roll
	;get here if sendx == 1
	rlf	sendx, same	;mark as not a new press...

no_roll	
	call	send_command_5
	goto	proc_out

;+++++++++++++++++
p7

proc_out
; need to update display
	movlw	0x82
	call	send_cmd
	
	;hi nibble first
	swapf	command_byte_1, 0
	andlw	0x0f
	call	convert_to_hex
	call	send_char

	;then low
	movf	command_byte_1, 0
	andlw	0x0f
	call	convert_to_hex
	call	send_char
	
	movlw	0x85
	call	send_cmd

	;hi nibble
	swapf	command_byte_2, 0
	andlw	0x0f
	call	convert_to_hex
	call	send_char

	;low nibble
	movf	command_byte_2, 0
	andlw	0x0f
	call	convert_to_hex
	call	send_char

	goto	main

convert_to_hex_f
	addwf	PCL, 1
	retlw	0x30	;'0'
	retlw	0x31	;'1'
	retlw	0x32	;'2'
	retlw	0x33	;'3'
	retlw	0x34	;'4'
	retlw	0x35	;'5'
	retlw	0x36	;'6'
	retlw	0x37	;'7'
	retlw	0x38	;'8'
	retlw	0x39	;'9'
	retlw	0x61	;'a'
	retlw	0x62	;'b'
	retlw	0x63	;'c'
	retlw	0x64	;'d'
	retlw	0x65	;'e'
	retlw	0x66	;'f'


;----------------------------------------------------------------------
;wait_for_interframe routine
; when called will eat time waiting for a roughly 2 ms idle time on 
; LANC - reads INPUT bit of PORTA
; uses counter counter2

wait_for_interframe_f
;	return
sync_up	
	movlw	3
	movwf	counter2	; counter2 = 3
	clrf	counter		; counter = 0

sync_loop
	btfss	PORTA, INPUT	;if lanc = 1, skip jump
	goto	sync_up		; any lanc = 0 resets counters

				; lanc == 1 to get here
	incfsz	counter, 1	; inc low byte of counter
	goto	sync_loop	; skip jump if counter overflows to 0

	decfsz	counter2, 1	; decrement counter2
	goto	sync_loop	; skip jump if --counter2 == 0

sync_ed	
	retlw	0		;return to caller

;--------------------------------------------------------------------
; send_command_5  sends command in command_byte_1 and command_byte_2
; the required 5 times.

send_command_5_f
	movlw	5
	movwf	command_pass

sc5_1
	call	wait_for_interframe


;------------------------------------------------------------------
; send_command
; waits until bit INPUT of PORTA goes low, then delays
; 1 bit time minus a few cycles, then sends the byte in 
; command_byte_1, then waits for INPUT to go low again, then
; sends byte in command_byte_2
; uses:
;	bit_counter, bits_to_send, byte_to_write, byte_number
send_command
	movlw	2
	movwf	byte_number	;initialize outer loop counter

	movf	command_byte_1, 0
	movwf	byte_to_write	;put command byte into byte_to_write

sc_wait_for_LANC_start
	movlw	TRIS_READ_LANC	; A0 = input
	tris	PORTA

sc_wfLs_1
	btfsc	PORTA, INPUT	;waiting for input port to drop - 
	goto	sc_wfLs_1	;is start bit from camcorder

	movlw	BIT_TIME - 1	; @ 4 MHz
	movwf	bit_counter

sc_wfLs_2				;each loop = 1.5 us @ 8MHz
	decfsz	bit_counter, 1
	goto	sc_wfLs_2


sc_write_byte
	movlw	8
	movwf	bits_to_send

	movlw	TRIS_WRITE_LANC	; A0 = output
	tris	PORTA

sc_write_bit
	movlw	BIT_TIME	;34 loops @ 3 clocks @ 1us each @ 4mhz
	movwf	bit_counter

	btfsc	byte_to_write, 0	;test bit 0
	goto	sc_wb_set_1		;skipped if bit 0 = 0

	bsf	PORTA, OUTPUT	;clear output bit to 0
	goto	sc_wb_1
sc_wb_set_1
	bcf	PORTA, OUTPUT	;set output bit to 1 - 

sc_wb_1
	decfsz	bit_counter, 1
	goto	sc_wb_1

	rrf	byte_to_write, same
	decfsz	bits_to_send, same
	goto	sc_write_bit

	movlw	TRIS_READ_LANC	; A0 = input
	tris	PORTA

	decfsz	byte_number, same
	goto	sc_byte_2
	goto	sc_done

sc_byte_2
	movf	command_byte_2, 0
	movwf	byte_to_write
	goto	sc_wait_for_LANC_start

sc_done
	decfsz	command_pass, same
	goto	sc5_1

toggle_disp
	incf	last_val_0, same
	movlw	0x07
	andwf	last_val_0, same

	movlw	0x80
	call	send_cmd	; set ptr to 0
	movf	last_val_0, 0	; get val into w
	call	send_char	; write char
	
	retlw	0

;;-----------------------------------------------------------------------
;call with outer loop count in w - each unit delays for 771 us
delay_771_f
;return
	movwf   msd		 ; Use msd and lsd Registers to Initilize LCD
	clrf    lsd
loop_771    
	decfsz  lsd, F          ; Delay time = msd * ((3 * 256) + 3) * Tcy
	goto    loop_771
	decfsz  msd, F
	goto    loop_771
	return

;**************************************************
;* The LCD Module Subroutines			  *
;**************************************************

;*****************************************************************
;* send_char - Sends character contained in register W to LCD    *
;* This routine sends the entire character to the PORT	         *
;* The data is transmitted on the PORT<7:0> pins	         *
;*****************************************************************

send_char_f
	movwf   char	; Character to be sent is in W
send_char_busy			; Wait for LCD to be ready
	movlw   0xFF		; Set port_C for input
	tris    PORTC
	bcf     LCD_CNTL, RS    ; Set LCD for command mode
	bsf     LCD_CNTL, RW	; Setup to read busy flag
	bsf     LCD_CNTL, E     ; Set E high
	bcf     LCD_CNTL, E     ; Set E low
	movf    LCD_DATA, w     ; Read busy flag, DDram address
	movwf   temp    
	btfsc   temp, 7         ; Check busy flag, high=busy
	goto    send_char_busy
	bcf     LCD_CNTL, RW        
	movlw   0x00
	tris    PORTC		; Set port_C for output
	;end of "busy check"
	movf    char, w          
	movwf   LCD_DATA        ; Send data to LCD
	bcf     LCD_CNTL, RW   ; Set LCD in read mode
	bsf     LCD_CNTL, RS    ; Set LCD in data mode
	bsf     LCD_CNTL, E     ; toggle E for LCD
	bcf     LCD_CNTL, E
	return


;**************************************************************
;* SEND_CND - Sends command contained in register W to LCD    *
;* This routine sends the entire character to the PORT        *
;* The data is transmitted on the PORT<7:0> pins	      *
;**************************************************************

send_cmd_f
	movwf   char		; Command to be sent is in W
send_cmd_busy			; Wait for LCD to be ready
	movlw   0xFF		; Set port_C for input
	tris    PORTC
	bcf     LCD_CNTL, RS    ; Set LCD for command mode
	bsf     LCD_CNTL, RW	; Setup to read busy flag
	bsf     LCD_CNTL, E     ; Set E high
	bcf     LCD_CNTL, E     ; Set E low
	movf    LCD_DATA, w     ; Read busy flag, DDram address
	movwf   temp    
	btfsc   temp, 7         ; Check busy flag, high=busy
	goto    send_cmd_busy
	bcf     LCD_CNTL, RW        
	movlw   0x00
	tris    PORTC		; Set port_C for output
	; end of "busy check"
	movf    char, w          
	movwf   LCD_DATA        ; Send data to LCD
	bcf     LCD_CNTL, RW	; Set LCD in read mode
	bcf     LCD_CNTL, RS    ; Set LCD in command mode
	bsf     LCD_CNTL, E     ; toggle E for LCD
	bcf     LCD_CNTL, E
	return


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

init_f
	clrf    STATUS		; Do initialization (Bank 0)

	movlw   TRIS_READ_LANC
	tris    PORTA		; A0,2,3 inputs, 1 out
	movlw   TRIS_READ_SWITCHES	; RB7 - 5 out, RB3 - 0 inputs 
	tris    PORTB
	movlw   0x00
	tris    PORTC		; RC Port are outputs

	clrf    PORTA		
	clrf    PORTB
	clrf    PORTC

; Initialize the LCD Display Module
	clrf    LCD_CNTL        ; ALL PORT output should output Low.
	movlw   0x038		; Command for 8-bit interface, 2 lines
	movwf   LCD_DATA
	bsf     LCD_CNTL, E
	bcf     LCD_CNTL, E

	movlw   0x75	    ;117 * (3* 256 * 1 us) >> 15 ms...
	call	delay_771

; Command sequence for 2 lines of 5x7 characters
	movlw   0X038
	movwf   LCD_DATA        
	bsf     LCD_CNTL, E     ; toggle E
	bcf     LCD_CNTL, E

	movlw   0x10		;16 * (3* 256 * 1 us) >> 4 ms...
	call	delay_771

	movlw   0X038
	movwf   LCD_DATA        
	bsf     LCD_CNTL, E     ; toggle E
	bcf     LCD_CNTL, E

	movlw   0x02		;2 * (3* 256 * 1 us) >> 100us...
	call	delay_771

	movlw   0X038
	movwf   LCD_DATA        
	bsf     LCD_CNTL, E     ; toggle E
	bcf     LCD_CNTL, E

; Busy Flag should be valid after this point
	movlw   0x38
	call    send_cmd
	movlw   0x08
	call    send_cmd
	movlw   0x01
	call    send_cmd
	movlw   0x06
	call    send_cmd
	movlw   0x0C
	call    send_cmd

;looks OK up to here...11/11/00
;-----------------------------------------------------------------------
;init_f, lanc part
	clrwdt
	movlw	7		;tmr0 prescale to 1:256
	option

	clrf	counter
	clrf	counter2
	clrf	bit_counter
	clrf	bits_to_send
	clrf	byte_to_write
	movlw	0x28
	movwf	command_byte_1
	clrf	command_byte_2
	clrf	byte_number
	clrf	command_pass
	clrf	b1up
	clrf	b1dn
	clrf	b2up
	clrf	b2dn
	clrf	send1
	clrf	sendx
	clrf	char
	clrf	last_val_0

;setup progress indicator characters 00-07
;clear all CG RAM locations
	movlw	66
	movwf	counter

	movlw	0x40		;char 0, line 0
	call	send_cmd	;01 000 000

clear_cg
	movlw	0x00
	call	send_char
	
	decfsz	counter, 1
	goto	clear_cg

;set individual lines from bottome up...
	movlw	0x46		;char 0, line 6 
	call	send_cmd	;01 000 110
	movlw	0xff		;0100 0110
	call	send_char

	movlw	0x4d		;char 1, line 5
	call	send_cmd	;01 001 101
	movlw	0xff		;0100 1101
	call	send_char

	movlw	0x54		;char 2, line 4 
	call	send_cmd	;01 010 100
	movlw	0xff		;0101 0100
	call	send_char

	movlw	0x5b		;char 3, line 3 
	call	send_cmd	;01 011 011
	movlw	0xff		;0101 1011
	call	send_char

	movlw	0x62		;char 4, line 2 
	call	send_cmd	;01 100 010
	movlw	0xff		;0110 0010
	call	send_char

	movlw	0x69		;char 5, line 1 
	call	send_cmd	;01 101 001
	movlw	0xff		;0110 1001
	call	send_char

	movlw	0x70		;char 6, line 0 
	call	send_cmd	;01 110 000
	movlw	0xff		;0111 0000
	call	send_char

	movlw	0x78		;char 7, line 0 
	call	send_cmd	;01 111 000
	movlw	0xff		;0111 1000
	call	send_char
	movlw	0x7e		;char 7, line 6
	call	send_cmd	;01 111 110
	movlw	0xff		;0111 1110
	call	send_char

	movlw	0x80
	call	send_cmd
	movlw	0x00
	call	send_char

; show msg
	movlw	0xc0	;2nd half of display
	call	send_cmd
	movlw	'E'
	call	send_char
	movlw	'x'
	call	send_char
	movlw	'p'
	call	send_char
	movlw	'l'
	call	send_char
	movlw	'o'
	call	send_char
	movlw	'r'
	call	send_char
	movlw	'e'
	call	send_char
	movlw	'r'
	call	send_char
	
	goto 	proc_out
	
	org 0x1d0
	de	"Ed's    LANC    Explorerrev 1.00(c) 2000"


    end

