please dont rip this site

Scenix Lib IO OSI2 IR DA Irda.src

MainInfoSeg	MACRO
;********************************************************************************
;  Main Code
;********************************************************************************
		ENDM

MainCodeSeg	MACRO
;********************************************************************************
;  Main Code
;********************************************************************************

ledRX		=	ra.0
ledTX		=	ra.1
ledCON		=	ra.2
ledERR		=	ra.3

Startup
	mov	m, #TRIS
	mov	 ra, #%0000		;init Port A
	mov	!ra, #%0000		;Port A (LEDs) - Outputs

	mov	 rb, #%00001100		;init rb - UartTx (bit 2) and UartCTS (bit 3) = idle high
	mov	!rb, #%01110011		;Direction
	mov	m, #PLP
	mov	!rb, #%11001111		;Enable pullup on unused pins (bits 4 and 5)
	mov	m, #WKED
	mov	!rb, #%11111110		;IrRx (bit 6) = falling edge, UartRx (bit0) = rising edge

	clr	rc			;Init output to 0
	mov	m, #TRIS
	mov	!rc, #%10101011		;Port C (IO Port) direction - set for jumper use
	mov	m, #PLP
	mov	!rc, #%01010100		;Port C (IO Port) pullup - enabled on input pins

	clr	fsr			;reset all ram banks
:loop	setb	fsr.4
	clr	ind
	ijnz	fsr,:loop

	call	@IsrInit

	call	@a2flReset
	call	@a2plReset
	call	@a2lapReset
	call	@a2lmpReset
	call	@a2appReset

Asynchronous				;Note: flags are global
	snb	IrdaRxAvail		;Irda byte received ?
	call	@a2flRxAvail
	snb	IrdaTxEmpty		;Irda TxEmpty flag set ?
	call	@a2flTxEmpty
	snb	UartRxAvail		;Uart byte received ?
	call	@a2appRxAvail
	snb	TimerOverflow		;Timer Overflow flag set ?
	call	@a2lapTimer
	jmp	Asynchronous

;********************************************************************************

		ENDM
IsrInfoSeg	MACRO
;********************************************************************************
;  Interrupt Service Routine
;********************************************************************************
;  Updated 19 November 1999 - Nick Kelsey
;  * Fixed fault in IrdaTxData and UartTxData where the stop bit was one
;    interrupt cycle too long.
;  Updated 6 December 1999 - Nick Kelsey
;  * Added RTS/CTS defines for debug UART.
;********************************************************************************
		ENDM


IsrDataSeg	MACRO
;********************************************************************************
;  Interrupt Service Routine
;********************************************************************************

		org	$10	

IsrBank		= 	$10

IsrTime50MHz	=	-108			;50Mhz * 2.17us = 108.5
IsrTime		=	IsrTime50MHz		;Constant = MHz * 2.17us

;**** Isr ****

IsrMReg		ds	1
IsrIntFlags	ds	1

;**** IsrStatus **** (Global varible providing an interface to the Isr)

TimerOverflow	=	IsrStatus.0
IrdaTxStart	=	IsrStatus.1
IrdaTxEmpty	=	IsrStatus.2		;1 = finished sending byte
IrdaRxAvail	=	IsrStatus.3		;1 = received byte available to be read
UartTxStart	=	IsrStatus.4
UartTxEmpty	=	IsrStatus.5
UartRxAvail	=	IsrStatus.6		;1 = received byte available to be read
DebugSend	=	UartTxStart

;**** Irda & Uart Status ****

IrdaUartStatus	ds	1
IrdaRxPulse	=	IrdaUartStatus.0
IrdaRxMode	=	IrdaUartStatus.1	;1 = currently receiving a byte, 0 = idle
IrdaTxMode	=	IrdaUartStatus.2	;1 = currently transmitting a byte, 0 = idle
UartRxMode	=	IrdaUartStatus.3	;1 = currently receiving a byte, 0 = idle
UartTxMode	=	IrdaUartStatus.4	;1 = currently transmitting a byte, 0 = idle

;**** Irda ****

IrdaTxPin	=	rb.7			;Output - Idle Low
IrdaRxPin	=	rb.6			;Input  - Idle High
IrdaRxInt	=	6			;Interrupt = bit 6

Irda9600	=	48			;+0.47%
Irda19200	=	24			;+0.47%
Irda38400	=	12			;+0.47%
Irda57600	=	8			;+0.47%
Irda115200	=	4			;+0.47%

IrdaSpeed	ds	1
IrdaData	ds	1
IrdaRxBits	ds	1
IrdaBitCount	ds	1
IrdaDivide	ds	1

;**** Uart ****

UartTxPin	=	rb.2			;Output - Idle High
UartRxPin	=	rb.0			;Input  - Idle High
UartRtsPin	=	rb.1			;Output
UartCtsPin	=	rb.3			;Input

Uart9600	=	48			;+0.47%
Uart19200	=	24			;+0.47%
Uart38400	=	12			;+0.47%
Uart57600	=	8			;+0.47%
Uart115200	=	4			;+0.47%

UartSpeed	=	Uart115200

UartTxData	=	DebugData		;Global Variable
UartTxBits	ds	1
UartTxBitCount	ds	1
UartTxDivide	ds	1

UartRxData	ds	1
UartRxBits	ds	1
UartRxBitCount	ds	1
UartRxDivide	ds	1

		org	$30

TimerBank	= 	$30			;Shared with Framing layer

Random		ds	1			;Increments every timer interrupt (108 cycles @ 50MHz)
Timer1		ds	1			;Resetable, Increments every timer interrupt (108 cycles @ 50MHz)
Timer2		ds	1			;Resetable, Increments every Timer1 overflow (27648 cycles @ 50MHz)
Timer3		ds	1			;Resetable, Increments every Timer2 overflow (7077888 cycles @ 50MHz)

;********************************************************************************
		ENDM


IsrCodeSeg	MACRO
;********************************************************************************
;  Interrupt Service Routine
;********************************************************************************

GlobalIsr					;Interrupt = Timer
	bank	TimerBank
	inc	Random				;1	Random increment (Note: The main code is synchronous with RTCC and so RTCC is not a random number)
	inc	Timer1				;1	Timer: increment
	snz					;1/2	Timer: overflow ?
	inc	Timer2				;1	Timer: Yes => increment
	snz					;1/2	Timer: overflow ?
	inc	Timer3				;1	Timer: Yes => increment
	snz					;1/2	Timer: overflow ?
	setb	TimerOverflow			;1	Timer: Yes => set flag (Timer = 7 cycles)

	bank	IsrBank				;1
	mov	IsrMReg, m			;2	Backup M register
	mov	m, #WKPND			;1	Set mode to examine port b interrupt flags
	mov	w, #0				;1	Clear W
	mov	!rb, w				;1	Swap contents of W and WKPEN_B (interrupt flags are cleared)
	mov	IsrIntFlags, w			;1	Store cause of interrupt

IrdaIsr						;	Irda -> IrdaRet: Idle = 6 cycles, Tx = 9/19/23 cycles, Rx = 12/21/27 cycles, RxStart = 18 cycles
	snb	IrdaTxMode			;1/2	Irda Tx ?
	jmp	IrdaTxDataIsr			;3	Yes => IrdaTxDataIsr
	snb	IrdaTxStart			;1/2	Irda Tx ?
	jmp	IrdaTxStartIsr			;3	Yes => IrdaTxStartIsr
	snb	IrdaRxMode			;1/2	Irda Rx ?
	jmp	IrdaRxDataIsr			;3	Yes => IrdaRxDataIsr
	snb	IsrIntFlags.IrdaRxInt		;1/2	Falling edge of Rx pin indicating start bit ?
	jmp	IrdaRxStartIsr			;3	Yes => IrdaRxStartIsr
IrdaRet						;	Irda -> IrdaRet: Idle = 6 cycles, Tx = 9/19/23 cycles, Rx = 12/21/27 cycles, RxStart = 18 cycles

UartTxIsr
	snb	UartTxMode			;1/2	Transmitting ?
	jmp	UartTxDataIsr			;3	Yes => UartTxDataIsr
	snb	UartTxStart			;1/2	Start transmit ?
	jmp	UartTxStartIsr			;3	Yes => UartTxStartIsr
UartTxRet

UartRxIsr
	snb	UartRxMode			;1/2	Receiving ?
	jmp	UartRxDataIsr			;3	Yes => UartRxDataIsr
	sb	UartRxPin			;1/2	Start bit ? (start bit = 0)
	jmp	UartRxStartIsr			;3	Yes => UartRxStartIsr
UartRxRet

	mov	m, IsrMReg			;2	Restore M register
	mov	w, #IsrTime			;1	Interrupt in 108 @ 50Mhz cycles
	retiw					;3	Total Isr Time = x cycles


IrdaTxDataIsr					;	Time = 5/13/16/20 cycles
	clrb	IrdaTxPin			;1	return to idle
	decsz	IrdaDivide			;1/2
	jmp	IrdaRet				;3	Isr Time = +5 cycles from IrdaTxIsr
	decsz	IrdaBitCount			;1/2	Sent all bits?
	jmp	:Bit				;3	No => output next bit
:End	snb	IrdaTxStart			;1/2	Yes => complete, Another byte to transmit?
	jmp	IrdaTxStartIsr			;3	Yes => IrdaTxStartIsr
	clrb	IrdaTxMode			;1	Finished
	setb	IrdaTxEmpty			;1	Flag to indicate that the transmission is complete
	clrb	ledTX				;1	Turn off TX LED (indication LED not actual IR emitter)
	jmp	IrdaRet				;3	Isr Time = +19 cycles from IrdaTxIsr
:Bit	sb	IrdaData.0			;1/2	Output next bit
	setb	IrdaTxPin			;1	Output next bit
	stc					;1	Stop bit (idle = 1)
	rr	IrdaData			;1
	mov	IrdaDivide, IrdaSpeed		;2	Apply baud rate
	jmp	IrdaRet				;3	Isr Time = +16 cycles from IrdaTxIsr

IrdaTxStartIsr
	clrb	IrdaTxStart			;1	Clear start mode
	setb	ledTX				;1	Turn on TX LED (indication LED not actual IR emitter)
	setb	IrdaTxPin			;1	Output start pulse (note position of this instruction is such that it matches the setb of the TxDataIsr)
	mov	IrdaDivide, IrdaSpeed		;2	Apply baud rate
	mov	IrdaBitCount, #10		;2	Bit count = 8 data + 1 stop + 1 for stop bit to complete
	setb	IrdaTxMode			;1	Enter Tx mode
	jmp	IrdaRet				;3	Isr Time = +n cycles

IrdaRxDataIsr					;	Time = 4/13/19 cycles
	snb	IsrIntFlags.IrdaRxInt		;1/2	Was a pulse received ?
	setb	IrdaRxPulse			;1	Yes => Flag pulse
	decsz	IrdaDivide			;1/2
	jmp	IrdaRet				;3	Isr Time = +4 cycles from IrdaRxIsr
	clc					;1	Determine bit
	sb	IrdaRxPulse			;1/2	Determine bit
	stc					;1	Determine bit
	rr	IrdaRxBits			;1	Record bit
	clrb	IrdaRxPulse			;1	Reset pulse flag
	mov	IrdaDivide, IrdaSpeed		;2	Apply baud rate
	decsz	IrdaBitCount			;1/2
	jmp	IrdaRet				;3	Isr Time = +13 cycles from IrdaRxIsr
	mov	IrdaData, IrdaRxBits		;2	Copy bits into IrdaData
	clrb	IrdaRxMode			;1	Finished
	setb	IrdaRxAvail			;1
	clrb	ledRX				;1	Turn off RX LED (indication LED not actual IR emitter)
	jmp	IrdaRet				;3	Isr Time = +19 cycles from IrdaRxIsr

IrdaRxStartIsr					;	Time = 10 cycles
	setb	ledRX				;1	Turn on RX LED (indication LED not actual IR emitter)
	clc					;1
	mov	w, >>IrdaSpeed			;1	W = IrdaSpeed / 2
	mov	IrdaDivide, w			;1	IrdaDivide = IrdaSpeed * 0.5
	mov	IrdaBitCount, #9		;2	Bit count = 9 (1/2 start, 8 data, ignore stop)
	setb	IrdaRxMode			;1	Enter rx mode
	jmp	IrdaRet				;3	Isr Time = +10 cycles from IrdaRxStartIsr

UartTxDataIsr					;	Time = 4/11/17 cycles
	decsz	UartTxDivide			;1/2
	jmp	UartTxRet			;3	Isr Time = +n cycles from UartTxIsr
	decsz	UartTxBitCount			;1/2	Sent all bits?
	jmp	:Bit				;3	No  => output next bit
:End	snb	UartTxStart			;1/2	Yes => complete, Another byte to transmit?
	jmp	UartTxStartIsr			;3	Yes => UartTxStartIsr
	clrb	UartTxMode			;1	No => Complete
	setb	UartTxEmpty			;1	Flag to indicate that the transmission is complete
	jmp	UartTxRet			;3	Complete
:Bit	movb	UartTxPin, UartTxBits.0		;4	Output next bit
	stc					;1	Stop bit (idle = 1)
	rr	UartTxBits			;1
	mov	UartTxDivide, #UartSpeed	;2	Apply UartSpeed
	jmp	UartTxRet			;3	Isr Time = +n cycles from UartTxIsr

UartTxStartIsr
	clrb	UartTxPin			;1	Output start bit
	mov	UartTxBits, UartTxData		;2	Load data for transmission
	mov	UartTxDivide, #UartSpeed	;2	Apply UartSpeed
	mov	UartTxBitCount, #10		;2	Bit count = 8 data + 1 stop + 1 for stop bit to complete
	clrb	UartTxStart			;1	Clear start mode
	setb	UartTxMode			;1	Enter Tx mode
	jmp	UartTxRet			;3	Isr Time = +n cycles

UartRxDataIsr
	decsz	UartRxDivide			;1/2
	jmp	UartRxRet			;3	Isr Time = +n cycles
	decsz	UartRxBitCount			;1/2
	jmp	:Read				;3
:Stop	mov	UartRxData, UartRxBits		;2	Copy bits into UartData
	clrb	UartRxMode			;1	Finished
	setb	UartRxAvail			;1
	jmp	UartRxRet			;3	Isr Time = +n cycles
:Read	clc					;1	Determine bit
	snb	UartRxPin			;1/2	Determine bit
	stc					;1	Determine bit
	rr	UartRxBits			;1	Record bit
	mov	UartRxDivide, #UartSpeed	;2	Apply baud rate
	jmp	UartRxRet			;3	Isr Time = +n cycles

UartRxStartIsr
	mov	UartRxDivide, #UartSpeed / 2	;2	UartDivide = UartSpeed * 0.5
	mov	UartRxBitCount, #10		;2	Bit count = 10 (1/2 start, 8 data, 1 stop)
	setb	UartRxMode			;1	Enter rx mode
	jmp	UartRxRet			;3	Isr Time = +n cycles


IsrInit
	clr	IsrStatus
	bank	IsrBank
	clr	IrdaUartStatus
	mov	IrdaSpeed, #Irda9600
	mov	!option, #%10011111		;enable rtcc interrupt
	retp

;********************************************************************************
		ENDM
FrameInfoSeg		MACRO
;********************************************************************************
;  FRAMING LAYER
;********************************************************************************
;
; Receive  : Processes incomming characters and passes payload to payload layer
; Transmit : Frames and applies transparency to payload data
;
;********************************************************************************
;
; Normal Frame Format:  Allowable:  Send:
;   n * FF		n >= 0      n = 10
;   n * BOF		n >= 1      n = 1
;   n * Payload data
;   2 * FCS
;   1 * EOF
;
; FCS - Frame Check Sequence
;   16 bit CCITT CRC sent low byte first
;   Transmit : send the complement of the calculated FCS
;   Receive  : include FCS bytes in calculation of the FCS, FCS will equal $f0b8 if valid
;   Note : FCS covers the payload data only.
;          It is calculated prior to adding any transparency bytes (ie FCS bytes must also be transparent).
;
; Transparency:
;   CE(=$7D)	indicates transparency issue
;   CE EOF	incicates sender has terminated packet
;   CE BOF	indicates sender has restarted payload
;   CE *	anything else: XOR with $20 to recover origional data
;
;********************************************************************************
;
;Asynchronous Events
;
;	a2flRxAvail()					;Signal to indicate that a byte has been received
;	a2flTxEmpty()					;Signal to indicate that the last byte has finished transmitting
;
;Interface
;
;	fl2plRxData(w=Data)				;Data byte from frame
;	fl2plRxValid()					;Payload data is complete and valid
;	fl2plRxError()					;Payload data contains errors
;	pl2flRxIgnore() call				;Return to idle state thus terminating any frame being received
;
;	pl2flTxStart()					;Request from payload layer to send a frame - Does not test for media busy
;	fl2plTxData(ret w=Data ret z=Last) call		;Request data from payload layer - Z flag is set if its the last byte
;	fl2plTxComplete()				;Inform payload layer that the transmission is complete
;
;Notes
; - The Rx code does not time out but is reset by calling RxIgnore, by receiving a new frame, or by transmitting a frame
; - If a frame is transmitted (TxStart) while a frame is being recieved the RxCode will reset to the idle state
;   without indicating an error (RxError).
;
;********************************************************************************
			ENDM


FrameDataSeg		MACRO
;********************************************************************************
;  FRAMING LAYER
;********************************************************************************

		org	$38

flBank		= 	$38			;8 bytes used - Note bank shared with Uart

flState		ds	1			;flBank - current state
flData		ds	1			;flBank - storage for a byte received
flPosition	ds	1			;flBank - Counter used to count the FF codes at start of frame and to keep track of buffer
flBuffer	ds	2			;flBank - 2 byte buffer to delay the passing of payload data to allow the removal of the FCS
flFFCount	ds	1			;flBank - number of FFs to send at the start of each packet
flFCSl		ds	1			;flBank - 16-bit FCS value (low byte)
flFCSh		ds	1			;flBank - 16-bit FCS value (high byte)

flRxState		= %00000000
flTxState		= %10000000

flRxBeginState		= 1 + flRxState		;waiting for start of payload
flRxPayloadState	= 2 + flRxState		;receiving payload data
flRxCtrlState		= 3 + flRxState		;waiting for byte after CE code

flTxBeginState		= 1 + flTxState		;sending initial FF bytes
flTxCtrlState		= 2 + flTxState		;waiting to send an encoded payload data byte
flTxPayloadState	= 3 + flTxState		;waiting to send another payload byte
flTxFCSlState		= 4 + flTxState		;waiting to send FCSl
flTxFCShState		= 5 + flTxState		;waiting to send FCSh
flTxSendEndState	= 6 + flTxState		;waiting to send EOF to close frame
flTxWaitEndState	= 7 + flTxState		;waiting for EOF to finish begin sent

BOF			= $C0	; = %11000000	;Beginning of Frame code (refer IrLAP specification)
EOF			= $C1	; = %11000001	;End of Frame code (refer IrLAP specification)
CE			= $7D	; = %01111101	;Control Escape code (refer IrLAP specification)

ValidFCSh		= $F0
ValidFCSl		= $B8

;********************************************************************************
			ENDM


FrameCodeSeg		MACRO
;********************************************************************************
;  FRAMING LAYER
;********************************************************************************

;********** a2flReset **********

a2flReset
	bank	IsrBank
	mov	IrdaSpeed, #Irda9600		;IrDA UART speed = 9600
	bank	flBank
	clr	flState				;Reset to idle state
	mov	flFFCount, #10			;Default to 10 FFs @ 9600 = 10.42ms
	retp

;********** a2flRxAvail **********

a2flRxAvail					;The IrdaRxAvail flag was set
	bank	IsrBank
	mov	w, IrdaData			;Get received byte
	clrb	IrdaRxAvail			;Clear flag
	bank	flBank
	snb	flState.7			;Current state = receiving or idle ?
	retp					;No => ignore (do not need to inform lap layer of media busy as in transmit mode)
	mov	flData, w			;Store byte that was received
	debug	PhysicalDataRx			;Debug: pass data received
	call	@fl2lapMediaBusy		;Inform lap layer of media busy
	bank	flBank
	mov	w, flState			;Jump based on state
	jmp	PC+w
	jmp	flRxIdle			; 0 = Idle
	jmp	flRxBegin			; 1 = flRxBeginState
	jmp	flRxPayload			; 2 = flRxPayloadState
	jmp	flRxCtrl			; 3 = flRxCtrlState

;********** a2flTxEmpty **********

a2flTxEmpty					;From physical layer: Last byte has finished transmitting
	bank	IsrBank
	clrb	IrdaTxEmpty			;Clear flag
	bank	flBank
	sb	flState.7			;Check that it is a TxState
	retp					;Rx state or idle => return
	mov	w, flState			;Jump based on state
	and	w, #%01111111			;Remove Tx state flag
	jmp	PC+w
	retp					; 0 = Invalid state
	jmp	flTxBegin			; 1 = flTxBeginState
	jmp	flTxCtrl			; 2 = flTxCtrlState
	jmp	flTxPayload			; 3 = flTxPayloadState
	jmp	flTxFCSl			; 4 = flTxFCSlState
	jmp	flTxFCSh			; 5 = flTxFCShState
	jmp	flTxSendEnd			; 6 = flTxSendEndState
	jmp	flTxWaitEnd			; 7 = flTxWaitEndState

;********** pl2flRxIgnore **********

pl2flRxIgnore
	bank	flBank
	clr	flState				;Reset to idle state
	retp

;********************************************************************************
;  FRAMING LAYER - FCS Subroutines
;********************************************************************************

;********** FCS Subroutines **********

flFCSa		=	Temp			;Global - Tempory varable used in the FCS calculation

flFCSInit
	mov	w, #$ff				;Init FCS to $FFFF
	mov	flFCSh, w			;Init FCS to $FFFF
	mov	flFCSl, w			;Init FCS to $FFFF
	retp

flFCSData					;Add data to FCS (w = Data) (must be in flBank)
	xor	flFCSl, w			;FCSl[=X] = FCSl xor w
	mov	w,<>flFCSl			;w = FCSl[32107654]
	and	w,#%11110000			;w = FCSl[3210oooo]
	xor	flFCSl, w			;FCSl = FCSl xor (FCSl shl 4)
						;Calculate A = FCSh
	mov	w, <>flFCSl			;w = FCSl[32107654]
	mov	flFCSa, w			;A = FCSl[32107654]
	mov	w, >>flFCSa			;w = FCSl[x3210765]
	and	w, #%00000111			;w = FCSl[ooooo765]
	xor	w, flFCSl			;w = FCSl xor (FCSl shr 5)
	mov	flFCSa, w			;store w into A = new FCSh value
						;Calculate new FCSl value
	rl	flFCSl				;
	rl	flFCSl				;
	mov	w, <<flFCSl			;w = FCSl[43210xxx]
	and	w, #%11111000			;w = FCSl[43210ooo]
	xor	w, flFCSh			;w = (FCSl shl 3) xor FCSh
	mov	flFCSl, w			;Store w into FCSl
	mov	w, <>flFCSa			;w = A[32107654]
	and	w, #%00001111			;w = A[oooo7654]
	xor	flFCSl, w			;FCSl = (FCSl shl 3) xor FCSh xor (A shr 4)
						;Store new FCSh value
	mov	w, flFCSa			;A holds FCSh value
	mov	flFCSh, w			;Store A in FCSh
	retp

;********************************************************************************
;  FRAMING LAYER - Receive
;********************************************************************************

flRxPassData					;Adds data (flRxData) to FCS and passes data to payload layer
	mov	w, flData			;Last byte that was received
	call	flFCSData			;Add Data to FCS value
	mov	Temp, flBuffer+1		;Shift data out of buffer
	mov	flBuffer+1, flBuffer+0		;Shift data in buffer
	mov	flBuffer+0, flData		;Shift new data into buffer
	incsz	flPosition			;Inc position, Zero ?
	retp					;No  => buffer is not full, return
	dec	flPosition			;Set position to FF to indicate buffer is still full
	mov	w, Temp				;Data to pass
	jmp	@fl2plRxData			;pass data to payload layer (payload layer issues retp instruction)

;********** a2flRxAvail - Idle State **********

flRxIdle					;Waiting for a BOF to indicate start of frame
	csne	flData, #BOF			;Was byte a BOF ?
	inc	flState				;Yes => BOF received indicating start of frame => change to flRxBeginState
	retp

;********** a2flRxAvail - Begin State **********

flRxBegin					;Waiting for non BOF to indicate start of data
	csne	flData, #BOF			;Was byte a BOF ?
	retp					;Yes => ignore
	csne	flData, #EOF			;Was byte a EOF indicating sender has terminated frame ?
	jmp	:Idle				;Yes => return to idle state
	csne	flData, #CE			;Was byte a CE indicating a transparency issue ?
	jmp	:Ctrl				;Yes => change to Ctrl state
	mov	flState, #flRxPayloadState	;Must be data => Payload state
	call	flFCSInit			;Init FCS
	mov	flPosition, #-3			;Init buffer position
	jmp	flRxPassData			;pass data to payload layer (payload layer issues ret instruction)
:Idle	clr	flState				;EOF indicating sender has terminated frame => return to idle state
	retp
:Ctrl	mov	flState, #flRxCtrlState		;CE indicating transparency issue => change to Ctrl state
	retp

;********** a2flRxAvail - Payload State **********

flRxPayload					;Currently receiving payload
	csne	flData, #BOF			;Was byte a BOF indicating sender has terminated the payload and started again ?
	jmp	:Begin				;Yes => terminate payload and goto Begin state
	csne	flData, #EOF			;Was byte an EOF indicating the frame/payload is complete ?
	jmp	:Idle				;Yes => signal complete payload and retpurn to idle state
	csne	flData, #CE			;Was byte a CE indicating a transparency issue ?
	jmp	:Ctrl				;Yes => change to Ctrl state
	jmp	flRxPassData			;pass data to payload layer (payload layer issues retp instruction)
:Begin	mov	flState, #flRxBeginState	;premature BOF => indicate payload reset to payload layer and retpurn to RxBegin State
	jmp	@fl2plRxError			;indicate error to payload layer (payload layer issues retp instruction)
:Idle	clr	flState				;EOF => end of frame reached => inform payload layer and retpurn to idle state
	cse	flFCSh, #ValidFCSh		;valid FCS (high) ?
	jmp	@fl2plRxError			;No => indicate reset to payload layer (payload layer issues retp instruction)
	cse	flFCSl, #ValidFCSl		;valid FCS (low) ?
	jmp	@fl2plRxError			;No => indicate reset to payload layer (payload layer issues retp instruction)
	jmp	@fl2plRxValid			;FCS valid => indicate complete to payload layer (payload layer issues retp instruction)
:Ctrl	mov	flState, #flRxCtrlState
	retp

;********** a2flRxAvail - Ctrl State **********

flRxCtrl					;CE has been encountered, need to check next character
	csne	flData, #BOF			;Was byte BOF indicating sender has terminated payload and started again ?
	jmp	:Begin				;Yes => restart at Begin state (Note payload layer has been passed data => must inform payload layer of reset)
	csne	flData, #EOF			;Was byte EOF indicating sender has terminated frame ?
	jmp	:Idle				;Yes => retpurn to idle (Note: payload layer has been passed any data => must inform payload layer of reset)
	mov	flState, #flRxPayloadState	;Must be data => pass data to payload layer and retpurn to payload state
	xor	flData, #$20			;Recover data
	jmp	flRxPassData			;pass data to payload layer (payload layer issues retp instruction)
:Begin	mov	flState, #flRxBeginState	;BOF => sender has terminated payload and started again => retpurn to begin state
	jmp	@fl2plRxError			;indicate error to payload layer (payload layer issues retp instruction)
:Idle	clr	flState				;EOF => sender has terminated frame => retpurn to idle state
	jmp	@fl2plRxError			;indicate error to payload layer (payload layer issues retp instruction)

;********************************************************************************
;  FRAMING LAYER - Transmit
;********************************************************************************

flTxSendData					;Send byte (w) now (doesn't check for busy)
	bank	IsrBank
	mov	IrdaData, w			;Byte to send
	setb	IrdaTxStart			;Send byte
	debug	PhysicalDataTx			;Debug: pass data being transmitted
	retp					;WARNING - not in flBank

;********** pl2flTxFrame **********

pl2flTxFrame					;Request to start a new frame
	bank	flBank
	mov	flState, #flTxBeginState	;Next state = begin
	mov	flPosition, flFFCount		;Counter = FFCount
	mov	w, #$FF
	jmp	flTxSendData			;Send FF (flTxSendData issues ret instruction)

;********** a2flTxEmpty - Begin State **********

flTxBegin					;Sending prefex FF bytes
	dec	flPosition			;Decrement counter
	snz					;Zero ?
	jmp	:BOF				;Yes => send BOF and set next state to send payload data
	mov	w, #$FF				;No  => Send another FF
	jmp	flTxSendData			;(TxSendData issues ret instruction)
:BOF	mov	flState, #flTxPayloadState	;Will enter flTxPayload state after BOF has been sent
	call	flFCSInit			;Init FCS
	mov	w, #BOF				;Send BOF
	jmp	flTxSendData

;********** a2flTxEmpty - Send States **********

flTxPayload
	call	@fl2plTxData			;Get data from payload layer
	bank	flBank
	snz					;Is this the last byte ? (Z set)
	inc	flState				;Yes => Next State = FCSl
	mov	flData, w			;Store data
	debug	PayloadDataTx			;Debug: pass payload data being transmitted
	call	flFCSData			;w = flData - Add data to FCS
	jmp	flTxSend			;Check for control code and send

flTxFCSl
	mov	w, /flFCSl			;Next data to send = FCSl
	mov	flData, w			;Store in TxData
	inc	flState				;Next State = FCSh
	jmp	flTxSend			;Check for control code and send

flTxFCSh
	mov	w, /flFCSh			;Next data to send = FCSh
	mov	flData, w			;Store in TxData
	inc	flState				;Next State = End
	jmp	flTxSend			;Check for control code and send

flTxSend					;Send payload byte
	csne	flData, #BOF			;Is byte a control code ?
	jmp	:Ctrl				;Yes => transparency issue
	csne	flData, #EOF			;Is byte a control code ?
	jmp	:Ctrl				;Yes => transparency issue
	csne	flData, #CE			;Is byte a control code ?
	jmp	:Ctrl				;Yes => transparency issue
	mov	w, flData			;Yes => transmit data
	jmp	flTxSendData			;Send byte
:Ctrl	mov	flPosition, flState		;Store current state in position variable
	mov	flState, #flTxCtrlState		;Next state = TxCtrlState
	mov	w, #CE
	jmp	flTxSendData			;Send CE code (TxSendData issues ret instruction)

flTxCtrl
	mov	flState, flPosition		;Recover old state from position variable
	mov	w, flData
	xor	w, #$20				;Encode data
	jmp	flTxSendData

;********** a2flTxEmpty - SendEnd State **********

flTxSendEnd					;FCS finished => send EOF to close frame
	inc	flState				;Next state = flTxWaitEnd state
	mov	w, #EOF
	jmp	flTxSendData			;Send EOF (TxSendData issues ret instruction)

;********** a2flTxEmpty - WaitEnd State **********

flTxWaitEnd					;Frame finished and now last byte has finished sending
	clr	flState				;Return to idle state
	jmp	@fl2plTxComplete		;Inform payload layer that the transmission is complete (payload layer issues retp instruction)

;********************************************************************************
		ENDM
PayloadInfoSeg		MACRO
;********************************************************************************
;  PAYLOAD LAYER
;********************************************************************************
;
;Framing Layer Events
;
;	fl2plRxData(w=Data)				;Data byte from frame
;	fl2plRxValid()					;Payload data is complete and valid
;	fl2plRxError()					;Payload data contains errors
;	pl2flRxIgnore() call				;Tell framing layer to ignore the current frame
;
;	pl2flTxStart()					;Request framing layer to start a frame
;	fl2plTxData(var w=Data var z=Last) call		;Request for data from framing layer - Z flag is set if its the last byte
;	fl2plTxComplete()				;Transmission is complete
;
;LAP Layer Events
;
;	pl2lapRxFrame(w=Type)				;Incomming frame of given type
;	pl2lapRxValid()					;Frame was valid
;	pl2lapRxError()					;Frame was invalid
;	pl2lapRxXIDData(w=Data)				;Pass XID data to lap layer
;	pl2lapRxIData(w=Data)				;Pass I data to lap layer
;	pl2lapRxUIData(w=Data)				;Pass I data to lap layer
;	lap2plRxIgnore()				;LAP layer has requested that the frame should be ignored
;
;	lap2plSNRMAccept()				;Accept connection and send reply
;	lap2plTxXIDCmd(w=Slot)				;Send a XID command frame
;	lap2plTxXIDRsp()				;Send a XID response frame
;	lap2plTxSimpleRsp(w=Command)			;Send simple response frame
;	lap2plTxIRsp(w=Command)				;Send an I frame
;	pl2lapTxIData(ret w=Data ret z=Last) call	;Request for data
;	pl2lapTxComplete()				;Complete indication
;
;	lap2plGenerateNewAddr				;Request that a new 32-bit address be generated
;
;********************************************************************************
			ENDM


PayloadDataSeg		MACRO
;********************************************************************************
;  PAYLOAD LAYER
;********************************************************************************

		org	$50

plBank		= 	$50			;16 bytes used - Bank not shared

plState		ds	1			;Current state
plData		ds	1			;Incomming byte of payload data
plFrameType	ds	1			;The frame type for shared code / passed to lap layer
plCommand	ds	1
plPosition	ds	1			;Current position for multibyte states
plConnAddr	ds	1			;Connection address (must be FF if not connected)
plSelfAddr	ds	4			;Own 4 byte address
plDestAddr	ds	4			;Dest 4 byte address
plInfo		ds	2			;Frame specific information

plTxAddressByte	=	plData			;Address to be transmitted
plTxPostCommand	=	plPosition

plIDataDLSAP	=	plInfo+0		;DLSAP byte from/for a I Data frame
plIDataSLSAP	=	plInfo+1		;SLSAP byte from/for a I Data frame
plXIDSlot	=	plInfo+0		;Slot number from/for a XID frame
plXIDFlags	=	plInfo+1		;Discovery Flags from/for a XID frame
plSNRMConnAddr	=	plInfo+0		;Connection Address of SNRM frame
plSNRMBaudRate	=	plInfo+1		;Baudrate parameter from SNRM frame

iFrame		= 1
sRRFrame	= 2
sRNRFrame	= 3
sREJFrame	= 4
sSREJFrame	= 5
uUIFrame	= 6				;UICmd or UIRsp (same command)
uDISCFrame	= 7				;DISCCmd or RDRsp (same command)
uUARspFrame	= 8				;UARsp
uNRMFrame	= 9				;SNRMCmd or RNRMRsp (same command)
uTESTFrame	= 10				;TESTCmd or TESTRsp (same command)
uFRMRRspFrame	= 11				;FRMRRsp
uDMRspFrame	= 12				;DMRsp
uXIDCmdFrame	= 13				;XIDCmd
uXIDRspFrame	= 14				;XIDRsp

sRR		= %00010001			;%xxx10001
sRNR		= %00010101			;%xxx10101
sREJ		= %00011001			;%xxx11001
sSREJ		= %00011101			;%xxx11101

uSNRMCmd	= %10010011
uDISCCmd	= %01010011
uUICmd		= %00010011
uXIDCmd		= %00111111
uTESTCmd	= %11110011
uRNRMRsp	= %10010011
uUARsp		= %01110011
uFRMRRsp	= %10010111
uDMRsp		= %00011111
uRDRsp		= %01010011
uUIRsp		= %00010011
uXIDRsp		= %10111111
uTESTRsp	= %11110011

plRxState	= %00000000
plTxState	= %10000000

plRxCommandState	=  1 + plRxState	;
plRxDataIgnoreState	=  2 + plRxState
plRxIDataState		=  3 + plRxState	;RxI
plRxUIDataState		=  4 + plRxState	;RxUI
plRxXIDFormatState	=  5 + plRxState	;RxXID
plRxXIDSourceState	=  6 + plRxState	;RxXID
plRxXIDDestState	=  7 + plRxState	;RxXID
plRxXIDFlagsState	=  8 + plRxState	;RxXID
plRxXIDSlotState	=  9 + plRxState	;RxXID
plRxXIDVersionState	= 10 + plRxState	;RxXID
plRxXIDInfoState	= 11 + plRxState	;RxXID
plRxSNRMSourceState	= 12 + plRxState	;RxSNRM
plRxSNRMDestState	= 13 + plRxState	;RxSNRM
plRxSNRMAddrState	= 14 + plRxState	;RxSNRM
plRxSNRMParamTypeState	= 15 + plRxState	;RxSNRM
plRxSNRMParamSizeState	= 16 + plRxState	;RxSNRM
plRxSNRMParamDataState	= 17 + plRxState	;RxSNRM

plTxCompleteState	=  1 + plTxState	;Waiting for Complete indication from framing Layer
plTxAddressState	=  2 + plTxState	;
plTxCommandState	=  3 + plTxState	;
plTxIDataDLSAPState	=  4 + plTxState	;
plTxIDataSLSAPState	=  5 + plTxState	;
plTxIDataDataState	=  6 + plTxState	;
plTxUIDataState		=  7 + plTxState	;
plTxXIDFormatState	=  8 + plTxState	;
plTxXIDSourceState	=  9 + plTxState	;
plTxXIDDestState	= 10 + plTxState	;
plTxXIDFlagsState	= 11 + plTxState	;
plTxXIDSlotState	= 12 + plTxState	;
plTxXIDVersionState	= 13 + plTxState	;
plTxXIDFooterState	= 14 + plTxState	;
plTxUASourceState	= 15 + plTxState	;
plTxUADestState		= 16 + plTxState	;
plTxUABaudRateState	= 17 + plTxState	;
plTxUAParamState	= 18 + plTxState	;

;********************************************************************************
			ENDM


PayloadCodeSeg		MACRO
;********************************************************************************
;  PAYLOAD LAYER
;********************************************************************************

;********** a2plReset **********

a2plReset
	bank	plBank
	clr	plState				;Reset to idle state
	mov	plConnAddr,#$FF			;Not connected => address must be $FF
	retp

;********** fl2plRxData **********

fl2plRxData
	bank	plBank
	snb	plState.7			;Check that it is a RxState
	retp					;Tx state => return
	mov	plData, w			;Store incomming byte
	debug	PayloadDataRx			;Debug: Pass payload byte received
	mov	w, plState			;Jump based on state
	jmp	PC+w
	jmp	plRxIdle			; 0 = plIdleState
	jmp	plRxCommand			; 1 = plRxCommandState
	retp					; 2 = plRxDataIgnoreState
	jmp	plRxIData			; 3 = plRxIDataState
	jmp	plRxUIData			; 4 = plRxUIDataState
	jmp	plRxXIDFormat			; 5 = plRxXIDFormatState
	jmp	plRxXIDSource			; 6 = plRxXIDSourceState
	jmp	plRxXIDDest			; 7 = plRxXIDDestState
	jmp	plRxXIDFlags			; 8 = plRxXIDFlagsState
	jmp	plRxXIDSlot			; 9 = plRxXIDSlotState
	jmp	plRxXIDVersion			;10 = plRxXIDVersionState
	jmp	plRxXIDInfo			;11 = plRxXIDInfoState
	jmp	plRxSNRMSource			;12 = plRxSNRMSourceState
	jmp	plRxSNRMDest			;13 = plRxSNRMDestState
	jmp	plRxSNRMAddr			;14 = plRxSNRMAddrState
	jmp	plRxSNRMParamType		;15 = plRxSNRMParamTypeState
	jmp	plRxSNRMParamSize		;16 = plRxSNRMParamSizeState
	jmp	plRxSNRMParamData		;17 = plRxSNRMParamDataState

;********** fl2plTxData **********

fl2plTxData
	bank	plBank
	sb	plState.7			;Check that it is a TxState
	retp					;Rx state => return
	mov	w, plState			;Jump based on state
	and	w, #%01111111			;Remove Tx state flag
	jmp	PC+w
	retp					; 0 = Invalid state
	retp					; 1 = plTxCompleteState (Cannot receive TxData in this state)
	jmp	plTxAddress			; 2 = plTxAddressState
	jmp	plTxCommand			; 3 = plTxCommandState
	jmp	plTxIDataDLSAP			; 4 = plTxIDataDLSAPState
	jmp	plTxIDataSLSAP			; 5 = plTxIDataSLSAPState
	jmp	plTxIDataData			; 6 = plTxIDataDataState
	jmp	plTxUIData			; 7 = plTxUIDataState
	jmp	plTxXIDFormat			; 8 = plTxXIDFormatState
	jmp	plTxXIDSource			; 9 = plTxXIDSourceState
	jmp	plTxXIDDest			;10 = plTxXIDDestState
	jmp	plTxXIDFlags			;11 = plTxXIDFlagsState
	jmp	plTxXIDSlot			;12 = plTxXIDSlotState
	jmp	plTxXIDVersion			;13 = plTxXIDVersionState
	jmp	plTxXIDFooter			;14 = plTxXIDFooterState
	jmp	plTxUASource			;15 = plTxUASourceState
	jmp	plTxUADest			;16 = plTxUADestState
	jmp	plTxUABaudRate			;17 = plTxUABaudRateState
	jmp	plTxUAParam			;18 = plTxUAParamState

;********** fl2plTxComplete **********

fl2plTxComplete
	bank	plBank
	clr	plState					;return to idle state
	debugl	PayloadDataTx, '^'			;Debug: Payload data complete indication
	jmp	@pl2lapTxComplete			;Indicate complete to lap layer (pl2lapTxComplete will issue ret instrustion)

;********** lap2plTxUICmd **********

lap2plTxUICmd	jmp	plTxUICmd

;********************************************************************************
;  PAYLOAD LAYER - Internal Subroutines
;********************************************************************************

plRxDecodeSCmd						;WARNING - does not set pa bits when ret => must be callled form same half page
	mov	Temp, w					;Command: check bits %....nn..
	rr	Temp					;Shift command right 1
	mov	w, >>Temp				;Shift command right 1 and into w
	and	w, #%00000011				;Mask out unwanted bits
	jmp	PC+w					;jump based on w
	retw	sRRFrame				;....00.. = RR
	retw	sRNRFrame				;....01.. = RNR
	retw	sREJFrame				;....10.. = REJ
	retw	sSREJFrame				;....11.. = SREJ

plRxDecodeUNextState				;WARNING - does not set pa bits when ret => must be callled form same half page
	mov	Temp, w				;FrameType
	mov	w, #uUIFrame			;lowest FrameType constant for a U frame
	sub	Temp, w				;subtract lowest valid number so uUIFrame is now 0
	mov	w, Temp
	jmp	PC+w
	retw	plRxUIDataState			;uUIFrame	=	6	;UICmd or UIRsp (same command)
	retw	plRxDataIgnoreState		;uDISCFrame	=	7	;DISCCmd or RDRsp (same command)
	retw	plRxDataIgnoreState		;uUARspFrame	=	8	;UARsp
	retw	plRxSNRMSourceState		;uNRMFrame	=	9	;SNRMCmd or RNRMRsp (same command)
	retw	plRxDataIgnoreState		;uTESTFrame	=	10	;TESTCmd or TESTRsp (same command)
	retw	plRxDataIgnoreState		;uFRMRRspFrame	=	11	;FRMRRsp
	retw	plRxDataIgnoreState		;uDMRspFrame	=	12	;DMRsp
	retw	plRxXIDFormatState		;uXIDCmdFrame	=	13	;XIDCmd
	retw	plRxXIDFormatState		;uXIDRspFrame	=	14	;XIDRsp

lap2plGenerateNewAddr				;Note: code is synchronous with the ISR therfore RTCC and Timer registers are not random numbers
	bank	TimerBank
	mov	w, Random			;Random number
	bank	plBank
	mov	plSelfAddr+0, w			;Byte 0 = Random number
	mov	FSR, w
	mov	w, INDF
	bank	plBank
	mov	plSelfAddr+1, w			;Byte 1 = contents of the register pointer to by the Random number
	mov	m, w				;m = byte 1 number (semi random)
	mov	w, plSelfAddr+0			;w = byte 0 number (fully random)
	iread					;read ROM and address given by w and m
	mov	plSelfAddr+2, w			;Byte 2 = low contents of ROM pointed to by byte1:byte0
	mov	w, m				;w = m = high 4 bits of ROM contents
	mov	plSelfAddr+3, w			;Byte 3 = high contents of ROM pointed to by byte1:byte0
	retp

;********************************************************************************
;  PAYLOAD LAYER - Receive
;********************************************************************************

;********** fl2plRxValid **********

fl2plRxValid
	clrb	ledERR				;Turn ERR led off
	debugl	PayloadDataRx, '^'		;Debug: Indicate complete
	bank	plBank
	clr	plState				;Return to idle state
	jmp	@pl2lapRxValid			;Inform lap layer that frame was valid (lap layer will issue ret instruction)


;********** fl2plRxError **********

fl2plRxError
	setb	ledERR				;Turn ERR led on
	debugl	PayloadDataRx, '!'		;Debug: Indicate error
	bank	plBank
	clr	plState				;Return to idle state
	jmp	@pl2lapRxError			;Inform lap layer that frame was invalid (lap layer will issue ret instruction)

;********** lap2plRxIgnore **********

lap2plRxIgnore					;Ignore the current incomming frame
	bank	plBank
plRxIgnore
	clr	plState				;Return to idle state
	jmp	@pl2flRxIgnore
plRxInvalid
	clr	plState				;Return to idle state
	call	@pl2flRxIgnore
	jmp	@pl2lapRxError			;Inform lap layer of error

;********************************************************************************
;  PAYLOAD LAYER - RxData General
;********************************************************************************

plRxStoreSource
	mov	w, #plDestAddr				;pointer to DestAddress variable
	add	w, plPosition				;add offset
	mov	FSR, w					;Now can indirectly access
	mov	INDF, plData				;Store byte into SourceAddr
	inc	plPosition				;Move offset ready for next byte of SourceAddr
	cse	plPosition, #4				;Have 4 bytes been received ?
	retp						;No  => remain in this state waiting for next byte
	inc	plState					;Yes => end of Source. Change to next state
	clr	plPosition
	retp

plRxTestDest						;WARNING : will pass FF bytes in specific address (ie bytewise checking, not FFFFFFFF checking)
	csne	plData, #$FF				;Broadcast address ?
	jmp	:Cont					;Yes => Contiue
	mov	w, #plSelfAddr				;pointer to SelfAddress variable
	add	w, plPosition				;add offset
	mov	FSR, w					;Now can indirectly access
	cse	plData, INDF				;Self Address ?
	jmp	plRxInvalid				;No  => Ignore frame, Inform lap layer of error, and return to idle
:Cont	inc	plPosition				;Move offset ready for next byte of DestAddr
	cse	plPosition, #4				;Have 4 bytes been received ?
	retp						;No  => remain in this state waiting for next byte
	inc	plState					;Yes => end of DestAddr. Change to next state
	clr	plPosition
	retp

;********************************************************************************
;  PAYLOAD LAYER - RxData
;********************************************************************************

;********** fl2plRxData - Idle State **********

plRxIdle						;First byte = address
	mov	w, plData				;Received Address
	xor	w, plConnAddr				;Compare with interested address
	sz						;Valid address ?
	jmp	plRxIgnore				;No  => ignore
	mov	plState, #plRxCommandState		;Yes => next will receive command byte
	retp

;********** fl2plRxData - RxCommand State **********

plRxCommand
	mov	plCommand, plData			;Store command
	sb	plCommand.4				;Is the P/F bit set ?
	jmp	plRxIgnore				;No => Ignore frame (IrDA lite spec p10 and p16) and return to idle state
	sb	plCommand.0				;Is this an I frame ? (%.......0)
	jmp	plRxICommand				;Yes => process
	sb	plCommand.1				;No  => must be S or U frame. Is this a S frame ?
	jmp	plRxSCommand				;Yes (%......01) => process S frame 
	jmp	plRxUCommand				;No  (%......11) => process U frame

plRxICommand
	debugl	PayloadInfo, 'I'
	mov	plState, #plRxIDataState		;Next should be data
	mov	plFrameType, #iFrame			;store frame type and w will also be passed to lap layer
	jmp	@pl2lapRxFrame				;pass message (lap layer will issue ret instruction)

plRxSCommand
	debugl	PayloadInfo, 'S'
	mov	plState, #plRxDataIgnoreState		;Next should be complete indication (ie no data) but need waiting state
	mov	w, plCommand
	call	plRxDecodeSCmd				;pass w = plRxData, returns w for plFrameType
	mov	plFrameType, w				;store frame type and w will also be passed to lap layer
	jmp	@pl2lapRxFrame				;pass message (lap layer will issue ret instruction)

plRxUCommand
	debugl	PayloadInfo, 'U'
	mov	plPosition, #_plUCommands		;plPosition = 1st byte of data
:Loop	mov	m, #_plUCommands / 256			;m = Pointer to string (high)
	mov	w, plPosition				;w = Pointer to string (low)
	inc	plPosition				;Increment offset for next byte
	iread						;Read data byte from ROM
	xor	w, plCommand				;is the byte the same as the received command ?
	jz	:Found					;Yes => must be valid
	mov	w, m					;No  => try again. Move high part of data to w
	test	w					;Is this the last byte ?
	jz	:Loop					;No  => try again
	jmp	plRxIgnore				;Yes => Invalid command => ignore and return to idle state
:Found	mov	plFrameType, plPosition			;plFrameType = position
	mov	w, #_plUCommands + 1			;w = starting offset
	sub	plFrameType, w				;remove offset => FrameType 0 for a uUIFrame
	mov	w, #uUIFrame				;constant of first type of U command (uUIFrame = 6)
	add	plFrameType, w				;FrameType is now correct
	mov	w, plFrameType				;pass FrameType in w
	call	plRxDecodeUNextState			;Returns w = next state
	mov	plState, w				;Store state
	clr	plPosition				;Clear position for following states
	mov	w, plFrameType				;pass frame type to lap layer
	jmp	@pl2lapRxFrame				;pass message (lap layer will issue ret instruction)

;********************************************************************************
;  PAYLOAD LAYER - Receiving I Frame
;********************************************************************************

;********** fl2plRxData - RxIData State **********

plRxIData
	mov	w, plData				;Data to pass
	debug	IFrameDataRx				;Show debug info
	jmp	@pl2lapRxIData				;Pass data to lmp layer (via lap layer)

;********************************************************************************
;  PAYLOAD LAYER - Receiving UI Frame
;********************************************************************************

;********** fl2plRxData - RxUIData State **********

plRxUIData
	mov	w, plData				;Data to pass
	jmp	@pl2lapRxUIData				;Pass data to app layer (via lap layer)

;********************************************************************************
;  PAYLOAD LAYER - Receiving XID Frame
;********************************************************************************

;********** fl2plRxData - RxXIDFormat State **********

plRxXIDFormat
	cse	plData, #1				;Format must be 1
	jmp	plRxInvalid				;No  => Ignore frame, inform lap layer, and return to idle state
	inc	plState					;Next 4 bytes will be the source address => Enter plRxXIDSourceState
	clr	plPosition				;Byte 0 of the source address
	retp

;********** fl2plRxData - RxXIDSource State **********

plRxXIDSource	=	plRxStoreSource			;Store byte in DestAddr

;********** fl2plRxData - RxXIDDest State **********

plRxXIDDest	=	plRxTestDest			;Compare 4 bytes with SelfAddr (mismatch of not FFFFFFFF will change to ignore state)

;********** fl2plRxData - RxXIDFlags State **********

plRxXIDFlags
	mov	plXIDFlags, plData			;Store the flags for the response
	inc	plState					;Next will receive the slot number (plRxXIDSlotState)
	retp

;********** fl2plRxData - RxXIDSlot State **********

plRxXIDSlot
	mov	plXIDSlot, plData			;Store the slot number
	inc	plState					;plRxXIDVersionState
	retp

;********** fl2plRxData - RxXIDVersion State **********

plRxXIDVersion
	test	plData					;Is version = 0 ?
	jnz	plRxInvalid				;No  => Ignore frame, inform lap layer, and return to idle state
	inc	plState					;Next bytes will be the Descovery Info if any (plRxXIDInfoState)
	clr	plPosition				;Clear position for next state
	retp

;********** fl2plRxData - RxXIDInfo State **********

plRxXIDInfo
	mov	w, plData				;Get data byte
	jmp	@pl2lapRxXIDData			;Pass data to lap layer

;********************************************************************************
;  PAYLOAD LAYER - Receiving SNRM Frame
;********************************************************************************

;********** fl2plRxData - RxSNRMSource State **********

plRxSNRMSource	=	plRxStoreSource

;********** fl2plRxData - RxSNRMDest State **********

plRxSNRMDest	=	plRxTestDest

;********** fl2plRxData - RxSNRMAddr State **********

plRxSNRMAddr
	mov	plSNRMConnAddr, plData			;Store ConnAddr (only apply if frame is validated)
	mov	plSNRMBaudRate, #%00000010		;If no baud rate received then default to 9600 (bit 1 indicates 9600)
	inc	plState					;#plRxSNRMParamTypeState - Next bytes are the negioation parameters
	retp

;********** fl2plRxData - RxSNRMParam State **********

plRxSNRMParamType
	inc	plState					;#plRxSNRMParamSizeState - Next byte will state how many bytes of data
	csne	plData, #$01				;Receiving type $01 = baud rate ?
	setb	plSNRMBaudRate.0			;Yes => Set flag to indicate receiving baud rate (bit 0 is normally used to indicate 2400 which we do not support thus will be removed later)
	retp						;No  => continue

plRxSNRMParamSize
	mov	plPosition, plData			;RxData states how many bytes of data
	inc	plState					;#plRxSNRMParamDataState - Next bytes will be the param data
	retp

plRxSNRMParamData
	decsz	plPosition				;Decrement counter; Zero ?
	jmp	:More					;No  => wait for more
	mov	plState, #plRxSNRMParamTypeState	;Yes => Next byte will be another parameter
:More	sb	plSNRMBaudRate.0			;Is this byte the first byte of the baud rate parameter
	retp						;No => ignore
	mov	w, plData				;Get baud rate parameter
	and	w, #%00111110				;And with our supported baud rates = 9600(bit 1), 19200(bit 2), 38400(bit 3) 57600(bit 4) 115200(bit 5)
	mov	plSNRMBaudRate, w			;Store in SNRMBaudRate (note bit 0 is now clear => will correctly ignore next byte of parameter if it is a 2 byte parameter)
	setb	plSNRMBaudRate.1			;Force 9600 to be valid
	retp

;********************************************************************************
;  PAYLOAD LAYER - Tx
;********************************************************************************

plTxFooter						;w = Addr, m = Addr / 256
	add	w, plPosition				;Add offset
	inc	plPosition				;Increment offset for next byte
	iread
	mov	Temp, w					;Store data
	mov	w, m					;Move high part of data to w
	test	w					;Is this the last byte ?
	jnz	:Last					;Yes => Jump
	mov	w, Temp					;Data byte to be transmitted
	clz						;Indicate more data to follow
	retp						;Return data to framing layer
:Last	mov	plState, #plTxCompleteState		;Last byte => change to complete state
	mov	w, Temp					;Data byte to be transmitted
	stz						;Indicate complete
	retp						;Return data to framing layer

plTxSelfAddr
	mov	w, #plSelfAddr				;pointer to SelfAddress variable
	add	w, plPosition				;add offset
	mov	FSR, w					;Now can indirectly access
	inc	plPosition				;Move offset ready for next byte of SourceAddr
	cse	plPosition, #4				;Sent all 4 bytes ?
	jmp	:Send					;No  => Send current byte (stay in this state)
	inc	plState					;Yes => Send current byte (next state)
	clr	plPosition
:Send	mov	w, INDF					;Byte of Source Address
	clz						;Indicate more data to follow
	retp						;Return data to framing layer

plTxDestAddr
	mov	w, #plDestAddr				;pointer to recorded DestAddress variable
	add	w, plPosition				;add offset
	mov	FSR, w					;Now can indirectly access
	inc	plPosition				;Move offset ready for next byte
	cse	plPosition, #4				;Sent all 4 bytes ?
	jmp	:Send					;No  => Send current byte (stay in this state)
	inc	plState					;Yes => Send current byte (Next will send Discovery flags)
	clr	plPosition
:Send	mov	w, INDF					;Byte of Source Address
	clz						;Indicate more data to follow
	retp						;Return data to framing layer

;********************************************************************************

plTxCmdStart
	mov	plState, #plTxAddressState		;First byte = address
	mov	plTxAddressByte, plConnAddr		;Address = ConnAddr
	setb	plTxAddressByte.0			;Indicate Cmd frame
	jmp	@pl2flTxFrame				;Ask to framing layer to start a new frame

plTxRspStart
	mov	plState, #plTxAddressState		;First byte = address
	mov	plTxAddressByte, plConnAddr		;Address = ConnAddr
	clrb	plTxAddressByte.0			;Indicate Cmd frame
	jmp	@pl2flTxFrame				;Ask to framing layer to start a new frame

;********** fl2plTxData - TxAddress State **********

plTxAddress
	inc	plState					;After address will send command
	mov	w, plTxAddressByte			;Send Address
	clz						;Indicate more data to follow
	retp						;Return Data to framing layer

;********** fl2plTxData - TxCommand State **********

plTxCommand
	mov	plState, plTxPostCommand		;After command will change to state given in TxIState
	clr	plPosition				;Clear position just in case needed for following states
	csne	plState, #plTxCompleteState		;Is this the last byte to be sent ?
	jmp	:Last					;Yes
	mov	w, plCommand				;Send Command
	clz						;Indicate more data to follow
	retp						;Return Data to framing layer
:Last	mov	w, plCommand				;Send Command
	stz						;Indicate complete
	retp						;Return Data to framing layer

;********************************************************************************
;  PAYLOAD LAYER - Send Simple Frame
;********************************************************************************

lap2plTxSimpleCmd					;Transmit a frame of type specified in w
	bank	plBank
	mov	plCommand, w 				;Store command in plCommand
	mov	plTxPostCommand, #plTxCompleteState	;After address & command frame will be complete
	jmp	plTxCmdStart				;Set State and Address, and ask framing layer to start frame

lap2plTxSimpleRsp					;Transmit a frame of type specified in w
	bank	plBank
	mov	plCommand, w 				;Store command in plCommand
	mov	plTxPostCommand, #plTxCompleteState	;After address & command frame will be complete
	jmp	plTxRspStart				;Set State and Address, and ask framing layer to start frame

;********************************************************************************
;  PAYLOAD LAYER - Send I Frame
;********************************************************************************

lap2plTxIRsp
	bank	plBank
	mov	plCommand, w 				;Store command in plCommand
	mov	plTxPostCommand, #plTxIDataDLSAPState	;After address & command will send data
	jmp	plTxRspStart				;Set State and Address, and ask framing layer to start frame

plTxIDataDLSAP
	inc	plState					;Next state = plTxIDataSLSAP
	mov	w, plIDataDLSAP				;Send DLSAP byte
	debug	IFrameDataTx				;Show debug info
	clz						;Indicate more data to follow
	retp

plTxIDataSLSAP
	inc	plState					;Next state = plTxIDataData
	mov	w, plIDataSLSAP				;Send SLSAP byte
	debug	IFrameDataTx				;Show debug info
	clz						;Indicate more data to follow
	retp

plTxIDataData
	call	@pl2lapTxIData				;Get next byte to be transmitted (returns z = false if data)
	debug	IFrameDataTx				;Show debug info
	snz						;Is the z flag set (Last byte) ?
	jmp	:Last					;Yes => jump
	retp						;Z is still clear indicating more data to follow
:Last	mov	Temp, w					;Backup data
	bank	plBank
	mov	plState, #plTxCompleteState		;New state = Wait for complete indication
	mov	w, Temp					;Recover data
	stz						;Indicate no more data to follow
	retp

;********************************************************************************
;  PAYLOAD LAYER - Send UI Frame
;********************************************************************************

plTxUICmd
	bank	plBank
	mov	plCommand, #uUICmd			;Store command in plCommand
	mov	plTxPostCommand, #plTxUIDataState	;After address & command will send data
	jmp	plTxCmdStart				;Set State and Address, and ask framing layer to start frame

plTxUIData
	call	@pl2lapTxUIData				;Get next byte to be transmitted (returns z = false if data)
	snz						;Is the z flag set (Last byte) ?
	jmp	:Last					;Yes => jump
	retp						;Z is still clear indicating more data to follow
:Last	mov	Temp, w
	bank	plBank
	mov	plState, #plTxCompleteState		;New state = Wait for complete indication
	mov	w, Temp					;Recover data
	stz						;Indicate no more data to follow
	retp

;********************************************************************************
;  PAYLOAD LAYER - Send XID Frame
;********************************************************************************

;********** lap2plTxXIDCmd **********

lap2plTxXIDCmd
	bank	plBank
	mov	plXIDSlot, w				;Store slot number
	mov	plCommand, #uXIDCmd			;Command = XID command
	mov	w, #$FF
	mov	plDestAddr+0, w				;Dest address = FFFFFFFF
	mov	plDestAddr+1, w				;Dest address = FFFFFFFF
	mov	plDestAddr+2, w				;Dest address = FFFFFFFF
	mov	plDestAddr+3, w				;Dest address = FFFFFFFF
	mov	plXIDFlags, #2				;Set flags = 2 (=> 8 slots)
	mov	plFrameType, #uXIDCmdFrame		;Rember that this is a XID Command Frame
	mov	plTxPostCommand, #plTxXIDFormatState	;After address & command will send format
	jmp	plTxCmdStart				;Set State and Address, and ask framing layer to start frame

;********** lap2plTxXIDRsp **********

lap2plTxXIDRsp
	bank	plBank
	mov	plCommand, #uXIDRsp			;Command = XID response
	mov	plFrameType, #uXIDRspFrame		;Rember that this is a XID Response Frame
	mov	plTxPostCommand, #plTxXIDFormatState	;After address & command will send format
	jmp	plTxRspStart				;Set State and Address, and ask framing layer to start frame

;********** fl2plTxNext - TxXIDFormat State **********

plTxXIDFormat						;Send XID Format byte
	inc	plState					;Next will send source
	mov	w, #1					;Format = 1
	clz						;Indicate more data to follow
	retp						;Return data to framing layer

;********** fl2plTxNext - TxXIDSource State **********

plTxXIDSource	=	plTxSelfAddr

;********** fl2plTxNext - TxXIDDest State **********

plTxXIDDest	=	plTxDestAddr

;********** fl2plTxNext - TxXIDFlags State **********

plTxXIDFlags
	inc	plState					;After Flags will send slot number (plTxSlotState)
	mov	w, plXIDFlags				;Reply with same flags as received command frame
	clz						;Indicate more data to follow
	retp						;Return data to framing layer

;********** fl2plTxNext - TxXIDSlot State **********

plTxXIDSlot
	csne	plFrameType, #uXIDRspFrame		;Is the frame a XID response frame ?
	jmp	:Footer					;Yes => must send footer
	csne	plXIDSlot, #$FF				;Is the slot number FF ?
	jmp	:Footer					;Yes => must send footer
	mov	plState, #plTxXIDVersionState		;No => Send slot followed by version only
	jmp	:Send
:Footer	mov	plState, #plTxXIDFooterState
	clr	plPosition				;Set to 0 ready for footer
:Send	mov	w, plXIDSlot				;Transmit slot number
	clz						;Indicate more data to follow
	retp						;Return data to framing layer

;********** fl2plTxNext - TxXIDVersion State **********

plTxXIDVersion
	mov	plState, #plTxCompleteState		;After version will indicate complete
	mov	w, #0					;Version = 0
	stz						;Indicate complete
	retp						;Return data to framing layer

;********** fl2plTxNext - TxXIDFooter State **********

plTxXIDFooter
	mov	m, #_plXIDFooter / 256			;Pointer to string (high)
	mov	w, #_plXIDFooter			;Pointer to string
	jmp	plTxFooter

;********************************************************************************
;  PAYLOAD LAYER - Send UA Connection Frame
;********************************************************************************

lap2plSNRMAccept
	bank	plBank
	mov	plCommand, #uUARsp			;Send UA packet to accept connection
	mov	plConnAddr, plSNRMConnAddr		;Apply connection address
	setb	plConnAddr.0				;Only accept command frames
	mov	plTxPostCommand, #plTxUASourceState	;After address & command will send source
	jmp	plTxRspStart				;Set State and Address, and ask framing layer to start frame

plTxUASource	=	plTxSelfAddr

plTxUADest	=	plTxDestAddr

plTxUABaudRate						;Send $01, $01, BaudRate
	inc	plPosition
	csne	plPosition, #3				;Is position 3 indicating to send BaudRate ?
	jmp	:Baud					;Yes => send BaudRate
	mov	w, #$01					;Data to send = $01
	clz						;Indicate more data to follow
	retp						;Return data to framing layer
:Baud	inc	plState					;Next state = plTxUAParamState
	clr	plPosition				;Clear position ready for next state
	mov	w, plSNRMBaudRate			;Data to send = BaudRate
	clz						;Indicate more data to follow
	retp						;Return data to framing layer

plTxUAParam
	mov	m, #_plSNRMParam / 256			;Pointer to string (high)
	mov	w, #_plSNRMParam			;Pointer to string
	jmp	plTxFooter

;********************************************************************************
			ENDM

PayloadString1		MACRO
;********************************************************************************
;  PAYLOAD LAYER - String	;WARNING - Strings must not go over a 256 boundry !!!
;********************************************************************************

_plUCommands							;Must be in the same order as the FrameType constants !!!
_plUCommand6		dw	uUICmd				;UICmd or UIRsp (same command)
_plUCommand7		dw	uDISCCmd			;DISCCmd or RDRsp (same command)
_plUCommand8		dw	uUARsp				;UARsp
_plUCommand9		dw	uSNRMCmd			;SNRMCmd or RNRMRsp (same command)
_plUCommand10		dw	uTESTCmd			;TESTCmd or TESTRsp (same command)
_plUCommand11		dw	uFRMRRsp			;FRMRRsp
_plUCommand12		dw	uDMRsp				;DMRsp
_plUCommand13		dw	uXIDCmd				;XIDCmd
_plUCommand14		dw	uXIDRsp + $F00			;XIDRsp (F00 indicates end of string)

;********************************************************************************
			ENDM

PayloadString2		MACRO
;********************************************************************************
;  PAYLOAD LAYER - String	;WARNING - Strings must not go over a 256 boundry !!!
;********************************************************************************

;_plSNRMParam1		dw	$01, 1, %00000010		;Baud Rate       = 9600 bps	Flexible
_plSNRMParam
_plSNRMParam2		dw	$82, 1, %00000001		;Turnaround      = 500 ms	Solid
_plSNRMParam3		dw	$83, 1, %00000001		;Data Size       = 64 bytes	Flexible ?
_plSNRMParam4		dw	$84, 1, %00000001		;Window Size     = 1		Solid
_plSNRMParam5		dw	$85, 1, %10000000		;Additional BOFs = 0		Solid
_plSNRMParam6		dw	$86, 1, %00000011		;Min turnaround  = 5/10 ms	Solid to IrDA Transeiver spec
_plSNRMParam7		dw	$08, 1, %00000001+$F00		;Disconnect      = 3 s		Solid

;********************************************************************************
			ENDM

PayloadString3		MACRO
;********************************************************************************
;  PAYLOAD LAYER - String	;WARNING - Strings must not go over a 256 boundry !!!
;********************************************************************************

_plXIDFooter
_plXIDVersion		dw	0				;Version = 0 (only possible)
_plXIDHints		dw	$80, $04			;Hints   = IrComm
_plXIDCharset		dw	0				;Charset = ASCII
_plXIDNickname		dw	'SX IrComm Device'+$F00		;Nickname ($F00 indicates end)

;********************************************************************************
			ENDM
LapInfoSeg		MACRO
;********************************************************************************
;  LAP LAYER
;********************************************************************************
;
;Framing Layer Events
;
;	fl2lapMediaBusy()				;A byte has been received => the media is busy
;
;Payload Layer Events
;
;	pl2lapRxFrame(w=Type)				;Incomming frame of given type
;	pl2lapRxValid()					;Frame was valid
;	pl2lapRxError()					;Frame was invalid
;	pl2lapRxXIDData()				;XID data
;	pl2lapRxIData()					;I data
;	pl2lapRxUIData()				;UI data
;	lap2plRxIgnore()				;Tell the framing layer to ignore the frame
;
;	lap2plSNRMAccept()				;Accept connection and send reply
;	lap2plTxXIDCmd(w=Slot)				;Send a XID command frame
;	lap2plTxXIDRsp()				;Send a XID response frame
;	lap2plTxSimpleRsp()				;Send simple response frame
;	lap2plTxIRsp()					;Send an I frame
;	pl2lapTxIData(ret w=Data ret z=Last) call	;Request for data
;	pl2lapTxComplete()				;Complete indication
;
;	lap2plGenerateNewAddr				;Request that a new 32-bit address be generated
;
;LMP Layer Events
;
;	lap2lmpConnectIndication() call
;	lap2lmpDisconnectIndication()
;	lmp2lapDisconnectRequest()
;
;	lap2lmpRxData(w=Data)				;Incomming data bytes
;	lap2lmpRxValid() call				;Data bytes passed since RxFrame message are valid
;	lap2lmpRxError() call				;Data bytes passed since RxFrame message are invalid
;
;	lap2lmpTxFrame(ret z=None) call			;Lap layer can transmit a i-frame and will do so if z is returned false
;	lap2lmpTxData(ret w=Data ret z=Last) call	;Payload layer can accept a data byte (for an I frame) if there is one available. if there is data available then lmp returns data byte and sets z to false
;	lap2lmpTxValid() call				;Lap layer is indicating that all data passed since last TxStart message was acknowledged
;	lap2lmpTxError() call				;Lap layer is indicating that all data passed since last TxStart message will need to be sent again
;
;Application Events
;
;	app2lapDiscoveryRequest(ret z=Busy)		;Application wishes to initiate the XID discovery process
;	app2lapTxUIStart(ret z=Busy)			;Application wishes to send a UI command frame
;
;********************************************************************************
			ENDM


LapDataSeg		MACRO
;********************************************************************************
;  LAP LAYER
;********************************************************************************

		org	$70

lapBank		= 	$70				;8 bytes used

lapState	ds	1				;Current lap state
lapRxFrame	ds	1
lapRxData	ds	1
lapTxXIDSlot	ds	1

lapStatus	ds	1				;Status bits
lapRemoteBusy	=	lapStatus.0			;Remote busy flag
lapXIDDataFlag	=	lapStatus.1			;Indication that host has been informed that XID data will follow
lapRxUIDataFlag	=	lapStatus.2			;Indication that app layer has been informed that UI data will follow
lapTxUIDataFlag	=	lapStatus.3			;Indication that app layer has been informed that UI data will follow
lapLmpRxFlag	=	lapStatus.4			;Indication that lmp layer has sent data that has not been acknowledged
lapLmpTxFlag	=	lapStatus.5			;Indication that lmp layer has sent data that has not been acknowledged
lapMediaIdle	=	lapStatus.6			;Indication that the media has not been used in the past 500ms (NDM state only)

lapRxNs		ds	1				;%.....nnn = expected next I-frame sequence number (Ns)
lapRxNrAck	ds	1				;%.....nnn = expected next I-response sequence number if last frame that was transmitted has been acknowledged
lapRxNrNotAck	ds	1				;%.....nnn = expected next I-response sequence number if last frame that was transmitted has been not-acknowledged

lapNDMState		= 0				;NDM state
lapQUERYState		= 1				;QUERY state
lapNDM2NRMState		= 2				;internal state to wait for TxComplete so new connection parameters can be applied
lapNRMState		= 3				;NRM state
lapSCLOSEState		= 4				;SCLOSE state
lapSCLOSE2NDMState	= 5				;internal state to wait for TxComplete so default connection parameters can be applied

lapMaxFrameSize		= 64				;Max frame size = 64 bytes
lapMinTurnaround	= 116				;Number of additional BOFs to send @ 115200bps (116 = 10ms, 58 = 5ms)

Timer140ms		= -1				;1  =  1*256*256*108*(1/50MHz) =  141.56ms
Timer570ms		= -4				;4  =  4*256*256*108*(1/50MHz) =  566.23ms
Timer1000ms		= -7				;7  =  7*256*256*108*(1/50MHz) =  990.90ms
Timer3000ms		= -21				;21 = 21*256*256*108*(1/50MHz) = 2972.72ms
							;Note - For a different clock frequency the 108 ISR constant changes => these timeout numbers remain the same

;********************************************************************************
			ENDM


LapCodeSeg		MACRO
;********************************************************************************
;  LAP LAYER
;********************************************************************************

;********** a2lapReset **********

a2lapReset
	call	@lap2plGenerateNewAddr			;Generate new device address
	bank	lapBank
	mov	lapState, #lapNDMState			;Enter NDM state
	clr	lapStatus				;Init status
	jmp	lapMediaBusy				;Reset media idle detection (lapMediaBusy will issue retp instruction)

;********** a2lapTimer **********

a2lapTimer
	clrb	TimerOverflow				;Clear Timer flag
	bank	lapBank
	mov	w, lapState				;jump based on state
	jmp	PC+w
	jmp	lapNDMTimer				; 0 = lapNDMState
	jmp	lapQUERYTimer				; 1 = lapQUERYState
	retp						; 2 = lapNDM2NRMState
	jmp	lapNRMTimer				; 3 = lapNRMState
	jmp	lapSCLOSETimer				; 4 = lapSCLOSEState
	retp						; 5 = lapSCLOSE2NDMState

;********** pl2lapRxFrame **********

pl2lapRxFrame
	bank	lapBank
	mov	lapRxFrame, w				;Store frame type
	mov	w, lapState				;Jump based on state
	jmp	PC+w
	jmp	lapNDMRxFrame				; 0 = lapNDMState
	jmp	lapQUERYRxFrame				; 1 = lapQUERYState
	retp						; 2 = lapNDM2NRMState (RxFrame = impossable in this state)
	jmp	lapNRMRxFrame				; 3 = lapNRMState
	jmp	lapSCLOSERxFrame			; 4 = lapSCLOSEState
	retp						; 5 = lapSCLOSE2NDMState (RxFrame = impossable in this state)

;********** pl2lapRxValid **********

pl2lapRxValid
	bank	lapBank
	mov	w, lapState				;Jump based on state
	jmp	PC+w
	jmp	lapNDMRxValid				; 0 = lapNDMState
	jmp	lapQUERYRxValid				; 1 = lapQUERYState
	retp						; 2 = lapNDM2NRMState (RxValid is impossable in this state)
	jmp	lapNRMRxValid				; 3 = lapNRMState
	jmp	lapSCLOSERxValid			; 4 = lapSCLOSEState
	retp						; 5 = lapSCLOSE2NDMState (RxValid is impossable in this state)

;********** pl2lapRxValid - NRM State **********

lapNRMRxValid
	mov	w, lapRxFrame				;Jump based on frame type
	jmp	PC+w
	jmp	lapNRMXCmdValid				;xFrame		=	0
	jmp	lapNRMIValid				;iFrame		=	1
	jmp	lapNRMRRValid				;sRRFrame	=	2
	jmp	lapNRMRNRValid				;sRNRFrame	=	3
	jmp	lapNRMREJValid				;sREJFrame	=	4
	jmp	lapNRMSREJValid				;sSREJFrame	=	5
	jmp	lapNRMXCmdValid				;uUIFrame	=	6	;UICmd or UIRsp (same command)
	jmp	lapNRMDISCValid				;uDISCFrame	=	7	;DISCCmd or RDRsp (same command)
	jmp	lapNRMXCmdValid				;uUARspFrame	=	8	;UARsp
	jmp	lapNRMNRMValid				;uNRMFrame	=	9	;SNRMCmd or RNRMRsp (same command)
	jmp	lapNRMXCmdValid				;uTESTFrame	=	10	;TESTCmd or TESTRsp (same command)
	jmp	lapNRMXCmdValid				;uFRMRRspFrame	=	11	;FRMRRsp
	jmp	lapNRMXCmdValid				;uDMRspFrame	=	12	;DMRsp
	jmp	lapNRMXCmdValid				;uXIDCmdFrame	=	13	;XIDCmd
	jmp	lapNRMXCmdValid				;uXIDRspFrame	=	14	;XIDRsp

;********** pl2lapTxValid **********

pl2lapTxComplete
	bank	lapBank
	mov	w, lapState				;Jump based on state
	jmp	PC+w
	jmp	lapNDMTxComplete			; 0 = lapNDMState        (not interesting in TxComplete)
	retp						; 1 = lapQUERYState      (not interesting in TxComplete)
	jmp	lapNDM2NRMTxComplete			; 2 = lapNDM2NRMState    (now can apply connection parameters)
	retp						; 3 = lapNRMState        (not interesting in TxComplete)
	retp						; 4 = lapSCLOSEState     (not interesting in TxComplete)
	jmp	lapSCLOSE2NDMTxComplete			; 5 = lapSCLOSE2NDMState (now can apply defaultconnection parameters)

;********** fl2lapMediaBusy **********

fl2lapMediaBusy
	bank	lapBank
	cse	lapState, #lapNDMState			;NDM state ?
	retp						;No => ignore
	clrb	lapMediaIdle				;Clear MediaIdle flag
	test	lapRxFrame				;Is a frame being received ?
	sz
	retp						;Yes => do not reset timer
	mov	w, #Timer570ms				;No  => Reset timer to 500ms
	jmp	lapSetTimer				;Apply timer to wait for media idle

;********** DiscoveryRequest **********

app2lapDiscoveryRequest
	bank	lapBank
	cse	lapState, #lapNDMState			;NDM state ?
	clrb	lapMediaIdle				;No  => same as MediaIdle being false
	stz						;Indicate busy
	sb	lapMediaIdle				;Is the media idle ?
	retp						;No  => return busy indication
	bank	plBank
	mov	plConnAddr, #$FE			;Accept broadcast replys only
	bank	lapBank
	clr	lapTxXIDSlot				;Start at slot # 0
	mov	lapState, #lapQUERYState		;Enter QUERY state
	call	:Send					;Send first frame
	clz						;Indicate request was accepted
	retp
:Send	jmp	lapQUERYTimer

;********** DiscoveryRequest **********

app2lapTxUIStart
	bank	lapBank
	cse	lapState, #lapNDMState			;NDM state ?
	clrb	lapMediaIdle				;No  => same as MediaIdle being false
	stz						;Indicate busy
	sb	lapMediaIdle				;Is the media idle ?
	retp						;No  => return busy indication
	clrb	lapMediaIdle				;Remember that another frame cannot be sent
	setb	lapRxUIDataFlag				;Flag to pass messages to app layer
	call	@lap2plTxUICmd				;Request that the payload layer send a UI command frame
	clz						;Indicate request was accepted
	retp

;********************************************************************************
;  LAP LAYER - Internal Subroutines
;********************************************************************************

lapRandomFlags	=	Temp+0
lapRandomMask	=	Temp+1

;Slot bits: %00 =>  1 slot  => Mask = %0000 = 0 -> 0
;           %01 =>  6 slots => Mask = %0011 = 0 -> 3 (ie can't result in 4 or 5)
;           %10 =>  8 slots => Mask = %0111 = 0 -> 7
;           %11 => 16 slots => Mask = %1111 = 0 -> 15

lapRandomSlot						;returns Slot number to transmit in
	bank	plBank					;Peek at frame info
	mov	w, plXIDFlags				;get discovery flags
	bank	lapBank
	and	w, #%00000011				;Mask out non Slot bits
	snz						;Slot bits = 0 ?
	retp						;Yes => return 0
	mov	lapRandomFlags, w			;Store into Flags register
	mov	w, #%00000001				;If bit 1 = 0 then w = 0001
	snb	lapRandomFlags.1
	mov	w, #%00000111				;If bit 1 = 1 then w = 0111
	mov	lapRandomMask, w			;Mask = 0001 or 0111
	stc
	snb	lapRandomFlags.0			;If bit 0 = 1 then rotate left with carry set
	rl	lapRandomMask				;Rotate mask with carry set
	bank	TimerBank
	mov	w, Random				;random number (non resetable, increments every timer interrupt)
	bank	lapBank					;Note: The code is synchronous with RTCC and so RTCC is not a random number
	and	w, lapRandomMask			;Mask out unwanted bits
	mov	lapTxXIDSlot, w				;Store slot number
	retp

;********** SetTimer **********

lapSetTimer						;w = negative number to count up from
	bank	TimerBank				;-1 = 141.56ms
	clr	Timer1
	clr	Timer2
	mov	Timer3, w
	clrb	TimerOverflow
	bank	lapBank
	retp

;********** fl2lapMediaBusy **********

lapMediaBusy
	clr	lapRxFrame				;Reset frame type to none
	mov	w, #Timer570ms				;No  => Reset timer to 500ms
	jmp	lapSetTimer				;Apply timer to wait for media idle

;********************************************************************************
;  LAP LAYER
;********************************************************************************

;********** pl2lapRxError **********

pl2lapRxError
	bank	lapBank
	call	lapMediaBusy				;Reset media idle detection
	snb	laplmpRxFlag				;Has the lmp layer been receiving data ?
	jmp	:LMP					;Yes => must inform lmp layer
	snb	lapXIDDataFlag				;Has the host been informed to expect XID data ?
	jmp	:XID					;Yes => inform of error
	sb	lapRxUIDataFlag				;Is the app layer expecting data
	retp						;No  => return
:UI	clrb	lapRxUIDataFlag				;Yes => Inform app layer that UI frame is invalid
	jmp	@lap2appRxUIError
:LMP	clrb	laplmpRxFlag				;Clear flag
	jmp	@lap2lmpRxError				;Inform lmp layer of error (lmp layer will issue ret instruction)
:XID	clrb	lapXIDDataFlag				;Clear flag
	debugl	ShowXIDInfo, '}'			;Inform host of error
	retp


;********** pl2lapRxXIDData **********

pl2lapRxXIDData
	bank	lapBank
	sb	lapXIDDataFlag				;Is the host expecting XID Data ?
	retp						;No  => ignore data
	debug	ShowXIDInfo				;Yes => pass data
	retp

;********** pl2lapRxIData **********

pl2lapRxIData
	bank	lapBank
	sb	laplmpRxFlag				;Should we pass data ?
	retp						;No  => ignore data
	jmp	@lap2lmpRxData				;Yes => pass data

;********** pl2lapTxIData **********

pl2lapTxIData
	jmp	@lap2lmpTxData				;Get data from lmp layer

;********** pl2lapRxUIData **********

pl2lapRxUIData
	bank	lapBank
	sb	lapRxUIDataFlag				;Should we pass data ?
	retp						;No  => ignore data
	jmp	@lap2appRxUIData			;Yes => pass data

;********** pl2lapTxUIData **********

pl2lapTxUIData
	jmp	@lap2appTxUIData			;Get data from app layer

;********************************************************************************
;  LAP LAYER - NDM Events
;********************************************************************************

lapEnterNDMState					;Reset connection parameters
	mov	lapState, #lapNDMState			;Enter NDM state
	call	lapMediaBusy				;Reset media idle detection
:Tx	sb	laplmpTxFlag				;Is the lmp data waiting for comformation of data ?
	jmp	:Rx					;No  => contiue without message to lmp layer
	clrb	laplmpTxFlag				;Yes => inform lap layer that data was not-acknowledged and contiue
	call	@lap2lmpTxError
	bank	lapBank
:Rx	sb	lapLmpRxFlag				;Is the lmp layer expecting data ?
	jmp	:Cont					;No  => contiue without message to lmp layer
	clrb	lapLmpRxFlag				;Yes => must inform lmp layer that data is invalid
	call	@lap2lmpRxError
:Cont	bank	plBank
	mov	plConnAddr, #$FF			;Not connected => set ConnAddr to only accept be $FF
	bank	flBank
	mov	flFFCount, #10				;Default to 10 FFs @ 9600 = 10.42ms
	bank	IsrBank
	mov	IrdaSpeed, #Irda9600			;IrDA UART speed = 9600
	clrb	ledCON					;Turn off Connect LED
	debugl	ShowConnect, ']'
	jmp	@lap2lmpDisconnectIndication		;Inform lmp layer of disconnection

;********** NDM - RxFrame **********

lapNDMRxFrame
	csne	lapRxFrame, #uXIDCmdFrame		;XID Command frame ?
	jmp	:Accept					;Yes => Accept frame (may want to code to inform host of incommming XIDCmd frame ?)
	csne	lapRxFrame, #uNRMFrame			;SNRM Command frame ?
	jmp	:Accept					;Yes => Accept frame
	csne	lapRxFrame, #uUIFrame			;UI frame ?
	jmp	:UI					;Yes => Accept frame
	clr	lapRxFrame				;No  => Ignore frame
	jmp	@lap2plRxIgnore				;Request that the payload layer ignores the frame
:UI	setb	lapRxUIDataFlag				;Flag to pass data to app layer
:Accept	mov	w, #Timer570ms				;500ms Timeout
	jmp	lapSetTimer				;(lapSetTimer will issue retp instruction)

;********** NDM - Timer **********

lapNDMTimer
	test	lapRxFrame				;Was a frame being received ?
	jnz	pl2lapRxError				;Yes => treat as error, pl2lapRxError will reset the MediaBusy detection
	setb	lapMediaIdle				;No  => media must be idle
	retp

;********** NDM - RxValid **********

lapNDMRxValid
	csne	lapRxFrame, #uXIDCmdFrame		;XID Command frame ?
	jmp	:XID					;Yes => process
	csne	lapRxFrame, #uNRMFrame			;SNRM Command frame ?
	jmp	:SNRM					;Yes => process
							;No  => must be UI frame
:UI	call	lapMediaBusy				;Reset media idle detection
	sb	lapRxUIDataFlag				;Is the app layer expecting data
	retp						;No =>  ignore
	clrb	lapRxUIDataFlag				;Yes => Inform app layer that UI frame is complete
	jmp	@lap2appRxUIValid

:XID	call	lapMediaBusy				;Reset media idle detection
	bank	plBank					;Peek at frame info
	snb	plXIDFlags.2				;Is the "Generate new device address" flag set ?
	call	@lap2plGenerateNewAddr			;Yes => ask payload layer to generate a new 32-bit address
	bank	plBank					;Peek at frame info
	test	plXIDSlot				;is the slot number = 0 ?
	bank	lapBank
	snz
	call	lapRandomSlot				;Yes => generate random slot (slot returned in lapTxXIDSlot)
	mov	w, lapTxXIDSlot				;Get the slot number to transmit in
	bank	plBank
	mov	w, plXIDSlot-w				;Subtract (ie compare) with current slot number
	sz						;Are they the same ? (ie this slot to transmit in ?)
	retp						;No  => return
	bank	lapBank
	mov	w, lapTxXIDSlot
	clr	lapTxXIDSlot				;Reset slot number to indicate that a reply has been sent
	jmp	@lap2plTxXIDRsp				;Transmit response

:SNRM	mov	lapState, #lapNDM2NRMState		;Next state wil be NDM2NRM state to apply connection parameters after this reply has been sent
	clrb	lapRemoteBusy				;Initilise RemoteBusy flag to false
	clr	lapRxNs					;Initilise RxNs to 0
	clr	lapRxNrAck				;Initilise RxNrAck to zero
	clr	lapRxNrNotAck				;Initilise RxNrNotAck to zero
	mov	w, #Timer1000ms				;1s timeout IrDA Lite p15)
	call	lapSetTimer
	setb	ledCON					;Turn on Connect LED
	debugl	ShowConnect, '['
	call	@lap2lmpConnectIndication		;Inform lmp layer of connection
	jmp	@lap2plSNRMAccept			;Send reply

;********** NDM - TxComplete **********

lapNDMTxComplete
	call	lapMediaBusy				;Reset media idle test
	sb	lapRxUIDataFlag				;Is the app layer expecting data
	retp						;No =>  ignore
	clrb	lapRxUIDataFlag				;Yes => Inform app layer that UI frame is complete
	jmp	@lap2appTxUIComplete

;********************************************************************************
;  LAP LAYER - QUERY Events
;********************************************************************************

;********** QUERY - RxFrame **********

lapQUERYRxFrame
	cse	lapRxFrame, #uXIDRspFrame		;XID Response frame ?
	jmp	@lap2plRxIgnore				;No  => Ignore frame
	setb	lapXIDDataFlag				;Yes => Accept frame. Remember that currently passing data to host
	debugl	ShowXIDInfo, '{'			;Show XID info start
	retp

;********** QUERY - RxValid **********

lapQUERYRxValid
	sb	lapXIDDataFlag				;Is the host expecting data
	retp						;No =>  ignore
	clrb	lapXIDDataFlag				;Yes => Inform host that XID frame is complete
	debugl	ShowXIDInfo, '}'
	retp

;********** QUERY - Timer **********

lapQUERYTimer
	bank	TimerBank				;Set global timer
	clr	Timer1					;80ms timeout after transmission is complete (75-85ms IrDA Lite p21)
	mov	Timer2, #-198				;80ms timeout + 29.2 ms (28 bytes) to transmit = 109.2ms. 198 : 198*256*108*(1/50MHz) = 109.49ms
	mov	Timer3, #-1				;negitive number
	clrb	TimerOverflow
	bank	lapBank
	sb	lapXIDDataFlag				;Has the host been informed to expect XID data ?
	jmp	:Good					;Yes => inform of error
	clrb	lapXIDDataFlag				;Clear flag
	debugl	ShowXIDInfo, '}'			;Inform host of error
:Good	cse	lapTxXIDSlot, #08			;Last slot ?
	jmp	:Send					;No  => send
	mov	lapState, #lapNDMState			;Yes => After send will return to NDM state
	mov	w, #$FF					;w = FF
	mov	lapTxXIDSlot, w				;set slot to $FF to indicate complete
	bank	plBank
	mov	plConnAddr, w				;ConnAddr = FF => Accept broadcast commands only
	bank	lapBank
:Send	mov	w, lapTxXIDSlot				;Get current slot #
	inc	lapTxXIDSlot				;Increment for nexty slot #
	jmp	@lap2plTxXIDCmd				;Send XID command frame (payload layer will return)

;********************************************************************************
;  LAP LAYER - NRM Events
;********************************************************************************

;********** NDM2NRM - TxComplete **********

lapNDM2NRMTxComplete
	mov	lapState, #lapNRMState			;NRM state
	bank	plBank					;Agreed BaudRate is the most significant bit that is set in plSNRMBaudRate
	mov	w, #Irda9600				;Min = 9600
	snb	plSNRMBaudRate.2			;19200 ?
	mov	w, #Irda19200				;Yes => w = 19200
	snb	plSNRMBaudRate.3			;38400 ?
	mov	w, #Irda38400				;Yes => w = 38400
	snb	plSNRMBaudRate.4			;57600 ?
	mov	w, #Irda57600				;Yes => w = 57600
	snb	plSNRMBaudRate.5			;115200 ?
	mov	w, #Irda115200				;Yes => w = 115200
	bank	IsrBank
	mov	IrdaSpeed, w				;Apply baud rate
	bank	plBank					;Set FF Count to ensure 10ms. FFCount = BaudRate / 10 * 0.01s
	mov	w, #lapMinTurnaround / 11.6		;Min = 9600 => 10ms = 10 bytes
	snb	plSNRMBaudRate.2			;19200 ?
	mov	w, #lapMinTurnaround / 5.8		;Yes => 10ms = 20 bytes
	snb	plSNRMBaudRate.3			;38400 ?
	mov	w, #lapMinTurnaround / 2.9		;Yes => 10ms = 39 bytes
	snb	plSNRMBaudRate.4			;57600 ?
	mov	w, #lapMinTurnaround / 2		;Yes => 10ms = 58 bytes
	snb	plSNRMBaudRate.5			;115200 ?
	mov	w, #lapMinTurnaround			;Yes => 10ms = 116 bytes
	bank	flBank
	mov	flFFCount, w				;Apply FFCount
	retp

;********** NRM - SendResponse **********

lapSendNRMResponse
	snb	lapRemoteBusy				;Is the remote busy flag set ?
	jmp	lapSendSResponse			;Yes => send S-Response
	call	@lap2lmpTxFrame				;Returns z = false if data to be sent
	bank	lapBank
	snz						;Is there data to be sent ?
	jmp	lapSendSResponse			;No  => send S-Response
:Data	setb	laplmpTxFlag				;Yes => Rember that lmp layer is passing data
	mov	w, <<lapRxNs				;Send Nr = RxNs. w = RxNs %....nnn.
	and	w, #%00001110				;mask out non Ns bits
	mov	Temp, w					;Store in Temp
	swap	Temp					;Temp = RxNs %nnn.....
	setb	Temp.4					;Set bit 4 = final flag
	mov	w, <<lapRxNrAck				;Send Ns = RxNrAck. w = RxNrAck %....nnn.
	and	w, #%00001110				;mask out non Ns bits
	add	w, Temp					;Add Nr bits
	inc	lapRxNrAck				;add 1 to NrAck - the expect acknowledge
	jmp	@lap2plTxIRsp				;Transmit I frame
	
lapSendSResponse
	mov	w, <<lapRxNs				;Send Nr = RxNs. w = RxNs %....nnn.
	and	w, #%00001110				;mask out non Ns bits
	mov	Temp, w					;Store in Temp
	swap	Temp					;Temp = RxNs %nnn.....
	mov	w, #sRR					;frame will be of type RR
	add	w, Temp					;Set Nr of frame to RxNs = expected next I frame
	jmp	@lap2plTxSimpleRsp			;Send simple response frame

;********** NRM - SendRD **********

lapNRMSendRD
	mov	w, #Timer3000ms
	call	lapSetTimer				;Reset timer for SCLOSE state
	sb	lapLmpRxFlag				;Is the lmp layer expecting data ? (ie error caused by timeout)
	jmp	:Cont					;No  => contiue
	clrb	lapLmpRxFlag				;Yes => must inform lmp layer that data is invalid
	call	@lap2lmpRxError				;
	bank	lapBank
:Cont	mov	lapState, #lapSCLOSEState		;change to SCLOSE state
	mov	w, #uRDRsp				;frame will be of type RD
	jmp	@lap2plTxSimpleRsp			;Send simple response frame

;********** NRM - RxFrame **********

lapNRMRxFrame
	csne	lapRxFrame, #iFrame			;I Data frame ?
	setb	lapLmpRxFlag				;Yes => Flag to pass data to lmp layer
	retp						;Accept all frames

;********** NRM - SValid or IValid **********

lapNRMSIValid
	mov	w, #Timer3000ms
	call	lapSetTimer				;Reset timer on any S-Command
	bank	plBank
	mov	w, >>plCommand				;w = %.nnn.... get the received command byte (shifted)
	mov	Temp, w					;Temp = received Nr bits (%.nnn....)
	swap	Temp					;Temp = received Nr bits (%.....nnn)
	bank	lapBank
	mov	w, lapRxNrAck				;w = expected Nr if Ack
	xor	w, Temp					;compare received Nr with NrAck
	and	w, #%00000111				;only examine lowest bits
	snz						;Does Nr = NrAck (ie is this a valid ack) ?
	jmp	:Ack					;Yes => valid Ack
	mov	w, lapRxNrNotAck			;w = expected Nr if Not-Ack
	xor	w, Temp					;compare received Nr with NrNotAck
	and	w, #%00000111				;only examine lostest bits
	sz						;Does Nr = NrNotAck (ie is this a valid not-ack) ?
	jmp	lapNRMSendRD				;No  => Fatal Error - invalid Nr => must disconnect (Valid/Error message for LMP layer willbe sent prior to the DisconnectIndication)
:NotAck	dec	lapRxNrAck				;return NrAck back to what it was before transmission of the last I-Frame
	sb	laplmpTxFlag				;Is the lmp data waiting for comformation of data ?
	jmp	:Cont					;No  => contiue without message to lmp layer
	clrb	laplmpTxFlag				;Yes => inform lap layer that data was not-acknowledged and contiue
	call	@lap2lmpTxError
	jmp	:Cont
:Ack	mov	lapRxNrNotAck, lapRxNrAck		;Set NrNotAck to match NrAck
	sb	laplmpTxFlag				;Is the lmp data waiting for comformation of data ?
	jmp	:Cont					;No  => contiue without message to lmp layer
	clrb	laplmpTxFlag				;Yes => inform lap layer that data was acknowledged and contiue
	call	@lap2lmpTxValid
:Cont	bank	lapBank
	cse	lapRxFrame, #iFrame			;Is this an i frame ?
	jmp	lapSendNRMResponse			;No  => S frame => Send-NRM-Response
	bank	plBank					;Yes => must test Ns
	mov	w, >>plCommand				;get the received command byte (shifted right 1 bit)
	bank	lapBank
	xor	w, lapRxNs				;Compare with expected Ns
	and	w, #%00000111				;Only test lowest 3 bits
	jnz	:Ignore					;If Ns <> expected then ignore
:Valid	inc	lapRxNs					;increment RxNs
	sb	lapLmpRxFlag				;Is the lmp layer expecting data ?
	jmp	lapSendNRMResponse			;No  => send NRM-response
	clrb	lapLmpRxFlag				;Yes => must inform lmp layer that data is complete
	call	@lap2lmpRxValid				;Indicate data complete and valid
	bank	lapBank
	jmp	lapSendNRMResponse			;send NRM-response
:Ignore	sb	lapLmpRxFlag				;Is the lmp layer expecting data ?
	jmp	lapSendSResponse			;No  => send S-response
	clrb	lapLmpRxFlag				;Yes => must inform lmp layer that data is invalid
	call	@lap2lmpRxError				;
	bank	lapBank
	jmp	lapSendSResponse			;send S-response

lapNRMIValid	=	lapNRMSIValid			;A I frame has been received

lapNRMRRValid						;A RR frame has been received
	clrb	lapRemoteBusy				;Remember that remote is not busy and send reply
	jmp	lapNRMSIValid

lapNRMRNRValid						;A RNR frame has been received
	setb	lapRemoteBusy				;Remember that remote is busy and send reply
	jmp	lapNRMSIValid

lapNRMREJValid	=	lapNRMSIValid		;A REJ frame has been received
lapNRMSREJValid	=	lapNRMSIValid		;A SREJ frame has been received

;********** NRM - SNRMCmdValid **********

lapNRMNRMValid	=	lapNRMSendRD

;********** NRM - XCmdValid **********

lapNRMXCmdValid	=	lapSendSResponse

;********** NRM - DISCCmdValid **********

lapNRMDISCValid						;Disconnect command: ack and apply default parameters.
	mov	lapState, #lapSCLOSE2NDMState		;Next state = transition to apply origional connection parameters once this frame has been sent
	mov	w, #uUARsp				;Send UA frame to acknowledge disconnect
	jmp	@lap2plTxSimpleRsp			;Send simple response frame

;********** NRM - Timer **********

lapNRMTimer	=	lapEnterNDMState		;Timeout => return to NDM state.

;********** lmp2lapDisconnectRequestr **********

lmp2lapDisconnectRequest
	bank	lapBank
	cse	lapState, #lapNRMState			;Currenly in NRM state ?
	retp						;No  => ignore request
	mov	lapState, #lapSCLOSEState		;Yes => change to SCLOSE state
	retp

;********************************************************************************
;  LAP LAYER - NRM Events
;********************************************************************************

;********** SCLOSE - RxFrame **********

lapSCLOSERxFrame
	retp						;Accept all frames

;********** SCLOSE - RxValid **********

lapSCLOSERxValid
	csne	lapRxFrame, #uDISCFrame			;DISC Command frame ?
	jmp	lapNRMDISCValid				;Yes => Send ack, apply default parameters and enter NDM state
	mov	w, #Timer3000ms
	call	lapSetTimer				;No, however still must be a command frame (due to ConnAddr) => send RD frame
	mov	w, #uRDRsp				;Send RD Response frame to request disconnect
	jmp	@lap2plTxSimpleRsp			;Send simple response frame

;********** SCLOSE - Timer **********

lapSCLOSETimer		=	lapEnterNDMState

;********** SCLOSE2NDM - TxComplete **********

lapSCLOSE2NDMTxComplete	=	lapEnterNDMState

;********************************************************************************
		ENDM

LmpInfoSeg		MACRO
;********************************************************************************
;  LMP LAYER
;********************************************************************************
;
;	lap2lmpConnectIndication() call
;	lap2lmpDisconnectIndication()
;
;	lap2lmpRxData(w=Data)				;Incomming data bytes
;	lap2lmpRxValid() call				;Data bytes passed since RxFrame message are valid
;	lap2lmpRxError() call				;Data bytes passed since RxFrame message are invalid
;
;	lap2lmpTxFrame(ret z=None) call
;	lap2lmpTxData(ret w=Data ret z=Last) call	;Payload layer can accept a data byte (for an I frame) if there is one available. if there is data available then lmp returns data byte and sets z to false
;	lap2lmpTxValid() call				;Lap layer is indicating that all data passed since last TxStart message was acknowledged
;	lap2lmpTxError() call				;Lap layer is indicating that all data passed since last TxStart message will need to be sent again
;
;********************************************************************************
			ENDM


LmpDataSeg		MACRO
;********************************************************************************
;  LMP LAYER
;********************************************************************************

		org	$90

lmpBank		= 	$90			;16 bytes

lmpPosition	ds	1			;Position of multi byte stages
lmpData		ds	1			;Temporary Data storage
lmpAppLSAP	ds	1			;LSAP number of remote CommApp (or 0 if not connected)
lmpAppStatus	ds	1

lmpRxState	ds	1			;Current Rx state
lmpRxDLSAP	ds	1			;Received DLSAP
lmpRxSLSAP	ds	1			;Received SLSAP
lmpRxInfo	ds	4

lmpRxLMPCmdOpcode	=	lmpRxInfo + 0	;LMP Command frames : holds opcode
lmpRxIASErrOpcode	=	lmpRxInfo + 0	;IAS frame : holds service request
lmpRxIASErrRetCode	=	lmpRxInfo + 1	;IAS frame : holds return code for service request
lmpRxSendStringL	=	lmpRxInfo + 2	;SendStringH = _lmpTxStringSegment
lmpRxPostTest		=	lmpRxInfo + 3

lmpTxState	ds	1			;Current Tx state
lmpTxDLSAP	ds	1			;Transmit DLSAP = Received SLSAP
lmpTxSLSAP	ds	1			;Transmit SLSAP = Received DLSAP
lmpTxInfo	ds	2

lmpTxIASErrOpcode	=	lmpTxInfo + 0	;IAS frame : holds service request
lmpTxIASErrRetCode	=	lmpTxInfo + 1	;IAS frame : holds return code for service request
lmpTxStringH		=	lmpTxInfo + 0
lmpTxStringL		=	lmpTxInfo + 1

lmpConnectCmdOpcode		= $01
lmpConnectRspOpcode		= $81
lmpDisconnectOpcode		= $02
lmpAccessCmdOpcode		= $03
lmpAccessRspOpcode		= $83

lmpLSAPServer			= 0
lmpLSAPComm			= 5			;Random number between 1 and 6F

lmpAppRxFlag			= lmpAppStatus.0	;Indicates that app layer has been passed unacknoldged data
lmpAppTxFlag			= lmpAppStatus.1	;Indicates that app layer is passing data or has passed data that has not yet been acknoldged

lmpRxDataMode			= %00000000		;More data is required
lmpRxVerifyMode			= %10000000		;Waiting for frame to complete

lmpRxSLSAPState			= 1 + lmpRxDataMode	;Second byte = Source LSAP
lmpRxLMPCmdOpcodeState		= 2 + lmpRxDataMode	;LMP Command : Opcode
lmpRxIASCmdState		= 3 + lmpRxDataMode	;IAS Data :
lmpRxIASClassLengthState	= 4 + lmpRxDataMode	;IAS Data :
lmpRxIASClassTestState		= 5 + lmpRxDataMode	;IAS Data :
lmpRxIASDeviceAttribState	= 6 + lmpRxDataMode	;IAS Data :
lmpRxIASCommAttribState		= 7 + lmpRxDataMode	;IAS Data :
lmpRxIASAttribTestState		= 8 + lmpRxDataMode	;IAS Data :
lmpRxCommDataState		= 9 + lmpRxDataMode	;Comm Data

lmpRxBadLSAPState		= 1 + lmpRxVerifyMode	;Error state : Invalid Dest LSAP
lmpRxLMPCmdVerifyState		= 2 + lmpRxVerifyMode	;LMP Command : Verify
lmpRxIASAttribVerifyState	= 3 + lmpRxVerifyMode	;IAS Data :
lmpRxIASErrorState		= 4 + lmpRxVerifyMode	;IAS Data :

lmpTxStringState		= 1			;Send a string
lmpTxIASErrorState		= 2			;Reply stating that the IAS service is an un-supported option or error
lmpTxCommDataState		= 3			;Sending Comm Data

;********************************************************************************
			ENDM


LmpCodeSeg		MACRO
;********************************************************************************
;  LMP LAYER
;********************************************************************************

;********** a2lmpReset **********

a2lmpReset
	bank	lmpBank
	clr	lmpRxState
	clr	lmpTxState
	clr	lmpAppLSAP
	retp

;********** lap2lmpConnectIndication **********

lap2lmpConnectIndication	=	a2lmpReset

;********** lap2lmpDisconnectIndication **********

lap2lmpDisconnectIndication	=	a2lmpReset

;********** lap2lmpRxData **********

lap2lmpRxData
	bank	lmpBank
	mov	lmpData, w				;Store data
	snb	lmpRxState.7				;Interested in data ? (lmpRxDataMode)
	retp
	mov	w, lmpRxState				;Jump based on state
	jmp	PC+w
	jmp	lmpRxDLSAPByte				;  0 = lmpIdleState
	jmp	lmpRxSLSAPByte				;  1 = lmpRxSLSAPState
	jmp	lmpRxCmdOpcodeByte			;  2 = lmpRxLMPCmdOpcodeState
	jmp	lmpRxIASCmd				;  3 = lmpRxIASCmdState
	jmp	lmpRxIASClassLength			;  4 = lmpRxIASClassLengthState
	jmp	lmpRxIASStringTest			;  5 = lmpRxIASClassTestState
	jmp	lmpRxIASDeviceAttrib			;  6 = lmpRxIASDeviceAttribState
	jmp	lmpRxIASCommAttrib			;  7 = lmpRxIASCommAttribState
	jmp	lmpRxIASStringTest			;  8 = lmpRxIASAttribTestState
	jmp	lmpRxCommData				;  9 = lmpRxCommDataState

;********** lap2lmpRxValid **********

lap2lmpRxValid
	debugl	IFrameDataRx, '^'
	bank	lmpBank
	snb	lmpAppRxFlag				;CommData ?
	jmp	lmpRxValidCommData			;Yes => process
	sb	lmpRxState.7				;Interested in valid ? (lmpRxVerifyMode)
	retp
	mov	w, lmpRxState				;Jump based on state
	and	w, #%01111111				;Remove Mode bit
	clr	lmpRxState				;Clear RxState back to idle
	jmp	PC+w
	retp						;  0 = lmpIdleState (invalid)
	jmp	lmpRxBadLSAP				;  1 = lmpRxBadLSAPState
	jmp	lmpRxValidLMPCommand			;  2 = lmpRxLMPCmdVerifyState
	jmp	lmpRxValidIASAttribVerify		;  3 = lmpRxIASAttribVerifyState
	jmp	lmpRxValidIASError			;  4 = lmpRxIASErrorState

;********** lap2lmpRxInvalid **********

lap2lmpRxError
	debugl	IFrameDataRx, '!'
	setb	ledERR					;Turn ERR led on
	bank	lmpBank
	clr	lmpRxState				;Return to idle state
	sb	lmpAppRxFlag				;CommDataMode ?
	retp						;No  => return
	clrb	lmpAppRxFlag				;Clear flag
	jmp	@lmp2appRxCommError			;Yes => Inform app layer of valid (app layer will issue ret instruction)

;********** lap2lmpTxData **********

lap2lmpTxFrame
	bank	lmpBank
	clr	lmpPosition
	test	lmpTxState				;Idle state ?
	jnz	:Send
:Idle	test	lmpAppLSAP				;LMP Connection open to comm layer ?
	snz						;Zero indicates no connection
	retp						;No  => indicate no data and return
	call	@lmp2appTxCommStart			;Yes => find out if data to send
	snz						;Data to send
	retp						;No  => indicate no data and return
	bank	lmpBank
	mov	lmpTxState, #lmpTxCommDataState		;Prepare to transmit frame
	mov	lmpTxDLSAP, lmpAppLSAP			;Ensure correct DLSAP
	mov	lmpTxSLSAP, #lmpLSAPComm		;Ensure correct SLSAP
	mov	lmpPosition, #lapMaxFrameSize-2		;Protect frame size (LAP frame size less DLSAP and SLSAP bytes)
:Send	mov	w, lmpTxDLSAP				;Desired DLSAP
	bank	plBank
	mov	plIDataDLSAP, w				;Store for transmission
	bank	lmpBank
	mov	w, lmpTxSLSAP				;Desired SLSAP
	bank	plBank
	mov	plIDataSLSAP, w				;Store for transmission
	clz						;Indicate more data to follow
	retp

;********** lap2lmpTxData **********

lap2lmpTxData						;Lap layer can accept a data byte (for an I frame) if there is one available. if there is data available then lmp returns data byte and sets z to false
	bank	lmpBank
	mov	w, lmpTxState				;Jump based on state
	jmp	PC+w					;Jump based on state
	retp						;  0 = Idle state (cannot receive TxData in idle state)
	jmp	lmpTxString				;  1 = lmpTxStringState
	jmp	lmpTxIASError				;  2 = lmpTxIASErrorState
	jmp	lmpTxCommData				;  3 = lmpTxCommDataState

;********** lap2lmpTxValid **********

lap2lmpTxValid						;Lap layer is indicating that all data passed since last TxStart message was acknowledged
	debugl	IFrameDataTx, '^'
	bank	lmpBank
	clr	lmpTxState				;Return to idle state
	sb	lmpAppTxFlag				;Transmitting app data ?
	retp						;No  => return
	clrb	lmpAppTxFlag
	jmp	@lmp2appTxCommValid			;Yes => Inform app layer of valid (app layer will issue ret instruction)

;********** lap2lmpTxError **********

lap2lmpTxError						;Lap layer is indicating that all data passed since last TxStart message will need to be sent again
	debugl	IFrameDataTx, '!'
	setb	ledERR					;Turn ERR led on
	bank	lmpBank
	sb	lmpAppTxFlag				;Transmitting app data ?
	retp						;No  => return (stay in this state for retransmission)
	clrb	lmpAppTxFlag
	jmp	@lmp2appTxCommError			;Yes => Inform app layer of error (app layer will issue ret instruction)

;********************************************************************************
;  LMP LAYER - Rx
;********************************************************************************

lmpRx2TxSetup
	mov	lmpTxDLSAP, lmpRxSLSAP			;DLSAP = received SLSAP
	mov	lmpTxSLSAP, lmpRxDLSAP			;SLSAP = received DLSAP
	retp

;********************************************************************************

;********** lap2lmpRxData - RxDLSAPState **********

lmpRxDLSAPByte
	mov	lmpRxDLSAP, lmpData			;Store data
	inc	lmpRxState				;Next state = lmpRxSLSAPState
	retp

;********** lap2lmpRxData - RxSLSAPState **********

lmpRxSLSAPByte
	mov	lmpRxSLSAP, lmpData			;Store data
	clrb	lmpRxSLSAP.7				;Ensure MSB is clear
	snb	lmpRxDLSAP.7				;Is this a LMP-Command frame (DLSAP bit 7 set) ?
	jmp	:Cmd					;Yes => process command
	csne	lmpRxDLSAP, #lmpLSAPComm		;DLSAP addressing Comm ?
	jmp	:Comm					;Yes => accept
	mov	w, lmpRxBadLSAPState			;If not server then Bad LSAP
	test	lmpRxDLSAP				;0 = IAS Server
	snz						;Addressing IAS Server ?
	mov	w, #lmpRxIASCmdState			;Yes => IAS Server state
	mov	lmpRxState, w				;Apply state
	retp
:Cmd	mov	lmpRxState, #lmpRxLMPCmdOpcodeState	;No => change to RxCmdOpcodeState
	clrb	lmpRxDLSAP.7				;Ensure MSB is clear
	retp
:Comm	mov	w, #lmpRxCommDataState			;Comm data
	test	lmpAppLSAP				;Connected ?
	snz
	mov	w, lmpRxBadLSAPState			;No => error
	mov	lmpRxState, w				;Apply state
	retp

;********** lap2lmpRxData - RxCmdOpcodeState **********

lmpRxCmdOpcodeByte
	mov	lmpRxLMPCmdOpcode, lmpData		;Store data in opcode variable
	mov	lmpRxState, #lmpRxLMPCmdVerifyState	;Wait for Valid message
	retp

;********** lap2lmpRxData - RxIASCmdState **********

lmpRxIASCmd
	mov	w, lmpData				;IAS Service request
	and	w, #%10111111				;Mask out ack bit
	mov	lmpRxIASErrOpcode, w			;Store Service Request in case of error
	xor	w, #$84					;Is the service request GetValueByClass ?
	jnz	:Err					;No => must reply with service unsupported
	inc	lmpRxState				;Yes => wait for class name length
	retp
:Err	mov	lmpRxState, #lmpRxIASErrorState		;Will reply with Unsupported
	mov	lmpRxIASErrRetCode, #$FF		;Reply = $FF = unsupported service
	retp

;********** lap2lmpRxData - RxIASClassLengthState **********

lmpRxIASClassLength					;Data = lnegth of class name
	inc	lmpRxState				;Next state = lmpRxIASClassTestState
	mov	lmpRxIASErrRetCode, #$01		;If error then Reply = $01 = no such class
	csne	lmpData, #$06				;Is the class name length 6 indicating that we should test for "Device" ?
	jmp	:Dev					;Yes => test for "Device"
	csne	lmpData, #$0B				;Is the class name length 11 indicating that we should test for "IrDA:IrCOMM" ?
	jmp	:Comm					;Yes => test for "IrDA:IrCOMM"
	mov	lmpRxState, #lmpRxIASErrorState		;No => Will reply with IAS error
	retp
:Dev	mov	lmpRxPostTest, #lmpRxIASDeviceAttribState	;If class is correct then will cahnge to DeviceAttrib state
	mov	lmpPosition, #_lmpIASDeviceClass		;Pointer to string
	retp
:Comm	mov	lmpRxPostTest, #lmpRxIASCommAttribState		;If class is correct then will cahnge to CommAttrib state
	mov	lmpPosition, #_lmpIASCommClass			;Pointer to string
	retp

;********** lap2lmpRxData - RxIASDeviceAttribState **********

lmpRxIASDeviceAttrib
	mov	lmpRxState, #lmpRxIASAttribTestState		;Next will verify attrib string
	mov	lmpRxPostTest, #lmpRxIASAttribVerifyState	;If attrib is correct then will cahnge to AttribVerify state
	mov	lmpRxIASErrRetCode, #$02			;If error then Reply = $02 = no such attribute
	csne	lmpData, #$0A					;Is the class name length 10 indicating that we should test for "DeviceName" ?
	jmp	:Name						;Yes => test for "Device"
	csne	lmpData, #12					;Is the class name length 12 indicating that we should test for "IrLMPSupport" ?
	jmp	:Supp						;Yes => test for "IrLMPSupport"
	mov	lmpRxState, #lmpRxIASErrorState			;No => Will reply with IAS error
	retp
:Name	mov	lmpRxSendStringL, #_lmpIASDeviceName		;Pointer to string to send in reply if attrib verifies
	mov	lmpPosition, #_lmpIASDeviceAttribName		;Pointer to string to test
	retp
:Supp	mov	lmpRxSendStringL, #_lmpIASDeviceSupport		;Pointer to string to send in reply if attrib verifies
	mov	lmpPosition, #_lmpIASDeviceAttribSupport	;Pointer to string to test
	retp
	
;********** lap2lmpRxData - RxIASCommAttribState **********

lmpRxIASCommAttrib
	mov	lmpRxState, #lmpRxIASAttribTestState		;Next will verify attrib string
	mov	lmpRxPostTest, #lmpRxIASAttribVerifyState	;If attrib is correct then will cahnge to AttribVerify state
	mov	lmpRxIASErrRetCode, #$02			;If error then Reply = $02 = no such attribute
	csne	lmpData, #$0A					;Is the class name length 10 indicating that we should test for "Parameters" ?
	jmp	:Param						;Yes => test for "Parameters"
	csne	lmpData, #$12					;Is the class name length 18 indicating that we should test for "IrDA:IrLMP:LsapSel" ?
	jmp	:Lsap						;Yes => test for "IrDA:IrLMP:LsapSel"
	mov	lmpRxState, #lmpRxIASErrorState			;No => Will reply with IAS error
	retp
:Param	mov	lmpRxSendStringL, #_lmpIASCommParam		;Pointer to string to send in reply if attrib verifies
	mov	lmpPosition, #_lmpIASCommAttribParam		;Pointer to string to test
	retp
:Lsap	mov	lmpRxSendStringL, #_lmpIASCommLsapSel		;Pointer to string to send in reply if attrib verifies
	mov	lmpPosition, #_lmpIASCommAttribLsapSel		;Pointer to string to test
	retp

;********** lap2lmpRxData - RxIASStringTestState **********

lmpRxIASStringTest
	mov	m, #_lmpRxStringSegment / 256		;String Segment (high)
	mov	w, lmpPosition				;Pointer to string (low)
	inc	lmpPosition				;Increment offset for next byte
	iread						;Get data byte (in w)
	xor	w, lmpData				;Is the received data byte correct ?
	jnz	:Err					;No  => error
	mov	w, m					;Yes => continue. Move high part of data to w
	test	w					;Is this the last byte ? (m is not 0)
	snz
	retp						;No  => stay in this state
	mov	lmpRxState, lmpRxPostTest		;Yes => Change to next state
	retp
:Err	mov	lmpRxState, #lmpRxIASErrorState		;Will reply with Error code
	retp

;********** lap2lmpRxData - RxCommDataState **********

lmpRxCommData
	setb	lmpAppRxFlag				;remember passing data
	mov	w, lmpData				;Data to pass
	jmp	@lmp2appRxCommData			;Pass data to app layer

;********************************************************************************

;********** lap2lmpRxValid - RxBadLSAPState **********

lmpRxBadLSAP						;Should disconnect connection !!!
	jmp	@lmp2lapDisconnectRequest

;********** lap2lmpRxValid - RxLMPCmdVerifyState **********

lmpRxValidLMPCommand
	csne	lmpRxLMPCmdOpcode, #lmpConnectCmdOpcode	;Is this a request to open a connection ?
	jmp	:Conn					;Yes => accept
	csne	lmpRxLMPCmdOpcode, #lmpDisconnectOpcode	;Is this a request to clsoe a connection ?
	jmp	:Disc					;Yes => close
	retp						;No  => Unknown or unsupported command => ignore
:Conn	mov	lmpTxStringH, #_lmpLMPConnRsp / 256	;Pointer to string
	mov	lmpTxStringL, #_lmpLMPConnRsp		;Pointer to string
	mov	lmpTxState, #lmpTxStringState		;Prepare to transmit parameters
	setb	lmpRxSLSAP.7				;Indicate command (this will be the DLSAP byte when transmitted)
	cse	lmpRxDLSAP, #lmpLSAPComm		;DLSAP addressing Comm ?
	jmp	lmpRx2TxSetup				;No  => nothing more to do other than to prepare to send reply
	mov	lmpAppLSAP, lmpRxSLSAP			;Yes => Store Source LSAP in AppLSAP (ie remember the remote Comm App LSAP)
	clrb	lmpAppLSAP.7				;Set to information frame
	jmp	lmpRx2TxSetup				;prepare to send reply
:Disc	csne	lmpRxDLSAP, #lmpLSAPComm		;DLSAP addressing Comm ?
	clr	lmpAppLSAP				;Yes => clear connection
	retp

;********** lap2lmpRxValid - RxIASAttribVerifyState **********

lmpRxValidIASAttribVerify
	mov	lmpTxStringH, #_lmpTxStringSegment / 256	;Pointer to string
	mov	lmpTxStringL, lmpRxSendStringL			;Pointer to string
	mov	lmpTxState, #lmpTxStringState			;Prepare to transmit parameters
	jmp	lmpRx2TxSetup					;Prepare to transmit frame

;********** lap2lmpRxValid - RxIASErrorState **********

lmpRxValidIASError
	mov	lmpTxState, #lmpTxIASErrorState			;Prepare to transmit error return code
	mov	lmpTxIASErrOpcode, lmpRxIASErrOpcode
	mov	lmpTxIASErrRetCode, lmpRxIASErrRetCode
	jmp	lmpRx2TxSetup					;Prepare to transmit frame

;********** lap2lmpRxValid - RxCommDataState **********

lmpRxValidCommData
	clr	lmpRxState					;Clear RxState back to idle
	clrb	lmpAppRxFlag
	jmp	@lmp2appRxCommValid

;********************************************************************************
;  LMP LAYER - Tx
;********************************************************************************

;********** lap2lmpTxData - TxStringState **********

lmpTxString
	mov	m, lmpTxStringH				;Pointer to string (high)
	mov	w, lmpTxStringL				;Pointer to string (low)
	add	w, lmpPosition				;Add offset
	inc	lmpPosition				;Increment offset for next byte
	iread
	mov	Temp, w					;Store data
	mov	w, m					;Move high part of data to w
	test	w					;Is this the last byte ?
	jnz	:Last					;Yes
	mov	w, Temp					;Data to pass
	clz						;Indicate more data to follow Data
	retp						;Return data to framing layer
:Last	mov	w, Temp					;Data to pass
	stz						;Indicate last byte
	retp						;Return data to framing layer

;********** lap2lmpTxData - TxIASErrorState **********

lmpTxIASError
	test	lmpPosition
	jnz	:ErrCod
:Opcode	mov	w, lmpTxIASErrOpcode			;Opcode that was received
	inc	lmpPosition				;Next will send RetCode
	clz						;Indicate more data to follow
	retp
:ErrCod	mov	w, lmpTxIASErrRetCode			;RetCode
	stz						;Indicate last byte
	retp

;********** lap2lmpTxData - TxCommDataState **********

lmpTxCommData
	setb	lmpAppTxFlag				;remember receiving data
	call	@lmp2appTxCommData			;Get next data byte
	bank	lmpBank
	snz						;Skip if not last byte
	retp						;Z = 0 indicating last byte
	dec	lmpPosition				;Byte counter
	retp						;Returns Z = true if counter = 0 ie when counter reaches 0 last flag will be set

;********************************************************************************
			ENDM

LmpRxStringSeg		MACRO
;********************************************************************************
;  LMP LAYER - Strings		;WARNING - Strings must not go over a 256 boundry !!!
;********************************************************************************

_lmpRxStringSegment		;Rx strings must all be in the same segement !!!

_lmpIASDeviceClass		dw	'Device'+$F00				;Classname = "Device" ($F00 indicates end)
_lmpIASDeviceAttribName		dw	'DeviceName'+$F00			;Device Attribute: "DeviceName" ($F00 indicates end)
_lmpIASDeviceAttribSupport	dw	'IrLMPSupport'+$F00			;Device Attribute: "IrLMPSupporte" ($F00 indicates end)
_lmpIASCommClass		dw	'IrDA:IrCOMM'+$F00			;Classname = "IrDA:IrCOMM" ($F00 indicates end)
_lmpIASCommAttribParam		dw	'Parameters'+$F00			;IrCOMM Attribute: "Parameters" ($F00 indicates end)
_lmpIASCommAttribLsapSel	dw	'IrDA:IrLMP:LsapSel'+$F00		;IrCOMM Attribute: "LsapSel" ($F00 indicates end)

;********************************************************************************
			ENDM

LmpTxStringSeg		MACRO
;********************************************************************************
;  LMP LAYER - String		;WARNING - Strings must not go over a 256 boundry !!!
;********************************************************************************

_lmpTxStringSegment		;Tx strings must all be in the same segement !!!

_lmpLMPConnRsp			dw	lmpConnectRspOpcode, $00+$F00

_lmpIASDeviceName		dw	$84, $00				;$84 = Reply to GetValueByClass, $00 = success
_lmpIASDeviceName1		dw	$00, $01				;List length = 1 item
_lmpIASDeviceName2		dw	$00, $00				;Object identifier = 0
_lmpIASDeviceName3		dw	$03, $00				;Data is of type "User string", ASCII
_lmpIASDeviceName4		dw	28					;length of text = 28 octets
_lmpIASDeviceNameText		dw	'SX IrDA IrComm Demonstration'+$F00	;String to be displayed

_lmpIASDeviceSupport		dw	$84, $00				;$84 = Reply to GetValueByClass, $00 = success
_lmpIASDeviceSupport1		dw	$00, $01				;List length = 1 item
_lmpIASDeviceSupport2		dw	$00, $00				;Object identifier = 0
_lmpIASDeviceSupport3		dw	$02					;Data is of type "Octet Sequence"
_lmpIASDeviceSupport4		dw	$00, $03				;Data is 3 bytes in length
_lmpIASDeviceSupport5		dw	$01					;Data : IrLMP Version = 1 (refer LMP p 84)
_lmpIASDeviceSupport6		dw	$00					;Data : IAS Support = no additional features (refer LMP p 84)
_lmpIASDeviceSupport7		dw	$00+$F00				;Data : MUX Support = no additional features (refer LMP p 85) ($F00 indicates end)

_lmpIASCommParam		dw	$84, $00				;$84 = Reply to GetValueByClass, $00 = success
_lmpIASCommParam1		dw	$00, $01				;List length = 1 item
_lmpIASCommParam2		dw	$00, $00				;Object identifier = 0
_lmpIASCommParam3		dw	$02					;Data is of type "Octet Sequence"
_lmpIASCommParam4		dw	$00, $06				;Data is 6 bytes in length
_lmpIASCommParam5		dw	$00, 1, %00000001			;Data : Service types = 3 wire raw
_lmpIASCommParam6		dw	$01, 1, %00000011+$F00			;Data : Port type = serial or parallel ($F00 indicates end)

_lmpIASCommLsapSel		dw	$84, $00				;$84 = Reply to GetValueByClass, $00 = success
_lmpIASCommLsapSel1		dw	$00, $01				;List length = 1 item
_lmpIASCommLsapSel2		dw	$00, $00				;Object identifier = 0
_lmpIASCommLsapSel3		dw	$01					;Data is of type "Integer"
_lmpIASCommLsapSel4		dw	$00, $00, $00, lmpLSAPComm+$F00		;LsapSel = 5 ($F00 indicates end)

;********************************************************************************
			ENDM

AppInfoSeg		MACRO
;********************************************************************************
;  APP LAYER
;********************************************************************************
;  Updated 6 Decembet 1999 - Nick Kelsey
;  * TransApp: Increased UART buffer size from 7 to 16 bytes.
;  * TransApp: Added flow control for UART receive.
;********************************************************************************
;
;	lmp2appRxCommData(w = Data)			;Incomming data bytes
;	lmp2appRxCommValid()				;Data bytes passed since last Valid/Error message are valid
;	lmp2appRxCommError()				;Data bytes passed since last Valid/Error message are invalid and should be discarded
;
;	lmp2appTxCommStart(ret z=None)			;Data bytes can now be sent, Return Z=false if data to be sent
;	lmp2appTxCommData(ret w=TxData, z=Last)		;Data bytes can now be sent. Set Z if this is the last byte to be sent
;	lmp2appTxCommValid()				;All data passed since last Valid/Error message were acknowledged as received by the remote station
;	lmp2appTxCommError()				;All data passed since last Valid/Error message were discarded and will need to be sent again
;
;	lap2appRxUIData(w = Data)			;Incomming UI data bytes (outside of a connection only)
;	lap2appRxUIValid()				;Data bytes passed since last Valid/Error message are valid
;	lap2appRxUIError()				;Data bytes passed since last Valid/Error message are invalid and should be discarded
;
;	app2lapTxUIFrame(ret z=Busy)
;	lap2appTxUIData(ret w=TxData, z=Last)
;	lap2appTxUIComplete()
;
;	app2lapDiscoveryRequest(ret z=Busy)
;
;********************************************************************************
			ENDM


AppCommSX2PCCodeSeg	MACRO
;********************************************************************************
;  APP LAYER - CommSX2PC
;********************************************************************************

appBank		= 	$F0

appTxState	=	appBank + 0		;Current transmission type
appTxPosition	=	appBank + 1		;Current transmission position
appTxBank	=	appBank + 2		;Current transmission position
appRxData	=	appBank + 3		;Current received byte

appTxStrState	=	1
appTxRegState	=	2
appTxPortState	=	3

;********** Return **********

appReturn	retp

;********** a2appReset **********

a2appReset
	bank	appBank
	clr	appTxState
	retp

;********** lmp2appRxCommData **********

lmp2appRxCommData					;Incomming data bytes
	bank	appBank
	mov	appRxData, w				;Store data (if more bytes are received in frame then only last byte is reconised)
	retp

;********** lmp2appRxCommValid **********

lmp2appRxCommValid					;Data bytes passed since last Valid/Error message are valid
	bank	appBank
	test	appTxState				;Currently not sending anything ?
	sz
	retp						;Already sending a frame => ignore command
	debugf	1, appRxData				;Show command out debug port
	csne	appRxData, #'?'				;Is the command '?' ?
	jmp	:Str					;Yes => prepare to transmit a string
	csne	appRxData, #'r'				;Is the command 'r' ?
	jmp	:Reg					;Yes => prepare to transmit registers
	csne	appRxData, #'c'				;Is the command 'c' ?
	jmp	:Port					;Yes => prepare to transmit port c contents
	retp
:Str	mov	appTxState, #appTxStrState		;Will send string
	retp
:Reg	mov	appTxState, #appTxRegState		;Will send registers
	clr	appTxBank				;Clear TxBank ready for transmission
	retp
:Port	mov	appTxState, #appTxPortState		;Will send port c
	retp

;********** lmp2appRxCommError **********

lmp2appRxCommError					;Data bytes passed since last Valid/Error message are invalid and should be discarded
	retp

;********** lmp2appTxCommStart **********

lmp2appTxCommStart					;Data bytes can now be sent. Return Z = flase if data to be sent
	bank	appBank
	clr	appTxPosition				;Clear TxPosition ready for transmission
	test	appTxState				;Return z=false if TxState not 0 to indicate data to be sent
	retp

;********** lmp2appTxCommData **********

lmp2appTxCommData					;Data bytes can now be sent. If there is data available then return data byte and set Last (z) to false
	bank	appBank
	mov	w, appTxState				;Jump based on state
	jmp	PC+w
	retp						;0 = Invalid
	jmp	appTxStrData				;1 = appTxStrState
	jmp	appTxRegData				;2 = appTxRegState
	jmp	appTxPortData				;3 = appTxPortState

appTxStrData
	mov	m, #_lmpIASDeviceNameText / 256		;Pointer to string (high)
	mov	w, #_lmpIASDeviceNameText		;Pointer to string (low)
	add	w, appTxPosition			;index into string
	inc	appTxPosition				;Increment offset for next byte
	iread						;Read data from ROM
	mov	Temp, w					;Store data
	mov	w, m					;Move high part of data to w
	test	w					;Is this the last byte ?
	jnz	:Last					;Yes => indicate last
:More	mov	w, Temp					;No  => indicate more. Recover data to pass
	clz						;Indicate more data to follow Data
	retp						;Return data
:Last	mov	w, Temp					;Data to pass
	stz						;Indicate last byte
	retp						;Return data

appTxRegData
	mov	w, #$10					;w = $10
	add	w, appTxBank				;w = current bank (starting from $10)
	add	w, appTxPosition			;w = pointer to current register
	mov	FSR, w					;Apply pointer
	mov	Temp, INDF				;Obtain data from register
	bank	appBank
	csne	appTxPosition, #$0F			;Last byte to be transmitted in frame ?
	jmp	:Last					;Yes => indicate last
:More	inc	appTxPosition				;No  => indicate more. Increment position fo next data byte
	mov	w, Temp					;Recover data to send
	clz						;Indicate more data to follow
	retp
:Last	mov	w, Temp					;Recover data to send
	stz						;Indicate last byte
	retp

appTxPortData
	mov	w, rc					;Return contents of port c
	stz						;Indicate no more data to send
	retp						;Return data

;********** lmp2appTxCommValid **********

lmp2appTxCommValid					;All data passed since last Valid/Error message were acknowledged as received by the remote station
	bank	appBank
	csne	appTxState, #appTxRegState		;Currently transmitting registers ?
	jmp	:Reg					;Yes => send more registers (multi frame)
	clr	appTxState				;No  => finished transmitting, return to idle state
	retp
:Reg	add	appTxBank, #$20				;Add $20 for next bank
	sz						;Back to starting bank ?
	retp						;No  => more data to send, stay in this state
	clr	appTxState				;Yes => finished transmitting, return to idle state
	retp

;********** lmp2appTxCommError **********

lmp2appTxCommError					;All data passed since last Valid/Error message were discarded and will need to be sent again
	retp						;Stay in current state for retransmission

;********** UI Frames **********

lap2appRxUIData		=	appReturn
lap2appRxUIValid	=	appReturn
lap2appRxUIError	=	appReturn
lap2appTxUIData		=	appReturn
lap2appTxUIComplete	=	appReturn

;********** Uart **********

a2appRxAvail
	bank	IsrBank
	clrb	UartRxAvail				;Clear flag
	retp

;********************************************************************************
			ENDM

AppCommTransCodeSeg	MACRO
;********************************************************************************
;  APP LAYER - CommTrans
;********************************************************************************

appBank		= 	$D0			;Local variables
appData		=	$F0			;16-byte buffer

appHeadPtr	=	appBank + 0		;1 byte
appTailPtr	=	appBank + 1		;1 byte

;********** Return **********

appReturn	retp

;********** a2appReset **********

a2appReset
	bank	appBank
	clr	appHeadPtr			;Init buffer head pointer
	clr	appTailPtr			;Init buffer tail pointer
	clrb	UartCtsPin			;Indicate CTS to PC - ready to accept more data
	retp

;********** lmp2appRxCommData **********

lmp2appRxCommData				;Incomming data bytes
	debug	1				;Show data out debug port
	retp

;********** lmp2appRxCommValid **********

lmp2appRxCommValid				;Data bytes passed since last Valid/Error message are valid
	retp

;********** lmp2appRxCommError **********

lmp2appRxCommError				;Data bytes passed since last Valid/Error message are invalid and should be discarded
	retp

;********** lmp2appTxCommStart **********

lmp2appTxCommStart				;Data bytes can now be sent. Return Z = flase if data to be sent
	bank	appBank
	mov	w, appHeadPtr			;Compare head pointer with tail pointer
	xor	w, appTailPtr			;Z is true if they match => indicating no data to send
	retp					;Z is false if they do not match indicating data to send

;********** lmp2appTxCommData **********

lmp2appTxCommData				;Data bytes can now be sent. If there is data available then return data byte and set Last (z) to false
	bank	appBank
	mov	w, appTailPtr			;Index into buffer
	and	w, #%00001111			;16 byte buffer
	xor	w, #appData			;Add pointer to first byte of data
	mov	FSR, w				;Apply pointer
	mov	Temp, INDF			;Read byte out of buffer
	bank	appBank
	inc	appTailPtr			;move on tail ptr
	mov	w, appHeadPtr			;Compare head pointer with tail pointer
	xor	w, appTailPtr			;Do they match (indicating no more data)
	jz	:Last				;Yes => no more data
:More	mov	w, Temp				;No  => more data. Recover data
	clz					;Indicate more data to follow
	retp					;Return data
:Last	mov	w, Temp				;Recover data
	clrb	UartCtsPin			;Indicate CTS to PC - ready to accept more data
	stz					;Indicate last byte
	retp					;Return data

;********** lmp2appTxCommValid **********

lmp2appTxCommValid				;All data passed since last Valid/Error message were acknowledged as received by the remote station
	retp

;********** lmp2appTxCommError **********

lmp2appTxCommError				;All data passed since last Valid/Error message were discarded and will need to be sent again
	retp

;********** UI Frames **********

lap2appRxUIData		=	appReturn
lap2appRxUIValid	=	appReturn
lap2appRxUIError	=	appReturn
lap2appTxUIData		=	appReturn
lap2appTxUIComplete	=	appReturn

;********** Uart **********

a2appRxAvail
	setb	UartCtsPin			;Indicate NOT CTS after 1st byte (PC will send 16 bytes after loosing CTS!)
	bank	IsrBank
	mov	Temp, UartRxData		;Store received byte in buffer
	clrb	UartRxAvail			;Clear flag
	bank	appBank
	mov	w, appHeadPtr			;Index into buffer
	and	w, #%00001111			;16 byte buffer
	xor	w, #appData			;Add pointer to first byte of data
	mov	FSR, w				;Apply pointer
	mov	INDF, Temp			;Store data
	bank	appBank
	inc	appHeadPtr			;Record count
	retp

;********************************************************************************
			ENDM

AppSX2SXCodeSeg		MACRO
;********************************************************************************
;  APP LAYER - SX 2 SX
;********************************************************************************

appBank		= 	$F0

appTxState	=	appBank + 0		;Current transmission type
appTxPosition	=	appBank + 1		;Current transmission position

appTxStrState	=	1
appTxPortState	=	2

;********** Return **********

appReturn	retp

;********** a2appReset **********

a2appReset
	bank	appBank
	clr	appTxState
	retp

;********** lmp2appCommData **********

lmp2appRxCommData	=	appReturn
lmp2appRxCommValid	=	appReturn
lmp2appRxCommError	=	appReturn

lmp2appTxCommData	=	appReturn
lmp2appTxCommValid	=	appReturn
lmp2appTxCommError	=	appReturn

lmp2appTxCommStart
	stz
	retp

;********** UI Frames - Rx **********

lap2appRxUIData
	debug	1					;Show data
	retp

lap2appRxUIValid
	retp

lap2appRxUIError
	retp

;********** UI Frames - Tx **********

lap2appTxUIData
	bank	appBank
	mov	w, appTxState				;Jump based on state
	jmp	PC+w
	retp						;0 = Invalid
	jmp	appTxStrData				;1 = appTxStrState
	jmp	appTxPortData				;2 = appTxPortState

appTxStrData
	mov	m, #_lmpIASDeviceNameText / 256		;Pointer to string (high)
	mov	w, #_lmpIASDeviceNameText		;Pointer to string (low)
	add	w, appTxPosition			;index into string
	inc	appTxPosition				;Increment offset for next byte
	iread						;Read data from ROM
	mov	Temp, w					;Store data
	mov	w, m					;Move high part of data to w
	test	w					;Is this the last byte ?
	jnz	:Last					;Yes => indicate last
:More	mov	w, Temp					;No  => indicate more. Recover data to pass
	clz						;Indicate more data to follow Data
	retp						;Return data
:Last	mov	w, Temp					;Data to pass
	stz						;Indicate last byte
	retp						;Return data

appTxPortData
	mov	w, rc					;Return contents of port c
	stz						;Indicate no more data to send
	retp						;Return data

lap2appTxUIComplete
	bank	appBank
	retp

;********** Uart **********

a2appRxAvail
	bank	IsrBank
	mov	Temp, UartRxData			;Store received byte in Temp
	clrb	UartRxAvail				;Clear data available flag
	bank	appBank
	debugf	1, Temp					;Show command
	csne	Temp, #'d'				;Was the byte a 'd'
	jmp	:XID					;Yes => request discovery
	csne	Temp, #'s'				;Was the byte a 's'
	jmp	:STR					;Yes => send the broadcast string
	csne	Temp, #'c'				;Was the byte a 'c'
	jmp	:PORT					;Yes => send contents of port c
	retp
:XID	call	@app2lapDiscoveryRequest		;Request discovery
	mov	w, #'^'					;Assume accepted (zero false)
	snz						;Was the request accepted ?
	mov	w, #'!'					;No => refused
	debug	1					;Send character out the debug port for the user
	retp
:STR	mov	appTxState, #appTxStrState		;Will send string
	clr	appTxPosition				;Reset position
	jmp	:Send
:PORT	mov	appTxState, #appTxPortState		;Will send port
:Send	call	@app2lapTxUIStart
	mov	w, #'^'					;Assume accepted (zero false)
	snz						;Was the request accepted ?
	mov	w, #'!'					;No => refused
	debug	1					;Send character out the debug port for the user
	retp
	
;********************************************************************************
			ENDM
;********************************************************************************
;  debugl MACRO
;  Send a Literal out the debug port
;  Affects : w
;  Cycles  : 3
;********************************************************************************

debugl	MACRO	2
IF	\1 = 1
	mov	w, #\2
	mov	DebugData, w
	setb	DebugSend
ENDIF
	ENDM

;********************************************************************************
;  debugf MACRO
;  Send a Register out the debug port
;  Affects : w, Z
;  Cycles  : 3
;********************************************************************************

debugf	MACRO	2
IF	\1 = 1
	mov	w,\2
	mov	DebugData, w
	setb	DebugSend
ENDIF
	ENDM

;********************************************************************************
;  debug MACRO
;  Send w out the debug port
;  Affects : None
;  Cycles  : 2
;********************************************************************************

debug	MACRO	1
IF	\1 = 1
	mov	DebugData, w
	setb	DebugSend
ENDIF
	ENDM
;********************************************************************************
;  IrDA Project
;********************************************************************************

	device	SX28L, OSCXT4, TURBO, STACKX_OPTIONX
;	device	PINS28, PAGES4, BANKS8, OSCHS, TURBO, STACKX, OPTIONX
	id	'IrDA'
	reset	Startup
	freq	50000000

;********** Mode Constants **********

TRIS		=	$0F
PLP		=	$0E
LVL		=	$0D
ST		=	$0C
WKEN		=	$0B
WKED		=	$0A
WKPND		=	$09
COMP		=	$08

IsrStatus	=	$0C			;Global ISR status register
DebugData	=	$0D			;Debug data to be sent out the debug port
Temp		=	$0E			;2 bytes of tempory storage

PhysicalDataTx	=	0			;Shows all transmitted bytes to IR medium
PhysicalDataRx	=	0			;Shows all received bytes from IR medium
PayloadDataTx	=	0			;Shows all payload data bytes transmitted followed by ^ when frame is complete
PayloadDataRx	=	0			;Shows all payload data bytes received followed by ^ or ! for pass/fail when frame is complete
PayloadInfo	=	0			;Filters address and shows I, S, or U based on command type
IFrameDataTx	=	0			;Shows all I frame data bytes transmitted followed by ^ or ! for ack/!ack
IFrameDataRx	=	0			;Shows all I frame data bytes received followed by ^ or ! for ack/!ack

ShowXIDInfo	=	1
ShowConnect	=	1

	IsrDataSeg
	FrameDataSeg
	PayloadDataSeg
	LapDataSeg
	LmpDataSeg
	
	org		$0000

	IsrCodeSeg
	MainCodeSeg
	FrameCodeSeg
	LmpRxStringSeg

	org		$0200

	LapCodeSeg
	PayloadString3

	org		$0400

	PayloadCodeSeg
	PayloadString1
	PayloadString2

	org		$0600

; ====================================================================
; Application Code
; 
; Uncomment the following lines for the three different applications.
;
; SX to PC communications (IrComm):
;	AppCommSX2PCCodeSeg
;
; Transparent data transfer. PC to PC. (IrComm):
	AppCommTransCodeSeg
;
; SX to SX communications:
;	AppSX2SXCodeSeg
;
; ====================================================================

	LmpCodeSeg
	LmpTxStringSeg


file: /Techref/scenix/lib/io/osi2/ir/da/IRDA.SRC, 124KB, , updated: 1999/12/6 16:53, local time: 2024/4/16 07:59,
TOP NEW HELP FIND: 
3.136.97.64:LOG IN

 ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF="http://techref.massmind.org/techref/scenix/lib/io/osi2/ir/da/IRDA.SRC"> scenix lib io osi2 ir da IRDA</A>

Did you find what you needed?

 

Welcome to massmind.org!

 

Welcome to techref.massmind.org!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  .