;**************************************************************************
; rt006cnt.ASM
;
; PROGRAM: Weather forecast timer 
;
; DESCRIPTION: turns on for the Radio 4 Shipping forecasts
; AUTHOR:  Douglas Rice
; Copyright 1998,2002,2005
;
; Test of One button,
;
;
; Want a single button that if pressed quickly increments a counter.
; If there is a pause between rapid presses, then move onto the next digit.
;
; There is a problem with zero, On phone diallers, it is coded as 10, here is it coded as a long press.
;
; Generate events:
;	SHORT_PRESS		- 	If release timer running, then events
;	LONG_PRESS	-
;	
; SHORT_PRESS Start Timer on press, if running on release, then SHORT_PRESS
; ______--______________________
;
; ______tttt__	- Timer is stopped if running and restarted as release timer

; LONG_PRESS 	Start Timer on press, on timout, increment a counter and restart timer.
; ______--------------__
;
; ______tttt|tttt|ttttt_____	- Timer is stopped if running and restarted as release timer
;
;
; reset pressed counter on count
; ______----_______  count ticks while pressed and action on release
;
; During press - count timeouts. These tick at about 1 per second. 
; On release - switch of pressed Counter.
; On release - pressedCounter = 0 -SHORT PRESS increment count and wait long release
; On release - pressedCounter = 1 -LONG  PRESS - ZERO input and move onto next digit, Stop timer
; On release - pressedCounter = 2 -VERY LONG PRESS - RESET digit input pointer, Stop timer  
; On release - pressedCounter > 2 -VERY LONG PRESS - RESET digit input pointer, Stop timer  
;
; On release start a timer to end incrementing the same digit.
;
; On next press, if long release timer is stopped move onto next digit.
; On next press, if long release timer is running increment current digit
;
; long presses stop the timer.
;
; if count = 1 then ZERO 
; if count = 0 then increment count and wait long release
; if pressed while timer running, then increment current digit
;
; The LONG PRESS timer is about 1 second, so a puase of presses of about a seconds moves onto the next digit
; There is also an inactivity timer, which resets the input if no press is pressed for about 10 seconds.
;
;
;
;**************************************************************************

#define dev16F628

;--------------------------------------------------------------------------
; Sec 0. Configs for different chips
;--------------------------------------------------------------------------


;--------------------------------------------------------------------------
; Sec 0.2 Device: 16F84
;--------------------------------------------------------------------------

	ifdef dev16F628


	list      p=16f628            ; list directive to define processor
	#include <p16f628.inc>        ; processor specific variable definitions
	
	__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _INTRC_OSC_CLKOUT  & _MCLRE_OFF & _LVP_OFF

	
	PORTLEDS	EQU	PORTA
	RAMSTART	EQU 0x20

	endif

;--------------------------------------------------------------------------
; Sec 1. Equates and Constants
;--------------------------------------------------------------------------
; The General Purpose Registers start at the end of the 
; Special Purpose Registers.


; IPMentState values
; in normal running or in time setting modes
;
SET_NORM		EQU	0
SET_SET		EQU	2

; STstate flag to indicate if beep is enabled.
; STstate is a variable of flag bits
STrelay		EQU	0
STbeep		EQU	1

; DoTimeSlice bits
; these bits are set to schedule a timer chain event
DTsS4event		EQU	0
DTsSevent		EQU	1
DTsMevent		EQU	2

;--------------------------------------------------------------------------
; Sec 1.1 Button and LED 
;--------------------------------------------------------------------------

	ifdef dev16F628
;PORT_BUTTONS	EQU  PORTB
BUTTON_ONE	EQU	4
BUTTON_SET	EQU	5
;BUTTON_NEXT	EQU	6

	endif

;--------------------------------------------------------------------------
; Sec 1.2 Button and LED 
;--------------------------------------------------------------------------

; PORTB bits
RELAY		EQU	0
RS232OUT		EQU	1
RS232tx		EQU	1

	ifdef dev16F628
SPEAKER		EQU	2
KEYFLASH		EQU	3
	endif



