Source file: /~heha/basteln/m/Kram/SimpleMaus.zip/SimpleMaus_v2-1.a14

;;======================================================================;;
;;				SimpleMaus		 		;;
;;======================================================================;;
;;									;;
;; Program:		SimpleMaus -- Lokmaus throttle			;;
;; Code:		Paco Cañada ( http://www.fut.es/~fmco )		;;
;; Platform:		Microchip PIC16F628, 4 Mhz			;;
;; Date:		01.02.2006					;;
;; First release:	16.02.2006					;;
;; LastDate:		16.08.2018					;;
;;									;;
;;======================================================================;;
;Tab width = 8, EOL = LF, Charset = ANSI (required to be binary compatible to ñ character in EEPROM space ... brr)

; This program is for a simple LokMaus throttle (Lenz XBus).
; It uses two LED display with only a common resistor (only one segment light at the same time)
; Uses PWM output (19200Hz) for analog voltage output that is compared with potentiometer voltage
; in 32 steps

; Processor PIC 16F628 running at 4MHz internal oscillator.
;
; Revisions:
;
; 01/02/2006	Start of writing code.
; 07/02/2006	First prototype. RA4 need external pull-up. Communication works
; 10/02/2006	Read pot. routines, added setup pot. and display
; 12/02/2006	Added display flashing
; 13/02/2006	Added save current loco 
; 14/02/2006	Added stabilization time on reconection
; 16/02/2006	Changed direction / steps menu and clear keys status on start-up
; 31/10/2006	Change direction directly on pushbutton. F1 and F2 supported.

; Hardware: Four keys, one potentiometer,
;   two 7-segment displays (dp not used), one RS485 transceiver
;RA0	17		Key "Sel", Segment "a"
;RA1	18	AN1	lowpass filtered PWM for analog comparator
;RA2	1	AN2	potentiometer to analog comparator
;RA3	2		First digit, common cathode
;RA4	3		Second digit, common cathode
;RA5	4	(!MCLR)	Keypress detect, H-active (This pin is input-only)
;RA6	15		Key "F1/-", Segment "g"
;RA7	16		Key "F0/+", Segment "f"
;RB0	6		MAX485 driver signal, H=send, L=receive
;RB1	7	RX	MAX485 Rexeive
;RB2	8	TX	MAX485 Send
;RB3	9	CCP1	PWM output for A/D conversion
;RB4	10		Key "STOP", Segment "b"
;RB5	11		Segment "c"
;RB6	12		Segment "d"
;RB7	13		Segment "e"

; ----- Definitions

#define	__VERNUM	0x02
#define	__VERREV	" "
#define	__VERDAY	0x30
#define	__VERMONTH	0x10
#define	__VERYEAR	0x06

	list    p=16F628,r=DEC

	errorlevel -302
	errorlevel -306

	INCLUDE "P16F628.INC"


	__FUSES _BODEN_ON & _CP_OFF & _PWRTE_ON & _WDT_OFF & _LVP_OFF & _MCLRE_OFF  & _INTRC_OSC_NOCLKOUT

; ----- Macros

#define	DNOP		goto	$+1

; ----- Constant values

FXTAL	equ	4000000		; Internal oscillator frequency
BaudRate equ	62500		; XBus serial speed

; --- Xbus constants

BROADCAST	equ	0x60	; broadcast call byte

; --- Display constants

MENU_RUN	equ	0x00
MENU_LOK	equ	0x04
MENU_DIR	equ	0x08
MENU_SETUP	equ	0x0C
MENU_XBUS	equ	0x10
MENU_POT	equ	0x14
MENU_FNC	equ	0x18

CHR_P		equ	0x0D
CHR_E		equ	0x0E
CHR_SPC		equ	0x0F
CHR_L		equ	0x10
CHR_D		equ	0x11
CHR_A		equ	0x12


; --- EEPROM Section

ADR_MEM		equ	0x00	; Xbus address EEPROM location
LOK_MEM		equ	0x01	; Last loco used
POT_MEM		equ	0x02	; Potentiometer offset


; ----- Variables

; --- Internal RAM Section

; --- Top on all banks

INT_W		equ	0x70	; Interrupt variables.
INT_STAT	equ	0x71
INT_PCLATH	equ	0x72
INT_FSR		equ	0x73

EEDATA0		equ	0x7B	; EEPROM shadow variables
EEADR0		equ	0x7C


; --- Bank 0

BUFRXINI	equ	0x20	; first input buffer location
HEADER		equ	0x20	; Xbus packet
DATA1		equ	0x21
DATA2		equ	0x22
DATA3		equ	0x23
DATA4		equ	0x24
DATA5		equ	0x25
;
BUFRXEND	equ	0x31	; last reception buffer location
KEYFLAG		equ	0x35	; Keyboard flags

R0		equ	0x38	; General & Bin to BCD registers
R1		equ	0x39
LSB		equ	0x3A
MSB		equ	0x3B

DUMMY		equ	0x3C	; Temporary values
TEMP		equ	0x3D
TEMP2		equ	0x3E
COUNT		equ	0x3F

CALLBYTE	equ	0x40	; call byte byte from command station
MY_ADR		equ	0x41	; XpressNet Address for normal inquiry messages
TXPOS		equ	0x42	; Serial Buffer output pointers
TXCNT		equ	0x43
RX_XOR		equ	0x44	; Serial incoming checksum
RX_LEN		equ	0x45	; Incomming message length
XFLAGS		equ	0x46	; XpressNet flags
XBUS_VER	equ	0x47	; XpressNet version
XBUS_STA	equ	0x48	; Command Station type
FLAGS		equ	0x49	; Flags

DCC_STATUS	equ	0x4F	; Command Station Status

CURRMTR		equ	0x52	; Current Loco Multi-Unit
CURRADR		equ	0x53	; Current Loco address
CURRSPD		equ	0x54	; Current Loco speed
CURRFNC		equ	0x55	; Current Loco functions

POT_SAVED	equ	0x58	; pot saved values for calc mid value (0x38..0x3F)
;
POT_INDEX	equ	0x60	; Index to POT_SAVE
POT_CNT		equ	0x61	; current pot value
OFFSET		equ	0x62	; pot. offset
SPEED		equ	0x63	; current speed
DIGITH		equ	0x64	; Display. Dizaines
DIGITL		equ	0x65	; Display. Units
SEGMENT		equ	0x66	; segment displayed
ROW		equ	0x67	; Key row scanned
KEYST		equ	0x68	; Keys status
NEWKEY		equ	0x69	; Keys pressed
DEBOUNCE	equ	0x6A	; debounce time
MENU		equ	0x6B	; current menu
FLASH		equ	0x6C	; flashing sequence

; --- Buffers

BUFTXINI	equ	0xA0	; XpressNet Serial output buffer

;----- Flags

#define	NEW_TX		XFLAGS,0	; new message to command station
#define	TXMIT		XFLAGS,1	; transmiting a message
#define	RCVING		XFLAGS,2	; receiving a message
#define	NEW_MSG		XFLAGS,3	; received new message to us

#define	EmergStop	DCC_STATUS,0	; System in Emergency Stop
#define	EmergOff	DCC_STATUS,1	; System in Emergency Off
#define	AutoStart	DCC_STATUS,2	; System in auto start-up. Not used
#define	ServiceMode	DCC_STATUS,3	; System in Service Mode

#define	LOCO_OTHER	FLAGS,0		; current loco is controlled by other device
#define	MULTIUNIT	FLAGS,2		; Current is multiunit address
#define	SEL_SETUP	FLAGS,3		; Setup selection

#define	KeyHit		KEYFLAG,0	; Key hitted
#define	ServKey		KEYFLAG,1	; Key need service
#define	DbnceOn		KEYFLAG,2	; Key debounce time
#define	KeyRep		KEYFLAG,3	; Key repeated
#define	TEST_AD		KEYFLAG,4	; Pot change discard

Loco128	equ	7			; CURRFNC bit definition
Loco28	equ	6
LocoDir	equ	5
LocoFL	equ	4
LocoF4	equ	3
LocoF3	equ	2
LocoF2	equ	1
LocoF1	equ	0

; --------------- Program Section --------------------------------------
PowerUp:
	clrf	INTCON		; Disable all interrupts
	clrf	PCLATH		; Tables on page 0
	clrf	STATUS		; reset flags
	goto	INIT
; ----- ISR (Interrupt Service Routines)
	movwf	INT_W		; 1 Save registers W, STATUS, PCLATH, FSR
	swapf	STATUS,w	; 2
	clrf	STATUS		; 3 Ensure port / timer access in bank 0
	movwf	INT_STAT	; 4
;		movf	PCLATH,w		; 
;		movwf	INT_PCLATH		; save PCLATH, interrupt uses page 0
;		clrf	PCLATH			; 
	movf	FSR,w		; Save FSR
	movwf	INT_FSR

IntRx:
	btfss	PIR1,RCIF	; serial receive interrupt?
	 goto	IntTx

	btfss	RCSTA,OERR	; yes, handle RX errors
	 btfsc	RCSTA,FERR
	 goto	IntError

	btfss	RCSTA,RX9D	; is the call byte?
	 goto	IntRxData	; no
IntRxCallByte:
	bcf	RCVING		; yes, abort message in progress
	clrf	RX_LEN
	movf	RCREG,w		; get call byte and save it
	movwf	CALLBYTE
	btfsc	NEW_MSG		; decoded last message?
	 goto	IntRestore	; no, ignore this call byte
	xorlw	BROADCAST	; broadcast call byte? ('P1100000')
	btfsc	STATUS,Z
	 goto	IntRxPacket	; yes, new message
	movf	CALLBYTE,w	; message to us?
	xorwf	MY_ADR,w	;     'P10AAAAA' anything to transmit?
	btfsc	STATUS,Z
	 goto	IntRxSend	; yes, answer before 80us
	xorlw	b'10100000'	; no, 'P11AAAAA' message to us?
	btfsc	STATUS,Z
	 goto	IntRxPacket	; yes, new message
	xorlw	b'01100000'	; no, 'P00AAAAA' acknowledge?
	btfsc	STATUS,Z
	 goto	IntRxAck	; yes, send ack
	goto	IntRestore	; no, discard

IntRxPacket:
	clrf	RX_XOR		; set receiving a message
	bsf	RCVING
	goto	IntRestore
		
IntRxData:
	movlw	BUFRXINI	; save data
	addwf	RX_LEN,w
	movwf	FSR
	movf	RCREG,w		; get data byte to clear interrupt
	btfss	RCVING		; are we receiving a packet for us?
	 goto	IntRestore	; no, discard data byte
	movwf	INDF		; yes, save data
	xorwf	RX_XOR,f	; checksum
	incf	RX_LEN,f	; next byte
	movlw	BUFRXINI	; check end of message
	movwf	FSR
	movf	INDF,w		; get header byte
	andlw	0x0F		; length to receive
	addlw	0x02		; plus header and xor-byte
	xorwf	RX_LEN,w	; equal to received length?
	btfss	STATUS,Z
	 goto	IntRestore	; no, receive more bytes
IntRxEnd:
	bcf	RCVING		; yes, end of receiving data
	movf	RX_XOR,w
	btfsc	STATUS,Z	; xor-byte correct?
	bsf	NEW_MSG		; yes, received new packet
	goto	IntRestore
	
IntRxAck:			; Acknowledge transmision (send 0x20, 0x20)
	bsf	PORTB,0		; MAX485 TX enable
	movlw	0x20
	movwf	TXREG
	banksel TXSTA	;Bank 1
IntTxAck:
	btfss	TXSTA,TRMT	; wait until end of byte transmited
	 goto	IntTxAck
	banksel TXREG	;Bank 0
	movlw	0x20		; send second byte
	movwf	TXREG
	goto	IntTxEnd	; wait until transmited
IntRxSend:
	btfss	NEW_TX		; new message to command station?
	 goto	IntRestore	; no
	bsf	PORTB,0		; MAX485 TX enable
	banksel PIE1	;Bank 1
	bsf	PIE1,TXIE	; Enable TX interrupts
	banksel TXPOS	;Bank 0		
	clrf	TXPOS
	bsf	TXMIT		; now transmiting
	goto	IntTxByte
IntError:
	movf	RCREG,w		; on error re-init receiver
	bcf	RCSTA,CREN
	bsf	RCSTA,CREN
IntTx:
	btfss	PIR1,TXIF	; serial transmit interrupt?
	 goto	IntRestore	; no, nothing to do
	btfss	TXMIT		; yes, still transmiting?
	 goto	IntTxEnd	; no, disable TX interrupts
IntTxByte:
	movlw	BUFTXINI	; calc buffer position
	addwf	TXPOS,w
	movwf	FSR
	movf	INDF,w		; get byte from buffer
	movwf	TXREG		; and send it
	incf	TXPOS,f
	decfsz	TXCNT,f		; last byte?
	 goto	IntRestore	; no
	bcf	NEW_TX		; yes, stop transmiting
	bcf	TXMIT
IntTxEnd:
	banksel TXSTA	;Bank 1
IntTxDone:
	btfss	TXSTA,TRMT	; wait until end of last byte transmited
	 goto	IntTxDone
	bcf	PIE1,TXIE	; Disable TX interrupts
	DNOP
	DNOP
	DNOP
	banksel PORTB	;Bank 0
	bcf	PORTB,0		; MAX485 TX disable
IntRestore:
	movf	INT_FSR,w	;  Restore the Context Registers and Return
	movwf	FSR
;		movf	INT_PCLATH,w
;		movwf	PCLATH
	swapf	INT_STAT,w
	movwf	STATUS
	swapf	INT_W,f
	swapf	INT_W,w
	retfie

; ----- Tables on first 256 bytes

BitConvert:
	andlw	0x07
	addwf	PCL,f		; Convert bit position to byte mask
	retlw	0x01
	retlw	0x02
	retlw	0x04
	retlw	0x08
	retlw	0x10
	retlw	0x20
	retlw	0x40
	retlw	0x80

Digit_RA:
	addwf	PCL,f		; return bit patterns for each digit
	retlw	b'10000001'	; '0'             a
	retlw	b'00000000'	; '1'          xxxxxx
	retlw	b'01000001'	; '2'      f  x      x b
	retlw	b'01000001'	; '3'         x   g  x
	retlw	b'11000000'	; '4'          xxxxxx
	retlw	b'11000001'	; '5'      e  x      x c
	retlw	b'11000001'	; '6'         x      x
	retlw	b'00000001'	; '7'          xxxxxx
	retlw	b'11000001'	; '8'             d
	retlw	b'11000001'	; '9'
	retlw	b'01000000'	; '-'	bits	76543210
	retlw	b'00000000'	; '_'	segment	fgXXXXXa   (X = port)
	retlw	b'00000001'	; '~'
	retlw	b'11000001'	; 'P'
	retlw	b'11000001'	; 'E'
	retlw	b'00000000'	; ' '
	retlw	b'10000000'	; 'L'
	retlw	b'01000000'	; 'd'
	retlw	b'11000001'	; 'A'

Digit_RB:
	addwf	PCL,f		; return bit patterns for each digit
	retlw	b'11110000'	; '0'             a
	retlw	b'00110000'	; '1'          xxxxxx
	retlw	b'11010000'	; '2'      f  x      x b
	retlw	b'01110000'	; '3'         x   g  x
	retlw	b'00110000'	; '4'          xxxxxx
	retlw	b'01100000'	; '5'      e  x      x c
	retlw	b'11100000'	; '6'         x      x
	retlw	b'00110000'	; '7'          xxxxxx
	retlw	b'11110000'	; '8'             d
	retlw	b'01110000'	; '9'
	retlw	b'00000000'	; '-'	bits	76543210
	retlw	b'01000000'	; '_'	segment	edcbXXXX   (X = port)
	retlw	b'00000000'	; '~'
	retlw	b'10010000'	; 'P'
	retlw	b'11000000'	; 'E'
	retlw	b'00000000'	; ' '
	retlw	b'11000000'	; 'L'
	retlw	b'11110000'	; 'd'
	retlw	b'10110000'	; 'A'

GetSegment:
	andlw	0x07			; don't mind digit
	addwf	PCL,f
	goto	KeyRow
	retlw	b'00000001'	; RA a	fgXXXX0a	bit1: 0:PORTA, 1:PORTB
	retlw	b'00010010'	; RB b	edcbXX1X
	retlw	b'00100010'	; RB c	edcbXX1X
	retlw	b'01000010'	; RB d	edcbXX1X
	retlw	b'10000010'	; RB e	edcbXX1X
	retlw	b'10000000'	; RA f	fgXXXX0a
	retlw	b'01000000'	; RA g	fgXXXX0a

KeyRow:
	movf	ROW,w		; ROW: 0..3 (4 keys)
	addwf	PCL,f	
	retlw	b'00000001'	; RA a	fgXXXX0a	bit1: 0:PORTA, 1:PORTB		
	retlw	b'00010010'	; RB b	edcbXX1X
	retlw	b'10000000'	; RA f	fgXXXX0a
	retlw	b'01000000'	; RA g	fgXXXX0a

KeyServ:
	bcf	ServKey			; Key pressed service routines
	btfsc	ServiceMode		; discard in Service Mode
	 return
;		btfsc	NEWKEY,SEL_KEY
	movlw	0x00
	btfsc	NEWKEY,7	; F0 key output
	 movlw	0x01
	btfsc	NEWKEY,6	; F1 key output
	 movlw	0x02
	btfsc	NEWKEY,4	;STOP_KEY
	 movlw	0x03		; go into current menu options
	addwf	MENU,w
	addwf	PCL,f
Menu00Run:
	goto	K_EnterLok	; Normal Operations
	goto	K_ChangeDirRun	; K_F1 	***
	goto	K_Light		; 	***
	goto	K_Stop
Menu04Lok:
	goto	K_EnterFunc	;Dir	; Change Loco number ***
	goto	K_LokUp
	goto	K_LokDwn
	goto	K_Stop
Menu08Dir:
	goto	K_EnterRun	; Change Loco Dir/Step
	goto	K_ChangeDir
	goto	K_ChangeStep
	goto	K_Stop
Menu0CSetup:
	return			; Setup
	goto	K_SelSetup
	goto	K_EnterPar
	goto	INIT
Menu10Xbus:
	goto	K_SelSetup	; Change Xbus address
	goto	K_XbusUp
	goto	K_XbusDwn
	goto	INIT
Menu14Pot:
	goto	K_SelSetup	; Change pot offset
	goto	K_OffsetUp
	goto	K_OffsetDwn
	goto	INIT
Menu18Fnc:
	goto	K_EnterDir	; Additional functions
	goto	K_F1
	goto	K_F2
	goto	K_Stop

	if ($ > 255) 
		ERROR "  Tables exceded page 0.   If it works, why do you change it?   "
	endif


; ----- Initialization

INIT:
	clrf	RCSTA			; disable UART
	movlw   0x18			; display off, receive
	movwf   PORTA                         
	movlw   0x00			; all zero
	movwf   PORTB
	banksel TRISB	;Bank 1
	movlw	0x06	; all outputs except serial port
	movwf   TRISB
	movlw   0x26	; RA1,RA2: comparator input,RA5: key input
	movwf   TRISA
	movlw	0x20	; RX interrupt
	movwf	PIE1	; peripheral interrupts
	movlw   0x81	; Option reg: timer prescaler 1:4, no pull-ups
			; Port B Pull-up:         1   disabled
			; External int edge:      0   falling
			; Timer trigger source:   0   clock
			; Timer trigger edge:     0   rising
			; Prescaler assignment:   0   Timer0
			; Prescaler value:	001   1:4
	movwf   OPTION_REG
	movlw	0x0B		; internal oscillator to 4MHz default
	movwf	PCON
	movlw	0x00		; VRR off
	movwf	VRCON
	banksel CMCON	;Bank 0
	movlw	0x05		; RA1, RA2 analog inputs
	movwf	CMCON                          
	movlw	0x31		; Timer 1. Run, set 1:8 Prescaler
	movwf	T1CON
	movlw	0x04		; Timer 2. Run with 1:1 Prescaler
	movwf	T2CON
	movlw	0x20		; Clear variables bank0
	movwf	FSR
ClearRAM:
	clrf	INDF
	incf	FSR,f
	btfss	FSR,7
	 goto	ClearRAM
	call	SetMyAddress	; get Xbus address
	call	UART_INI	; Init peripheals
	bcf	PORTB,0		; MAX485 TX disable just to be sure
	call	IniPWM		; 
	movlw	0xC0		; GIE enable, PEIE enable
	movwf	INTCON
;		bsf	PORTA,SEL_KEY		; Enter setup mode if SEL pressed
	movlw	0x19
	movwf	PORTA
	DNOP
	DNOP
	movlw	0x0A		; Diplay '--'
	movwf	DIGITH
	movwf	DIGITL
	movlw	0xFF		; no flash
	movwf	FLASH
	DNOP
	DNOP
	btfsc	PORTA,5		; Key input
	 goto	Setup
	movlw	LOK_MEM		; get last loco used
	call	EE_Read
	movwf	CURRADR
	movlw	0x00		; stop default
	movwf	CURRSPD
	movlw	b'01100000'	; default 28 steps, forward, FL,F1..F4 off
	movwf	CURRFNC
	call	GetVersion	; get command station version & type
	clrf	TMR1L		; time to transmit to command station
	clrf	TMR1H
	bcf	PIR1,TMR1IF
FindStation:
	btfsc	INTCON,T0IF	; update display and keyboard
	 call	TimerOut
	btfsc	NEW_MSG		; new message received?
	 call	HandleMsg	; yes, handle it
	btfsc	PIR1,TMR1IF
	 call	NotFound	; timeout
	btfsc	NEW_TX		; packet sended, command station present
	 goto	FindStation
;		bsf	T1CON,TMR1ON		; Timer1 on to be sure
	call	GetStatus	; get current status
	movlw	0x01		; Timer 1. Run, set 1:1 Prescaler
	movwf	T1CON
	clrf	TMR1L		; time to transmit changes to command station
	clrf	TMR1H		; and read keys and pot value
	bcf	PIR1,TMR1IF
MainLoop:
	call	K_EnterRun	; show last loco used and get info
	call	GetLocoInfo
	bsf	TEST_AD
	movlw	0x10
	movwf	MSB
		
MainStabilize:
	btfsc	INTCON,T0IF	; update display and keyboard
	 call	TimerOut
	btfsc	NEW_MSG		; new message received?
	 call	HandleMsg	; yes, handle it
	btfss	PIR1,TMR1IF	; wait stabilize time 1 sec
	 goto	MainStabilize
	bcf	PIR1,TMR1IF
	decfsz	MSB,f
	 goto	MainStabilize
	movlw	0xF0		; clear keys status
	andwf	KEYFLAG,f
	clrf	KEYST

Loop:
	btfsc	INTCON,T0IF	; update display and keyboard
	call	TimerOut

	btfsc	NEW_MSG		; new message received?
	call	HandleMsg	; yes, handle it

	btfsc	PIR1,TMR1IF	; read pot value if needed
	call	FlashPotSpeed

	btfsc	ServKey		; key need service?
	call	KeyServ		; yes, do action

	goto	Loop

; --- No Command Station avaiable
NotFound:
	bcf	PIR1,TMR1IF
	movlw	CHR_E		; show error 'E7'. SimpleMaus not addressed
	movwf	DIGITH
	movlw	0x07
	movwf	DIGITL
	return
; --- Setup Loop
Setup:
	call	K_EnterSetup	; Select Menu setup
	movlw	0x01		; Timer 1. Run, set 1:1 Prescaler
	movwf	T1CON
SetupLoop:
	btfsc	PIR1,TMR1IF	; show pot value if needed
	 call	ShowPot
	btfsc	INTCON,T0IF	; update display and keyboard
	 call	TimerOut
	btfsc	ServKey		; key need service?
	 call	KeyServ		; yes, do action
	goto	SetupLoop

; --- Xbus Incoming messages
HandleMsg:	; Handle incoming messages
Handle6X:
	movf	HEADER,w
Handle61:
	xorlw	0x61
	btfss	STATUS,Z
	 goto	Handle6X_2
Handle61_0:
	movf	DATA1,w
	btfss	STATUS,Z
	 goto	Handle61_1

	btfsc	EmergOff	; second transmision
	 goto	HandleEnd
	bcf	ServiceMode	; Track power off
	bsf	EmergOff
	bcf	EmergStop
HandleOff:
	movlw	CHR_E		; display 'E0'
	movwf	DIGITH
	movlw	0x00
	movwf	DIGITL
	call	SetFlash
	goto	HandleHomeEnd
				
Handle61_1:
	xorlw	0x01
	btfss	STATUS,Z
	 goto	Handle61_2

	bcf	ServiceMode	; normal operations resume
	bcf	EmergOff
	bcf	EmergStop
HandleResume:
	movf	CURRADR,w	; show current loco 
	call	DispBin 
	call	SetFlash
	movf	DCC_STATUS,w	; second transmision?
	andlw	b'00001011'
	btfsc	STATUS,Z
	 goto	HandleHomeEnd	; yes, prevent hanging
	bcf	NEW_MSG		; message processed
	call	GetLocoInfo	; get loco info
	goto	HandleHomeEnd

Handle61_2:
	xorlw	(0x01 ^ 0x02)
	btfss	STATUS,Z
	 goto	HandleEnd
	btfsc	ServiceMode	; second transmision
	 goto	HandleEnd
	bsf	ServiceMode	; Service Mode entry
	bcf	EmergOff
	bcf	EmergStop
HandleServ:
	movlw	0x05		; display 'SP'
	movwf	DIGITH
	movlw	CHR_P
	movwf	DIGITL
	call	SetFlash
	goto	HandleHomeEnd
Handle6X_2:
	xorlw	(0x61 ^ 0x62)
	btfss	STATUS,Z
	 goto	Handle6X_3
Handle62:
	movf	DATA1,w
	xorlw	0x22
	btfss	STATUS,Z
	 goto	HandleEnd

	movf	DATA2,w		; Commnad station status response
	movwf	DCC_STATUS

	btfsc	ServiceMode	; set correct status
	 goto	HandleServ
	btfsc	EmergOff
	 goto	HandleOff
	btfsc	EmergStop
	 goto	HandleStop
	goto	HandleResume

Handle6X_3:
	xorlw	(0x62 ^ 0x63)
	btfss	STATUS,Z
	 goto	Handle8X
Handle63:
	movf	DATA1,w
	xorlw	0x21
	btfss	STATUS,Z
	 goto	HandleEnd

	movf	DATA2,w		; software version
	movwf	XBUS_VER
	movf	DATA3,w
	movwf	XBUS_STA
	goto	HandleEnd
		
Handle8X:
	movf	HEADER,w
Handle81:
	xorlw	0x81
	btfss	STATUS,Z
	 goto	HandleEX
	movf	DATA1,w
	btfss	STATUS,Z
	 goto	HandleEnd
	btfsc	EmergStop	; second transmision
	 goto	HandleEnd
	bcf	ServiceMode	; Emergency stop
	bcf	EmergOff
	bsf	EmergStop
HandleStop:
	movlw	CHR_E		; show error 'ES'. Emergency stop
	movwf	DIGITH
	movlw	0x05
	movwf	DIGITL
	call	SetFlash
	goto	HandleHomeEnd
HandleEX:
	movf	HEADER,w		
HandleEX_1:
	xorlw	0xE1		; MU+DH errors
	btfss	STATUS,Z
	 goto	HandleEX_2
HandleE1:
	movf	DATA1,w
	xorlw	0x88		; stack full
	btfss	STATUS,Z
	 goto	HandleEnd
HandleFull:
	movlw	0x05		; show error 'S-'. Stack full
	movwf	DIGITH
	movlw	0x0A
	movwf	DIGITL
	movlw	b'11001100'	; fast flashing
	movwf	FLASH
	goto	HandleEnd

HandleEX_2:
	xorlw	(0xE1 ^ 0xE2)
	btfss	STATUS,Z
	 goto	HandleEX_3
HandleE2:
	movf	DATA1,w		; Loco information
	andlw	0xF0
	xorlw	0x20
	btfss	STATUS,Z
	 goto	HandleEnd
	bsf	MULTIUNIT	; set Multi Unit
	movf	CURRADR,w	; no functions
	movwf	CURRMTR
	clrf	CURRFNC				
	goto	HandleE4_Data

HandleEX_3:
	xorlw	(0xE2 ^ 0xE3)	; Loco is being operated by another device
	btfss	STATUS,Z
	 goto	HandleEX_4
	movf	DATA1,w		; Loco information
	xorlw	0x40
	btfss	STATUS,Z
	 goto	HandleEnd
	movf	DATA2,w		; check with CURRADR
	andlw	0x3F
	btfss	STATUS,Z
	 goto	HandleEnd
	movf	DATA3,w
	xorwf	CURRADR,w
	btfss	STATUS,Z
	 goto	HandleEnd
	bsf	LOCO_OTHER	; operated by other
	call	SetFlash
	bsf	TEST_AD
	goto	HandleEnd
		
HandleEX_4:
	xorlw	(0xE3 ^ 0xE4)
	btfss	STATUS,Z
	 goto	HandleEX_5
HandleE4_0:
	movf	DATA1,w		; Loco information normal locomotive
	andlw	0xF0
	btfss	STATUS,Z
	 goto	HandleEnd
	bcf	MULTIUNIT
	movf	CURRADR,w	; normal locomotive
	movwf	CURRMTR
HandleE4_Loco:
	movf	DATA3,w		; function
	andlw	0x1F		; clear other bits to be sure
	movwf	CURRFNC
HandleE4_Data:
	btfsc	DATA2,7		; set dir
	 bsf	CURRFNC,LocoDir
	btfss	DATA1,0		; set 27 -> steps
	 btfsc	DATA1,1		; set 28 steps
	 bsf	CURRFNC,Loco28
	btfsc	DATA1,2		; set 128 steps
	 bsf	CURRFNC,Loco128
	movf	DATA2,w
	andlw	0x7F
	movwf	CURRSPD
	bcf	LOCO_OTHER	; loco controlled by other device?
	btfsc	DATA1,3
	 bsf	LOCO_OTHER
	call	SetFlash
	bsf	TEST_AD
	goto	HandleEnd

HandleEX_5:
	xorlw	(0xE4 ^ 0xE5)
	btfss	STATUS,Z
	 goto	HandleEnd
HandleE5_1:
	movf	DATA1,w		; Loco information in multi-unit
	andlw	0xF0
	xorlw	0x10
	btfss	STATUS,Z
	 goto	HandleEnd
	bsf	MULTIUNIT
	movf	DATA5,w		; Loco in a Multi Unit
	movwf	CURRMTR
	goto	HandleE4_Loco

HandleHomeEnd:
	movlw	MENU_RUN
	movwf	MENU
	call	SetFlash
HandleEnd:
	bcf	NEW_MSG		; message processed
	return

; --- Request messages
GetVersion:
	movlw	0x21		; get software version request
	call	SendHeader
	movlw	0x21
	call	SendData
	goto	SendMsg
		
GetStatus:
	movlw	0x21		; get status request
	call	SendHeader
	movlw	0x24
	call	SendData
	goto	SendMsg

Estop:
	movlw	0x80		; Emergency stop
	call	SendHeader
	goto	SendMsg

EOff:
	movlw	0x21		; Emergency Off
	call	SendHeader
	movlw	0x80
	call	SendData
	goto	SendMsg

Resume:
	movlw	0x21		; Resume operations request
	call	SendHeader
	movlw	0x81
	call	SendData
	goto	SendMsg
		
GetLocoInfo:
	movlw	0xE3		; Locomotive information request
	call	SendHeader
	movlw	0x00
	call	SendData
	movlw	0x00		; AH
	call	SendData
	movf	CURRADR,w	; AL
	call	SendData		
	goto	SendMsg
		
LocoOperations:
	movlw	0xE4		; Locomotive operations request
	call	SendHeader
	movlw	0x10		; 14 steps
	btfsc	CURRFNC,Loco28
	 movlw	0x12		; 28 steps
	btfsc	CURRFNC,Loco128
	 movlw	0x13		; 128 steps
	call	SendData		
	movlw	0x00		; AH
	call	SendData
	movf	CURRADR,w	; AL
	call	SendData		
	movf	CURRSPD,w
	btfsc	CURRFNC,LocoDir
	 iorlw	0x80
	call	SendData
SaveCurrentLoco:
	bcf	LOCO_OTHER
	call	SetFlash		
	movf	CURRADR,w	; save current used loco
	movwf	EEDATA0
	movlw	LOK_MEM
	call	SetParm
	goto	SendMsg

FuncOperations:
	movlw	0xE4		; Function operations request
	call	SendHeader
	movlw	0x20
	call	SendData
	movlw	0x00		; AH
	call	SendData
	movf	CURRADR,w	; AL
	call	SendData		
	movf	CURRFNC,w	; Function group 1
	andlw	0x1F
	call	SendData		
	goto	SaveCurrentLoco

; --- XpressNet messages routines

SendHeader:
	movwf	DUMMY
SendHeaderW:
	btfsc	NEW_MSG		; new message received?
	 call	HandleMsg	; yes, handle it
	btfsc	NEW_TX		; last message sent?
	 goto	SendHeaderW	; no, wait
	clrf	TXPOS		; xor byte
	clrf	TXCNT		; byte count
	movf	DUMMY,w
SendData:
	movwf	TEMP
	movlw	BUFTXINI
	addwf	TXCNT,w
	movwf	FSR
	movf	TEMP,w
	movwf	INDF
	xorwf	TXPOS,f
	incf	TXCNT,f
	return

SendMsg:
	movf	TXPOS,w		; Xor byte
	call	SendData
	bsf	NEW_TX		; transmit this
	return

SetMyAddress:
	movlw	ADR_MEM		; read from EEPROM
	call	EE_Read
	andlw	0x1F		; address beetwen 1 to 31
	iorlw	0x40		; anything to transmit default value
	movwf	MY_ADR
	movwf	TEMP		;	0000 0011
	swapf	TEMP,W		;	0011 0000
	xorwf	TEMP,F		;	0011 0011
	rrf	TEMP,W		;	X001 1001 1
	xorwf	TEMP,F		;	X010 1010
	btfsc	TEMP,2
	 incf	TEMP, F
	rrf	TEMP,w		;	XX01 0101 0    ; C flag = parity (1=odd)
	btfsc	STATUS,C
	 bsf	MY_ADR,7
	return


; --- Display / Keyboard scanning

TimerOut:
	bcf	INTCON,T0IF	; SEGMENT=0 -> ROW

	call	ReadPot		; every 1 ms

;	bsf	PORTA,DISPH		; display off
;	bsf	PORTA,DISPL
	movlw	0x18		; display off
	movwf	PORTA	
	incf	SEGMENT,f	; Segment: 0..7,  bit 3: Display selection
	movf	SEGMENT,w
	andlw	0x07
	btfsc	STATUS,Z
	 goto	ReadKeyb

	movf	DIGITL,w	; select digit to show
	btfsc	SEGMENT,3
	 movf	DIGITH,w
	call	Display		; light one segment

	btfss	FLASH,7		; flashing?
	 return
	btfss	SEGMENT,3	; display on
	 bcf	PORTA,4		; Display low enable
	btfsc	SEGMENT,3
	 bcf	PORTA,3		; Display high enable
	return

ReadKeyb:
	btfss	DbnceOn		; debounce time?
	 goto	Scan		; no, scan keyboard
	decfsz	DEBOUNCE,f	; yes, wait debouncing
	 return
	bcf	DbnceOn		; end debounce
	movlw	120		; first time auto repeat
	movwf	DEBOUNCE
	return
Scan:
	incf	ROW,w
	andlw	0x03
	movwf	ROW
	movlw	0x08		; all active rows
	call	Display
	DNOP
	DNOP
	DNOP
	DNOP
	movf	TEMP2,w		; segment bit
	andlw	b'11010001'
	movwf	TEMP2
	comf	TEMP2,w		; segment bit
	andwf	KEYST,f		; clear bit
	movf	TEMP2,w
	btfsc	PORTA,5		; Key input
	iorwf	KEYST,f		; set if pressed

	movf	KEYST,w
 	btfsc	STATUS,Z	; key pressed?
	 goto	NoKey		; no

	btfsc	KeyHit		; yes, last key released?
	 goto	KeyRepeat	; no
	bsf	KeyHit
	bcf	KeyRep

	movf	KEYST,w
	movwf	NEWKEY

	bsf	DbnceOn
	movlw	8
	movwf	DEBOUNCE
KeyReturn:
	bsf	ServKey		; key need service
	return
NoKey:
	movf	ROW,w		; all buttons readed?
	btfss	STATUS,Z
	 return			; no, wait
	bcf	KeyHit		; set no key pressed
	bcf	KeyRep
	return
KeyRepeat:
	decfsz	DEBOUNCE,f	; wait auto repeat time
	 return
	bsf	KeyRep
	movlw	16		; next time auto repeat
	movwf	DEBOUNCE
	goto	KeyReturn	; set key pressed

Display:
	movwf	TEMP		; digit to display
	movf	SEGMENT,w
	call	GetSegment
	movwf	TEMP2
	bcf	INTCON,GIE	; disable interrupts
	movlw	b'00111110'	; display off	fgXXXXXa
	andwf	PORTA,f	
	movlw	b'00001111'	;		edcbXXXX
	andwf	PORTB,f
	movf	TEMP,w
	btfss	TEMP2,1		; select port
	 goto	DisplayRA
DisplayRB:
	call	Digit_RB
	andwf	TEMP2,w		; segment
	iorwf	PORTB,f
	bsf	INTCON,GIE
	return
DisplayRA:
	call	Digit_RA
	andwf	TEMP2,w		; segment
	iorwf	PORTA,f
	bsf	INTCON,GIE
	return

; ---- Display

DispBin:
	movwf	LSB		; Show bin: 0..99 
	call	BIN2BCD
	movf	R0,w
DispBCD:
	movwf	TEMP		; out 2 BCD digits
	swapf	TEMP,w
	andlw	0x0F		; out BCD tens
	movwf	DIGITH
	movf	TEMP,w
DispBCDL:
	andlw	0x0F		; out BCD units
	movwf	DIGITL
	return

SetFlash:
	movlw	b'11111111'	; always on
	movf	MENU,f
	btfss	STATUS,Z
	 movlw	b'11011111'	; minimum flashing
	btfsc	LOCO_OTHER
	 movlw	b'11001100'	; fast flashing
	btfsc	EmergOff
	 movlw	b'11000011'	; slow flashing
	btfsc	EmergStop
	 movlw	b'11000011'	; slow flashing
	btfsc	ServiceMode
	 movlw	b'11000011'	; slow flashing

	movwf	FLASH
	return

BIN2BCD:                       
	bcf	STATUS,C	; 8 bit bin to 2(3) digit BCD
	movlw	0x08
	movwf	COUNT
	clrf	R0                          
	clrf	R1                          
LOOP8:                       
	rlf	LSB,f                          
	rlf	R0,f                          
;	rlf	R1,f                          
	decfsz	COUNT,f                          
	 goto	ADJDEC
	return
ADJDEC:                         
	movlw	R0                          
	call	ADJBCD
;	movlw	R1                          
;	call	ADJBCD
	goto	LOOP8 
ADJBCD:                        
	movwf 	FSR                           
	movlw 	0x3                           
	addwf 	INDF,W                         
	movwf	TEMP
	btfsc	TEMP,3                      
	 movwf	INDF                           
	movlw	0x30                          
	addwf	INDF,W                         
	movwf	TEMP
	btfsc	TEMP,7                      
	 movwf	INDF                           
	return

; ----- Menu Keys
K_EnterLok:
	movlw	CHR_L		; Menu Loco selection. Diplay 'L '
	movwf	DIGITH
	movlw	CHR_SPC
	movwf	DIGITL
	movlw	MENU_LOK
	movwf	MENU
	call	SetFlash
	return
K_LokUp:
	incf	CURRADR,f	; Increment Loco number
	movlw	100
	xorwf	CURRADR,w
	movlw	1
	btfsc	STATUS,Z
	 movwf	CURRADR
K_LokEnd:
	call	GetLocoInfo
	movf	CURRADR,w
	goto	DispBin
K_LokDwn:
	decf	CURRADR,f	; Decrement Loco number
	movlw	99
	btfsc	STATUS,Z
	 movwf	CURRADR
	goto	K_LokEnd
K_Light:
	movlw	0x10		; Change FL ***
	xorwf	CURRFNC,f	; Change Fx
	goto	FuncOperations	
K_F2:
	movlw	0x02		; Change F2 ***
	goto	K_Func
K_F1:
	movlw	0x01		; Change F1
	goto	K_Func
K_Func:
	xorwf	CURRFNC,f	; Change Fx
	call	FuncOperations

K_EnterFunc:
	movlw	0x0B		; '_' F2 status ***
	btfsc	CURRFNC,1
	 movlw	0x0C		; '~'
	movwf	DIGITL
	movlw	0x0B		; '_' F1 status
	btfsc	CURRFNC,0
	 movlw	0x0C		; '~'
	movwf	DIGITH
	movlw	MENU_FNC
	movwf	MENU
	call	SetFlash
	return

K_ChangeDir:
;	movf	SPEED,w		; Change Direction only in speed 0 ***
;	btfss	STATUS,Z
;	 return
	movlw	0x20		; Change current loco direction
	xorwf	CURRFNC,f
	call	LocoOperations
K_EnterDir:
	movf	SPEED,w		; Change Dir / steps only in speed 0
	btfss	STATUS,Z
	 goto	K_EnterRun
	btfss	CURRFNC,LocoDir	; Menu Direction/Steps.
	 goto	K_EnterDirBack
 					; Forward	'd-'
	movlw	CHR_D	 	; 'd'
	movwf	DIGITH
	movlw	0x0B		; '_'  14 steps
	btfsc	CURRFNC,Loco28
	 movlw	0x0A		; '-'  28 steps
	btfsc	CURRFNC,Loco128
	 movlw	0x0C		; '~' 128 steps
	movwf	DIGITL
	goto	K_EnterDirEnd
K_EnterDirBack:			; Backward	'-d'
	movlw	0x0B		; '_'  14 steps
	btfsc	CURRFNC,Loco28
	 movlw	0x0A		; '-'  28 steps
	btfsc	CURRFNC,Loco128
	 movlw	0x0C		; '~' 128 steps
	movwf	DIGITH
	movlw	CHR_D		; 'd'
	movwf	DIGITL
K_EnterDirEnd:
	movlw	MENU_DIR
	movwf	MENU
	call	SetFlash
	return

K_ChangeDirRun:
	movlw	0x20		; Change current loco direction ***
	xorwf	CURRFNC,f
	call	LocoOperations	
K_EnterRun:
	movlw	MENU_RUN	; Main menu, show loco number
	movwf	MENU
	call	SetFlash
	movf	CURRADR,w
	goto	DispBin

K_ChangeStep:
	movf	SPEED,w		; only if speed 0
	btfss	STATUS,Z
	 return
	movlw	b'10000000'	; change step 14,28,128
	btfss	CURRFNC,Loco128
	 movlw	b'01000000'
	btfsc	CURRFNC,Loco28
	 movlw	b'11000000'
	xorwf	CURRFNC,f
	call	LocoOperations	; update new steps
	goto	K_EnterDir

K_Stop:
	btfsc	EmergStop	; in E_stop or E_Off?
K_StopOn:
	 goto	Resume		; yes, Resume
K_StopOff:
	btfsc	EmergOff
	 goto	K_StopOn
	goto	EOff		; no, do Emergency Off

K_XbusUp:
	movlw	ADR_MEM		; Increment Xbus address
	call	EE_Read
	movwf	EEDATA0
	incf	EEDATA0,f
	movlw	32
	xorwf	EEDATA0,w
	movlw	1
	btfsc	STATUS,Z
	 movwf	EEDATA0
K_XbusUpdate:
	movlw	ADR_MEM
	call	SetParm
	movf	EEDATA0,w
	goto	DispBin


K_XbusDwn:
	movlw	ADR_MEM		; Decrement Xbus address
	call	EE_Read
	movwf	EEDATA0
	decf	EEDATA0,f
	movlw	31
	btfsc	STATUS,Z
	 movwf	EEDATA0
	goto	K_XbusUpdate


K_SelSetup:
	btfss	SEL_SETUP	; Change setup menu selection
	 goto	K_EnterSetupPot
K_EnterSetup:
	bcf	SEL_SETUP
	movlw	CHR_A		; show 'A '
	goto	K_EnterSetupEnd
K_EnterSetupPot:
	bsf	SEL_SETUP
	movlw	CHR_P		; show 'P '
K_EnterSetupEnd:
	movwf	DIGITH
	movlw	CHR_SPC
	movwf	DIGITL
	movlw	MENU_SETUP
	movwf	MENU
	return

K_EnterPar:
	movlw	MENU_POT	; Set selected setup menu
	btfss	SEL_SETUP
	 movlw	MENU_XBUS
	movwf	MENU
	btfsc	SEL_SETUP
	 return
	movlw	ADR_MEM		; Show current Xbus address
	call	EE_Read
	goto	DispBin

K_OffsetUp:
	movlw	POT_MEM		; Increment Pot offset
	call	EE_Read
	movwf	EEDATA0
	incf	EEDATA0,f	; 0..15
	btfsc	EEDATA0,4
	 decf	EEDATA0,f
K_OffsetUpdate:
	movf	EEDATA0,w	; set new offset
	movwf	OFFSET
	movlw	POT_MEM
	goto	SetParm

K_OffsetDwn:
	movlw	POT_MEM		; Decrement Pot offset
	call	EE_Read
	movwf	EEDATA0
	decf	EEDATA0,f	; 0..15
	btfsc	EEDATA0,7
	 clrf	EEDATA0
	goto	K_OffsetUpdate

; ----- Analog 

IniPWM:
	bsf	STATUS,RP0
	movlw	51		; Set PWM freq = 19200 Hz (R:2K7, C:100nF) ??
	movwf	PR2
	bcf	STATUS,RP0
	movlw	0x04		; enable TMR2 1:1 prescaler
	movwf	T2CON

	movlw	POT_MEM		; read pot. offset
	call	EE_Read
	andlw	0x0F
	movwf	OFFSET
	movlw	0x1F		; init pot counter
	movwf	POT_CNT
	addwf	OFFSET,w
	movwf	CCPR1L		; analog output max. voltage (5bits + 2bits)

	movlw	0x0C		; enable PWM mode
	movwf	CCP1CON
	return

; copy POT_CNT to next POT_SAVED array
ReadPot:
	movf	POT_INDEX,w
	andlw	0x07
	addlw	POT_SAVED
	movwf	FSR
	btfss	CMCON,C2OUT	; check if decreased to pot position
	 goto	ReadPotNxt
	movf	POT_CNT,w	; yes, get position
	movwf	INDF		; Speed = PWM - Offset (0..31)
	incf	POT_INDEX,f
	goto	ReadPotEnd
ReadPotNxt:
	decf	CCPR1L,f
	decfsz	POT_CNT,f	; next step voltage
	 return
	clrf	INDF		; pot in stop
	incf	POT_INDEX,f
ReadPotEnd:
	movlw	0x1F		; reload max. voltage
	movwf	POT_CNT
	addwf	OFFSET,w	; pot. offset
	movwf	CCPR1L
	return

;Read potentiometer value from RAM and — if changed — send it to loco
FlashPotSpeed:
	bcf	PIR1,TMR1IF	; calc flashing sequence
	bcf	STATUS,C
	btfsc	FLASH,7
	 bsf	STATUS,C
	rlf	FLASH,f
;PotSpeed:
	btfsc	NEW_TX		; don't read if waiting to send
	 return
	movf	POT_SAVED,w	; calc medium value
	addwf	POT_SAVED+1,w
	addwf	POT_SAVED+2,w
	addwf	POT_SAVED+3,w
	addwf	POT_SAVED+4,w
	addwf	POT_SAVED+5,w
	addwf	POT_SAVED+6,w
	addwf	POT_SAVED+7,w
	movwf	TEMP
	rrf	TEMP,f
	rrf	TEMP,f
	rrf	TEMP,w
	andlw	0x1F
	movwf	TEMP
	xorwf	SPEED,w		; pot equal to last position?
	btfsc	STATUS,Z
	 return			; yes, nothing to do
	movf	TEMP,w		; save new position
	movwf	SPEED
	btfsc	TEST_AD
	 goto	PotDiscard

	btfsc	CURRFNC,Loco28	; convert to current speed step
	 goto	PotSpd28
	btfsc	CURRFNC,Loco128	
	 goto	PotSpd128
;PotSpd14:
	rrf	TEMP,w		; 14 steps
	andlw	0x0F
	xorlw	0x01		; skip E.stop
	btfss	STATUS,Z
	 xorlw	0x01
	movwf	CURRSPD		; update speed
	goto	LocoOperations
PotSpd28:
	movlw	0x04		; skip emergency & stop
	subwf	TEMP,w
	btfss	STATUS,C
	 clrf	TEMP
	rrf	TEMP,w		; set bit 4 as LSB
	btfsc	STATUS,C
	 iorlw	0x10
	andlw	0x1F
	movwf	CURRSPD		; update speed
	goto	LocoOperations
PotSpd128:
	rlf	TEMP,f		; SPEED * 4 (0..127)
	rlf	TEMP,w
	andlw	0x7C
	movwf	CURRSPD		; update speed
	goto	LocoOperations
PotDiscard:
	bcf	TEST_AD
	return

ShowPot:
	bcf	PIR1,TMR1IF
	movf	MENU,w		; show only in Setup Pot. Menu
	xorlw	MENU_POT
	btfss	STATUS,Z
	 return

	movf	POT_SAVED,w	; calc medium value
	addwf	POT_SAVED+1,w
	addwf	POT_SAVED+2,w
	addwf	POT_SAVED+3,w
	addwf	POT_SAVED+4,w
	addwf	POT_SAVED+5,w
	addwf	POT_SAVED+6,w
	addwf	POT_SAVED+7,w
	movwf	TEMP
	rrf	TEMP,f
	rrf	TEMP,f
	rrf	TEMP,w
	andlw	0x1F
	goto	DispBin
	

; ----- Serial port routines (XBus)

UART_INI:
	bcf	PORTB,0		; Disable TX
	clrf	XFLAGS		; clear XpressNet flags
	clrf	RX_LEN		; clear input buffer
	banksel SPBRG	;Bank 1
	movlw	((10*FXTAL/(16*BaudRate))+5)/10-1		; BRGH = 1
	movwf	SPBRG
	movlw	0x64		; 9 bit, Enable TX, BRGH=1, TXD9=0
	movwf	TXSTA
	banksel RCSTA	;Bank 0
	movlw	0xD0		; Enable RX, 9 bit
	movwf	RCSTA
	clrw			; Settling time
SETTLE:
	addlw	0xFF
	btfss	STATUS,Z
    	 goto 	SETTLE
	movf 	RCREG,w         ; flush receive buffer
	movf 	RCREG,w
	movf 	RCREG,w
	return

;----- Internal EEPROM routines ------------------------------------------------

EE_Read:
	bsf	STATUS,RP0	; w=ADR
	movwf	EEADR
	bsf	EECON1,RD
	movf	EEDATA,w
	bcf	STATUS,RP0
	return

SetParm:
	call	EE_Read		; w=ADR, EEDATA0=data. Write only changes
	xorwf	EEDATA0,w
	btfsc	STATUS,Z
	 return
EE_Write:		
	movf	EEDATA0,w
	bsf	STATUS,RP0
	movwf	EEDATA
	bsf	EECON1,WREN
	bcf	INTCON,GIE
	movlw	0x55
	movwf	EECON2
	movlw	0xAA
	movwf	EECON2
	bsf	EECON1,WR
	bsf	INTCON,GIE
	bcf	EECON1,WREN
EEWrite0:
	btfsc	EECON1,WR
	 goto	EEWrite0
	bcf	STATUS,RP0
	return

; ----- EEPROM default values
	org	0x2100

	dw	0x01		; XpressNet device address
	dw	0x03		; Last Locomotive used
	dw	0x00		; Pot. offset

	org	0x2110

	dt	" Simple "
	dt	"Maus v."
	dt	(__VERNUM   & 0x0F)+0x30
	dt	"F.Cañada"
	dt	(__VERDAY   >> 4)  +0x30
	dt	(__VERDAY   & 0x0F)+0x30,"/"
	dt	(__VERMONTH >> 4)  +0x30
	dt	(__VERMONTH & 0x0F)+0x30,"/"
	dt	(__VERYEAR  >> 4)  +0x30
	dt	(__VERYEAR  & 0x0F)+0x30

	end
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded