;;======================================================================;;
;;				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.02.2006					;;
;;									;;
;;======================================================================;;

; 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.


; ----- Definitions

#define		__VERNUM	0x02
#define		__VERREV	" "
#define		__VERDAY	0x30
#define		__VERMONTH	0x10
#define		__VERYEAR	0x06


                list    p=16F628,r=hex

		errorlevel -302
		errorlevel -306

	        INCLUDE "P16F628.INC"


                __FUSES _BODEN_ON & _CP_OFF & _PWRTE_ON & _WDT_OFF & _LVP_OFF & _MCLRE_OFF  & _INTRC_OSC_NOCLKOUT


#define		RAMINI0		0x020		; 80 bytes
#define		RAMINI1		0x0A0		; 80 bytes
#define		RAMINI2		0x120		; 48 bytes
#define		RAMINT		0x070		; 16 bytes


; ----- Macros

SEL_BANK_0:	macro	
		bcf	STATUS,RP0		; macros for data access
		bcf	STATUS,RP1
		endm

SEL_BANK_1:	macro	
		bsf	STATUS,RP0
		bcf	STATUS,RP1
		endm

SEL_BANK_2:	macro	
		bcf	STATUS,RP0
		bsf	STATUS,RP1
		endm

SEL_BANK_3:	macro	
		bsf	STATUS,RP0
		bsf	STATUS,RP1
		endm

#define		SEL_IBANK_0	bcf	STATUS,IRP

#define		SEL_IBANK_1	bsf	STATUS,IRP

#define		DNOP		goto	$+1

; ----- Constant values

FXTAL		equ	D'4000000'		; Internal oscillator frequency
BaudRate	equ	D'62500'		; XBus serial speed

HIGH_BAUD	equ	(((D'10'*FXTAL/(D'16'*BaudRate))+5)/D'10')-1		; BRGH = 1
LOW_BAUD	equ	(((D'10'*FXTAL/(D'64'*BaudRate))+5)/D'10')-1		; BRGH = 0


RA_TRIS         equ     0x26			; RA1,RA2: comparator input,RA5: key input
RB_TRIS         equ     0x06			; all outputs and serial port: RB0=TXRX
RA_INI          equ     0x18			; display off, TXRX=0 receive
RB_INI          equ     0x00			; all zero
INTC_INI	equ	0xC0			; GIE enable, PEIE enable
PIE1_INI	equ	0x20			; RX interrupt
OPTION_INI	equ	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


; --- Pin assignement

; --- Port A

; RA0	a / SEL
; RA1	PWM_IN
; RA2	POT
; RA3	DISPH
; RA4	DISPL
; RA5	KEY_IN
; RA6	g / F1 - UP	
; RA7	f / F0 - DWN

						; PORTA
SEL_KEY		equ	0			; SEL key output
DISPH		equ	3			; Display high enable
DISPL		equ	4			; Display low enable
KEYIN		equ	5			; Key input
F1_KEY		equ	6			; F1 key output
F0_KEY		equ	7			; F0 key output

; --- Port B

; RB0	TXRX
; RB1	RXD
; RB2	TXD
; RB3	PWM_OUT
; RB4	b / STOP
; RB5	c
; RB6	d
; RB7	e


COMPORT		equ	PORTB			; PORTB
TXRX		equ	0			; 1: enable, 0: disable RS485 transmision
RXD		equ	1			; serial port
TXD		equ	2			;
STOP_KEY	equ	4			; STOP key output


; --- 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

#define		EE_INI		0x00

ADR_MEM		equ	EE_INI+0x00		; Xbus address EEPROM location
LOK_MEM		equ	EE_INI+0x01		; Last loco used
POT_MEM		equ	EE_INI+0x02		; Potentiometer offset


; ----- Variables

; --- Internal RAM Section

; --- Top on all banks

INT_W		equ	RAMINT+0x00		; Interrupt variables.
INT_STAT	equ	RAMINT+0x01
INT_PCLATH	equ	RAMINT+0x02
INT_FSR		equ	RAMINT+0x03

EEDATA0		equ	RAMINT+0x0B		; EEPROM shadow variables
EEADR0		equ	RAMINT+0x0C


; --- Bank 0

BUFRXINI	equ	RAMINI0+0x00		; first input buffer location
HEADER		equ	RAMINI0+0x00		; Xbus packet
DATA1		equ	RAMINI0+0x01
DATA2		equ	RAMINI0+0x02
DATA3		equ	RAMINI0+0x03
DATA4		equ	RAMINI0+0x04
DATA5		equ	RAMINI0+0x05
;
BUFRXEND	equ	RAMINI0+0x11		; last reception buffer location
KEYFLAG		equ	RAMINI0+0x15		; Keyboard flags

R0		equ	RAMINI0+0x18		; General & Bin to BCD registers
R1		equ	RAMINI0+0x19
LSB		equ	RAMINI0+0x1A
MSB		equ	RAMINI0+0x1B

DUMMY		equ	RAMINI0+0x1C		; Temporary values
TEMP		equ	RAMINI0+0x1D
TEMP2		equ	RAMINI0+0x1E
COUNT		equ	RAMINI0+0x1F

CALLBYTE	equ	RAMINI0+0x20		; call byte byte from command station
MY_ADR		equ	RAMINI0+0x21		; XpressNet Address for normal inquiry messages
TXPOS		equ	RAMINI0+0x22		; Serial Buffer output pointers
TXCNT		equ	RAMINI0+0x23
RX_XOR		equ	RAMINI0+0x24		; Serial incoming checksum
RX_LEN		equ	RAMINI0+0x25		; Incomming message length
XFLAGS		equ	RAMINI0+0x26		; XpressNet flags
XBUS_VER	equ	RAMINI0+0x27		; XpressNet version
XBUS_STA	equ	RAMINI0+0x28		; Command Station type
FLAGS		equ	RAMINI0+0x29		; Flags