;--------------------------------------------------------------------------
; Sec 1.0 MACROS
;--------------------------------------------------------------------------


TEST_STRADDLE	MACRO	START
	if high( $ ) != high( START ) 
	    Error "Table straddles Page Boundary " + Start
	endif
	endm



;--------------------------------------------------------------------------
; Sec 2.0 Variables
;--------------------------------------------------------------------------
; Variables start 0x20
;

	cblock 	RAMSTART
DoTimeSlice	

CLtmr4sec	; counts quarter seconds

CLnbcdS 	; stores current time
CLnbcdM 
CLnbcdH 

LScnt	; For Loudspeaker beep generation
LScnt2		

SRout 		; for RS232 routines
SRcnt		
SRtxTemp
SRtxCnt

; variables used by Serial input and output routines
RStxTemp
RSloopCnt
RSdelayCnt
RSin
RSout


IPlast	; Input variables
IPnew		

IPbuttonEvent	
IPbuttonEventt	
IPbuttonEventF	
IPsetState	

IPoneTimer
IPoneInactivityTimer
IPoneCnt
IPonePressedCnt

IPonePORTB


; input buffer
IPbuffPointer
IPbuffReg
IPbuffHh
IPbuffhH
IPbuffMm
IPbuffmM
IPbuffEnd

LastVar
	endc


OPbufferStart	EQU	0x30	; 32 bytes of files that can store Dates

;PORT_BUTTONS	EQU  IPonePORTB
PORT_BUTTONS	EQU  PORTB


;--------------------------------------------------------------------------
; Sec 3. Program Code
;--------------------------------------------------------------------------
                
		ORG     0       
         GOTO    Start

		ORG		4
		GOTO 	Intrtn

;--------------------------------------------------------------------------
; Sec 3.1	Main Program Init Code
;--------------------------------------------------------------------------

Start

		; Enable Interupts
		MOVLW	H'00'
		MOVWF	INTCON

		; Set up PortB:7 as output.
		BSF		STATUS, RP0
		
	ifdef dev16F628
		MOVLW	0XF0
		MOVWF	TRISB
		MOVLW	0xE0	; Make PORTLEDS 3:0 outputs to drive LED display
		MOVWF	TRISA
	endif

		BCF		STATUS, RP0
		CLRF	DoTimeSlice	
		CLRF	IPsetState

		CLRF	IPbuttonEventt
		CLRF	IPoneTimer		
		CLRF	IPoneCnt


		CLRF	IPoneInactivityTimer

		MOVLW	10
		MOVWF 	IPoneInactivityTimer	; this timer uses a shitf reg

		
		; the Buffpointer is just before the buffer and stores the absolute address of the file.
		MOVLW	IPbuffReg
		MOVWF	IPbuffPointer

		; Change Prescaler
		CLRWDT
		; Configure Tmr 0
		BSF	STATUS,RP0
		; Set up prescaller for 8192 / 16 = 512 ticks perseconds.
		MOVLW	0x0 + 255 	; For Tmr0 0=/2, 1=/4, 2=/8,3=/16
		MOVWF	OPTION_REG

		BCF	STATUS,RP0

		; Set up prescaller for 8192 / 16 = 512 ticks perseconds.
		MOVLW	0x0 
		MOVWF	CLnbcdS

		MOVLW	0x23
		MOVWF	CLnbcdH

		MOVLW	0x50
		MOVWF	CLnbcdM

		MOVLW	4
		MOVWF	CLtmr4sec
		
		CALL	INsayHello	
		GOTO	MainLoop

MainLoopDebug
		; use the SetPCtoCursor to run this code
		CALL	IPoneReleased
		GOTO	MainLoop

		; use the SetPCtoCursor to run this code
		CALL	IPonePressed
		GOTO	MainLoop

		; use the SetPCtoCursor to run this code
		CALL	IPoneReleased
		GOTO	MainLoop


;--------------------------------------------------------------------------
; Sec 3.2	Main Program 
;--------------------------------------------------------------------------

MainLoop	
	; Enable Interupts
	; Disable Interupts
MLdisableInt	
;		CALL	LSbeep

;		CALL	IPtimeslice

		CALL	CLtimeslice


		; Any events that exist
		BTFSC	DoTimeSlice,DTsS4event	; On 1/4 Second Tick
   		CALL	SS4tick

		; Any events that exist
		BTFSC	DoTimeSlice,DTsSevent	; On Second Tick
		CALL	SStick

		BTFSC	DoTimeSlice,DTsMevent	; On Minute Tick
		CALL	SMtick

; There is nothing done on the Hour
;		BTFSC	DoTimeSlice,DTsHevent	; On Hour Tick
;		CALL	SHtick


		BTFSC	IPbuttonEvent,BUTTON_SET	; On BUTTON_NEXT Press
		CALL	IPsetPressed


		BTFSC	IPbuttonEventt,BUTTON_ONE	; On BUTTON_NEXT Press
		CALL	IPoneChanged

		; CALL	IPtimesliceFast ; also does switch action if edge found.
		GOTO 	MainLoop

		;
		; Debug code - This 
		;
		CALL	IPoneChanged
		GOTO 	MainLoop

		CALL	IPsetPressed
		GOTO 	MainLoop



;--------------------------------------------------------------------------
; Sec 3.3 	Jump Table for running or time setting mode
;---------------------------------------------------------------------------

IPsetJump
		RETURN
		
		
;--------------------------------------------------------------------------
; Sec 4.	Subroutines, procedures and functions
;--------------------------------------------------------------------------

;--------------------------------------------------------------------------
; Sec 4.1	Button Poll Routine
;--------------------------------------------------------------------------
		
IPtimeslice
		;	----___
		;	--_____
		;
		; This reads all Port B inputs and looks for Press
		MOVFW	IPnew
		MOVWF	IPlast
		MOVFW	PORT_BUTTONS
		MOVWF	IPnew
		
		; IP last contains new setting, IPlast contains previous

		;	----___
		;	--_____
		;

		; trigger event on down and up 
		MOVFW	IPnew	; ----______
		XORWF	IPlast,W	; -----_____ 
						; ____-_____
		; now force IPbuttonEvent bits to high for new pressed button
		; the service routine should clear the bit to clear the event.
		IORWF	IPbuttonEventt,F
		; RETURN

		; trigger event on press		
		COMF	IPnew,W	; ____------
		ANDWF	IPlast,W	; -----_____ 
						; ____-_____
		; now force IPbuttonEvent bits to high for new pressed button
		; the service routine should clear the bit to clear the event.
		IORWF	IPbuttonEvent,F
		RETURN

;--------------------------------------------------------------------------
; Sec 4.3	Clock Chain Routine
;--------------------------------------------------------------------------
		
CLtimeslice

		; Assuming:
		; 	Crystal = 32.768 kHz
		;	Prescaller ticks at Crystal / 4 or 8192 ticks per second.
		;	Prescaller set to divide by 8, so
		;	Tmr0 ticks at 128 ticks per second
		;	Tmr0 times out once per 2 seconds.
		;
		BTFSS	INTCON,T0IF
		RETURN

		;slow down the button press code 
		CALL	IPtimeslice

		; TMR0 timeout
		BCF		INTCON,T0IF
		BSF		DoTimeSlice,DTsS4event
		
		; This ticks 1 per second, 
		; 
		DECFSZ	CLtmr4sec,f
		RETURN
		; divide by 4
		MOVLW	10
		MOVWF	CLtmr4sec
		GOTO	CLbcdS

;--------------------------------------------------------------------------
; Sec 4.4	BDC Clock Chain Routine
;--------------------------------------------------------------------------

		; BCD Counter	- Seconds
CLbcdS
		BSF	DoTimeSlice,DTsSevent
		INCF	CLnbcdS,f
		MOVF	CLnbcdS,w
		; binary add bcd digits to make 60 overflow digits.
		ADDLW	0xA6	; 10 + 6 = 16, overflows digit 6 for 10, 7 for 9, 8 for 8, 9 for 7, A for 6
		BC	CLbcdS1
		BDC	CLbcdS2
		RETURN

CLbcdS2		; unit counter carry to tens counter
		MOVFW	CLnbcdS
		; Add 1 to tens, subtract units to zero
		ADDLW	0x10 - 0x0A
		MOVWF	CLnbcdS
		RETURN

CLbcdS1		
		CLRF	CLnbcdS
		; and on to the next counter

		; BCD Counter	- Minutes

CLbcdM
		BSF	DoTimeSlice,DTsMevent	
		INCF	CLnbcdM,f
		MOVF	CLnbcdM,w
		ADDLW	0xA6	; 10 + 6 = 16, overflows digit 6 for 10, 7 for 9, 8 for 8, 9 for 7, A for 6
		BC	CLbcdM1
		BDC	CLbcdM2
		RETURN

CLbcdM2		; unit counter carry to tens counter
		MOVFW	CLnbcdM
		; Add 1 to tens, subtract units to zero
		ADDLW	0x10 - 0x0A
		MOVWF	CLnbcdM
		RETURN

CLbcdM1		
		CLRF	CLnbcdM
		; and on to the next counter

		; BCD Counter	Hours

CLbcdH
;		BSF	DoTimeSlice,DTsHevent
		INCF	CLnbcdH,f
		MOVF	CLnbcdH,w
		ADDLW	0xA6		
		BC	CLbcdH1
		BDC	CLbcdH2
		; check for 24 hours
		MOVF	CLnbcdH,w
		ADDLW 0x00 - 0x24		
		SKPNZ	
		CLRF	CLnbcdH
		RETURN

CLbcdH2		; unit counter carry to tens counter
		MOVFW	CLnbcdH
		ADDLW	0x10 - 0x0A
		MOVWF	CLnbcdH
		RETURN

CLbcdH1		
		CLRF	CLnbcdH
		; and on to the next counter
		RETURN

;--------------------------------------------------------------------------
; Sec 4.5	Event Handler Routines - Timer
;--------------------------------------------------------------------------
SS4tick		;  do this 4 times a second
		BCF	DoTimeSlice,DTsS4event
		RETURN



SStick		
		BCF	DoTimeSlice,DTsSevent
		; Only do serial display when Beep machine is not running as
		; beeps and serial clash
		CALL	IPts
		RETURN
		

SMtick		
		BCF	DoTimeSlice,DTsSevent
		RETURN
		


;--------------------------------------------------------------------------
; Sec 4.6	Event Handler Routine - Buttons
;--------------------------------------------------------------------------
; come here and combine the current state and the current event to index into 
; the state jump table.
;

IPsetPressed	
		;
		; Write out a string of the entered digits
		; 
		; first write the pointer value followed by the string of characters in the buffer.	
		;
			

		BCF		IPbuttonEvent,BUTTON_SET
		CALL	LSblink

		; Print out the buffer
		
		MOVLW	0x0D
		CALL 	RStxChar
		
		MOVLW	0x0A
		CALL 	RStxChar


		MOVLW	-IPbuffReg
		ADDWF	IPbuffPointer,W
		
		CALL SRwrtHexNibble

		MOVLW	" "
		CALL 	RStxChar

		; the Buffpointer is just before the buffer and stores the absolute address of the file.
		MOVLW	IPbuffReg
		MOVWF	FSR


IPsetPressed1	
		; is pointer at the last character
		INCF	IPbuffPointer,W
		SUBWF	FSR,W
		SKPNZ
		RETURN


		; Only display the bottom nibble of each file.	
		MOVFW	INDF
		CALL SRwrtHexNibble
		INCF	FSR,f
		GOTO	IPsetPressed1 

		







;--------------------------------------------------------------	


IPoneChanged	
		BCF		IPbuttonEventt,BUTTON_ONE
		; test for up/down
		BTFSC	IPnew,BUTTON_ONE
		GOTO	IPoneReleased



;
; During press - count timeouts
; On release start a timer to end incrementing the same digit.
; On next press, if timer is stopped move onto next digit.
; On next press, if timer is running increment current digit
; long presses stop the timer.


; reset pressed counter on count
; ______----_______  count ticks while pressed and action on release
;