DCC_STATUS	equ	RAMINI0+0x2F		; Command Station Status

CURRMTR		equ	RAMINI0+0x32		; Current Loco Multi-Unit
CURRADR		equ	RAMINI0+0x33		; Current Loco address
CURRSPD		equ	RAMINI0+0x34		; Current Loco speed
CURRFNC		equ	RAMINI0+0x35		; Current Loco functions

POT_SAVED	equ	RAMINI0+0x38		; pot saved values for calc mid value (0x38..0x3F)
;
POT_INDEX	equ	RAMINI0+0x40		; Index to POT_SAVE
POT_CNT		equ	RAMINI0+0x41		; current pot value
OFFSET		equ	RAMINI0+0x42		; pot. offset
SPEED		equ	RAMINI0+0x43		; current speed
DIGITH		equ	RAMINI0+0x44		; Display. Dizaines
DIGITL		equ	RAMINI0+0x45		; Display. Units
SEGMENT		equ	RAMINI0+0x46		; segment displayed
ROW		equ	RAMINI0+0x47		; Key row scanned
KEYST		equ	RAMINI0+0x48		; Keys status
NEWKEY		equ	RAMINI0+0x49		; Keys pressed
DEBOUNCE	equ	RAMINI0+0x4A		; debounce time
MENU		equ	RAMINI0+0x4B		; current menu
FLASH		equ	RAMINI0+0x4C		; flashing sequence


; --- Bank 1

; --- Buffers

BUFTXINI	equ	RAMINI1+0x00		; XpressNet Serial output buffer
;BUFTXEND	equ	RAMINI1+0x1F


;----- 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 --------------------------------------


		org	0x000

PowerUp:
		clrf	INTCON			; Disable all interrupts
		clrf	PCLATH			; Tables on page 0
		clrf	STATUS			; reset flags
		goto	INIT


; ----- ISR (Interrupt Service Routines)

		org	0x004

Interrupt:
		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	COMPORT,TXRX		; MAX485 TX enable
		movlw	0x20
		movwf	TXREG
		SEL_BANK_1
IntTxAck:
		btfss	TXSTA,TRMT		; wait until end of byte transmited
		goto	IntTxAck
		SEL_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	COMPORT,TXRX		; MAX485 TX enable
		SEL_BANK_1
		bsf	PIE1,TXIE		; Enable TX interrupts
		SEL_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:
		SEL_BANK_1
IntTxDone:
		btfss	TXSTA,TRMT		; wait until end of last byte transmited
		goto	IntTxDone
		bcf	PIE1,TXIE		; Disable TX interrupts
		DNOP
		DNOP
		DNOP
		SEL_BANK_0		
		bcf	COMPORT,TXRX		; 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,F0_KEY
		movlw	0x01
		btfsc	NEWKEY,F1_KEY
		movlw	0x02
		btfsc	NEWKEY,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 ($ > d'255') 
		ERROR "  Tables exceded page 0.   If it works, why do you change it?   "
	endif


; ----- Initialization

INIT:
		clrf	RCSTA			; disable UART

		movlw   RA_INI			; Set ports
		movwf   PORTA                         
		movlw   RB_INI
		movwf   PORTB
		SEL_BANK_1
		movlw	RB_TRIS			; Set port B I/O configuration
		movwf   TRISB
		movlw   RA_TRIS         	; Set port A I/O configuration
		movwf   TRISA
		movlw	PIE1_INI
		movwf	PIE1			; peripheral interrupts
		movlw   OPTION_INI      	; PORTB pull-ups enabled, Timer configuration
		movwf   OPTION_REG
		movlw	0x0B			; internal oscillator to 4MHz default
		movwf	PCON
		movlw	0x00			; VRR off
		movwf	VRCON
		SEL_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	RAMINI0			; 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	COMPORT,TXRX		; MAX485 TX disable just to be sure
		call	IniPWM			; 
		movlw	INTC_INI		; Set interrupts
		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,KEYIN
		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
		

; --- Main Loop


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 sended?
		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,DISPL
		btfsc	SEGMENT,3
		bcf	PORTA,DISPH
		return

ReadKeyb:
		btfss	DbnceOn			; debounce time?
		goto	Scan			; no, scan keyboard
		decfsz	DEBOUNCE,f		; yes, wait debouncing
		return
		bcf	DbnceOn			; end debounce
		movlw	d'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,KEYIN
		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	d'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	d'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	d'100'
		xorwf	CURRADR,w
		movlw	d'1'
		btfsc	STATUS,Z
		movwf	CURRADR
K_LokEnd:
		call	GetLocoInfo
		movf	CURRADR,w
		goto	DispBin


K_LokDwn:
		decf	CURRADR,f		; Decrement Loco number
		movlw	d'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	d'32'
		xorwf	EEDATA0,w
		movlw	d'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	d'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		; Set PWM freq = 19200 Hz (R:2K7, C:100nF)
		movlw	d'51'
		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


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
	

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	COMPORT,TXRX		; Disable TX
		clrf	XFLAGS			; clear XpressNet flags
		clrf	RX_LEN			; clear input buffer
		SEL_BANK_1
		movlw	HIGH_BAUD
		movwf	SPBRG
		movlw	0x64			; 9 bit, Enable TX, BRGH=1, TXD9=0
		movwf	TXSTA
		SEL_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 + EE_INI

		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