; if count = 1 then ZERO 
; if count = 0 then increment count and wait long release
; if pressed while timer running, then increment current digit
;
	
		
IPonePressed	
		; reset counter incremented during pressed.
		CLRF	IPonePressedCnt

		; First test if timer is still running to indicate if the same digit is to be imcremented.
		; test if the timer has stopped.
		MOVF	IPoneTimer,f
		SKPNZ	
		GOTO	IPpressAfterLongPause

		; start of press 
		; Increment the current digit.
		MOVFW	IPbuffPointer
		MOVWF	FSR
		INCF	INDF,F

		CALL	LSblink
		CALL	IPstartTimer
		


		RETURN


IPpressAfterLongPause
		; move onto the next digit 
		; NOTE: no range test
		INCF	IPbuffPointer,f
		
		; Clear the next digit.
		MOVFW	IPbuffPointer	
		MOVWF	FSR
		; The user has pressed after a long pause, so start the count at 1
		MOVLW	1
		MOVWF	INDF

		CALL	LSblink
		CALL	IPstartTimer
		
		

		RETURN

		
IPoneReleased
		; The button has been released
		; If a very long press, then reset the state machine
		; If a long press then digit is zero
		; If a short press then increment a digit
		;
		; test if the timer has stopped.
		; If so the button was pressed for a very long time
		MOVF	IPonePressedCnt,W
		BZ		IPReleasedAfterShortPress	; count = 0
		ADDLW	-1
		BZ		IPReleasedAfterLongPress	; count = 1	
		GOTO	IPReleasedAfterVeryLongPress	; count = 2 or more
		
IPReleasedAfterShortPress			
		; Incrementing counter
		; Short press, do nothing until long release
		; If timer still running the 
		CALL	IPstartTimer	
		GOTO	IPReleasedLastThing
		RETURN

IPReleasedAfterLongPress
		; This indicates a long press, zero the current digit and increment pointer
		; Clear the current digit.
		MOVFW	IPbuffPointer
		MOVWF	FSR
		CLRF	INDF

		; Stop the timers to simulate a long pause to move onto the next digit.
		CLRF	IPoneTimer
		GOTO	IPReleasedLastThing
		RETURN


IPReleasedAfterVeryLongPress

IPresetInputBuffer
		; If pressed for a very long time, flash the LED and reset the pointers
		; the Buffpointer is just before the buffer and stores the absolute address of the file.
		; Note the pointer is alway incremented after a long pause, onto the next digit.
		MOVLW	IPbuffPointer
		MOVWF	IPbuffPointer
		; do not start thetimers, so that it is the same as a long press
		; When the next press is made, it is the same as a long press, so moves onto next digit.

		; Stop the timers to simulate a long pause to move onto the next digit.
		CLRF	IPoneTimer

		; We should really prevent a quick press.	
		GOTO	IPReleasedLastThing
		RETURN


IPReleasedLastThing
		; print out presses
		CALL	IPsetPressed
		RETURN
		

IPstartTimer
		; CLRF	IPoneTimer	; clear the timer
		MOVLW	4
		MOVWF 	IPoneTimer	; this timer uses a shitf reg

		MOVLW	20
		MOVWF 	IPoneInactivityTimer	; this timer uses a shitf reg
		
		RETURN
		



IPts
		;
		; Time Slice
		;

		;is IPoneInactivityTimer timer is running, if so decrement it
		;	

		MOVF	IPoneInactivityTimer,
		SKPZ	
		DECFSZ	IPoneInactivityTimer
		GOTO	IPtsActivity
		
		
		
		; timer just timed out
		GOTO	IPresetInputBuffer



IPtsActivity
		;test if timer is running, if so decrement it
		;	
		MOVF	IPoneTimer,f
		SKPNZ
		RETURN
		DECFSZ	IPoneTimer,f
		RETURN
		CALL	LSblink

		; Timeout 		
		; Test if button pressed, if so increment Pressed Counter
		BTFSC	IPlast,BUTTON_ONE
		RETURN
		
IPtsWhilePressed
		INCF	IPonePressedCnt,f
		; restart timer. Already blinked
		CALL	IPstartTimer
		RETURN


;--------------------------------------------------------------	


	
	
	
;--------------------------------------------------------------------------
; Sec 5.9 Initilization code - 
;--------------------------------------------------------------------------


INinit
	; Enable Interupts
	MOVLW	H'00'
	MOVWF	INTCON

	CLRF PORTA ;Initialize PORTA by setting
	;output data latches
	BANKSEL CMCON
	MOVLW 0X07 ;Turn comparators off and
	MOVWF CMCON ;enable pins for I/O


	banksel	TRISA
	MOVLW	0XF0
	MOVWF	TRISB
	MOVLW	~( 1 << RS232tx )	; Make PORTA 3:0 INPUTS.
	MOVWF	TRISA
	banksel	0


	; Change Prescaler
	CLRWDT

	; Configure Tmr 0
	BSF		STATUS,RP0
	; Set up prescaller for 8192 / 16 = 512 ticks perseconds.

	MOVLW	0x0 + 2 	; For Tmr0 0=/2, 1=/4, 2=/8,3=/16
	MOVWF	OPTION_REG
	BCF		STATUS,RP0

	; Configure Tmr 1
	MOVLW	0x0 | 1<<TMR1ON | 3 <<T1CKPS0 
	MOVWF	T1CON


	CLRF	DoTimeSlice	
	CLRF	IPbuttonEvent

	RETURN

INsayHello	
	; print out power on message
	MOVLW	0x0D
	CALL 	RStxChar
		
	MOVLW	0x0A
	CALL 	RStxChar

	MOVLW	'S'
	CALL 	RStxChar
		
	MOVLW	'R'
	CALL 	RStxChar
		
	MOVLW	0x0D
	CALL 	RStxChar
		
	MOVLW	0x0A
	CALL 	RStxChar
	return

;--------------------------------------------------------------------------
; Sec 5.10 	EEprom Routines for 16F628
;--------------------------------------------------------------------------

EEread		
		; w contains address
		banksel	EEADR	
		MOVWF	EEADR
		BSF		EECON1,RD
		MOVFW	EEDATA
		banksel	0	
		RETURN

EEsetAddr
		banksel	EEADR
		MOVWF	EEADR
		RETURN
		
EEwrt		; blocking, EEADR and EEDATA set up.
		;		BSF	STATUS,RP0
		banksel 	EEDATA
		MOVWF	EEDATA
		BCF		INTCON,GIE
		BCF		EECON1,EEIF
		BSF		EECON1,WREN
		MOVLW	0x55
		MOVWF	EECON2
		MOVLW	0xAA
		MOVWF	EECON2
		BSF		EECON1,WR
		; Now wait for EEwrt to finish write
EEwaitForWrt	; block until EEPROM write has finished.
		BCF		EECON1,WREN	; disable EROM
		BTFSC	EECON1,WR
		GOTO	EEwaitForWrt
		BCF		EECON1,EEIF	; EEPROM finished
		; BCF	STATUS,RP0

		banksel	0	
		RETURN
		
;--------------------------------------------------------------------------
; Sec 5.6 	Serial Output Routines
;--------------------------------------------------------------------------


SRwrtHexNibble	; currently only displays 0..9, A..F
	ANDLW	0x0F
	ADDLW	0x06	; is it A..F, if so trigger a digit overflow
	SKPNDC
	ADDLW	7; subtract 10, then add 'A'-'0'
	ADDLW	0x30-6	; Subtract extra 6 added to cause DC
	MOVWF	RSout
	GOTO	RStxChar

SRtxChar
RStxChar
	;
	; Output Start Bit
	; Start bit is low, data bits are inverted
	;
	
	movwf	RStxTemp
	comf	RStxTemp,f
	BCF		PORTA,RS232tx
	MOVLW	~( 1 << RS232tx )

	; Make RS232 pin an ouput while transmitting character
	BSF		STATUS, RP0
	MOVWF	TRISA		
	BCF		STATUS, RP0

	; 1200 baud output
	; move the char into RStxtemp, it is destroyed.
	;Start Bit
	BSF		PORTA,RS232tx

	call	RSdelayBit

	; number of bits.
	;movlw	8

	; someimes the receiving device is too slow, 
	; so if I use 16 bits, I add 8 stop bits
	movlw	0x10
	movwf	RSloopCnt

RStxCharLp1
	
	; After start bit, which is 1, then test each bit
	; I need to set PA:0 to same as LSB RStxTemp
	; this compares PA:0 with RStxTemp so see if it needs toggling
	; The xorwf PORTA,f causes the bit to be toggled if required.
	
	
	RRF		RStxTemp,f
	movfw	STATUS
	andlw	1 << C			; mask off bit
	addlw   ( 1 << RS232tx) -1	; shift bit by using a ripple carry
	xorwf	PORTA,W			; Doeas output need toggling ?
	andlw	1 << RS232tx		; Mask off output pin	
	xorwf	PORTA,f			; Toggle output pin if needed	
	call	RSdelayBit			; delay bit
	
	
	decfsz	RSloopCnt
	goto	RStxCharLp1

	; apply stop bit
	BCF		PORTA,RS232tx
	call	RSdelayBit
	call	RSdelayBit	

	; Make RS232 pin an input so that main loop can test for start bit
	BSF		STATUS, RP0
	BSF		TRISA,  RS232tx
	BCF		STATUS, RP0

	RETURN


; timing functions to delay serial routines for a bit or half bit.

RSdelayHalfBit		
		MOVLW	0x1D		; shorten delay as edge detector takes about 22 us for 4800 baud
		GOTO	RSdelayBit0			

RSdelayBit		
		NOP
		MOVLW	0x40	 ; for 4800 baud	

RSdelayBit0			
		MOVWF	RSdelayCnt
RSdelayBit1	DECFSZ	RSdelayCnt		; 1
		GOTO	RSdelayBit1		; 2 clk
		CLRWDT
		RETURN


	
;--------------------------------------------------------------------------
; Sec 4.9	Serial Out Display Procedure
;--------------------------------------------------------------------------

SRwrtCount
		RETURN


SRwrtTime
		RETURN






;--------------------------------------------------------------------------
; Sec 4.2	Loudspeaker tone generator, and Key Click
;--------------------------------------------------------------------------


LSblink
	;	MOVLW	0x60
		MOVLW	0xFF

LSblinkn		
		MOVWF	LScnt
		MOVLW	1<< KEYFLASH | 1<< SPEAKER
		XORWF	PORTB,f

LSblink0
		DECFSZ	LScnt,F
		GOTO	LSblink0
		MOVLW	1<< KEYFLASH | 1<< SPEAKER
		XORWF	PORTB,f

		RETURN


LSbeeeep
		MOVLW	0x60
		GOTO	LSbeepn

LSbeep		
		MOVLW	0x20
LSbeepn	
		; come here with duration in W
		; make pause between beeps = beep length
		MOVWF	LScnt
		MOVWF	LScnt2

LSbeep0
		MOVLW	1 << SPEAKER
		XORWF	PORTB,f

		DECFSZ	LScnt,f
		GOTO	LSbeep0
		; now delay for silence
LSbeep3
		GOTO 	$+1
		GOTO 	$+1
		DECFSZ	LScnt2,f
		GOTO	LSbeep3

LSbeep5
		
		RETURN	



;--------------------------------------------------------------------------
; Sec 5.0	Interrupt Routines
;--------------------------------------------------------------------------

Intrtn		
		; Which Interupt ?
		; No Context Save in these routines.
		BTFSC	INTCON,2
		GOTO	IntTmr0
		BTFSC	INTCON,1
		GOTO	Intfint
		BTFSC	INTCON,0
		GOTO	IntRbport
IntTmr0
		BCF INTCON,2
		RETFIE
Intfint
		BCF INTCON,1
		RETFIE
IntRbport
		BCF INTCON,0
		RETFIE

;--------------------------------------------------------------------------
; Program End
;--------------------------------------------------------------------------

;--------------------------------------------------------------------------
; EEPROM data
;--------------------------------------------------------------------------

 
		ORG	0x2100
              END


