* Code Window
* Copyright (c) 1998 Massachusetts Institute of Technology
*
* This material was developed by the Amorphous Computing project at the
* Massachusetts Institute of Technology Artificial Intelligence
* Laboratory.  Permission to copy and modify this software, to
* redistribute either the original software or a modified version, and
* to use this software for any purpose is granted, subject to the
* following restrictions and understandings.
*
* 1. Any copy made of this software must include this copyright notice
*    in full.
*
* 2. Users of this software agree to make their best efforts (a) to
*    return to the MIT Amorphous Computing project any improvements or
*    extensions that they make, so that these may be included in future
*    releases; and (b) to inform MIT of noteworthy uses of this
*    software.
*
* 3. All materials developed as a consequence of the use of this
*    software shall duly acknowledge such use, in accordance with the
*    usual standards of acknowledging credit in academic research.
*
* 4. MIT has made no warrantee or representation that the operation of
*    this software will be error-free, and MIT is under no obligation to
*    provide any services, by way of maintenance, update, or otherwise.
*
* 5. In conjunction with products arising from the use of this material,
*    there shall be no use of the name of the Massachusetts Institute of
*    Technology nor of any adaptation thereof in any advertising,
*    promotional, or sales literature without prior written consent from
*    MIT in each case.


********************************
**          LABELS            **
********************************
* 

REGBASE                 EQU $1000
PORTA                   EQU REGBASE+$00
PIOC                    EQU REGBASE+$02
PORTC                   EQU REGBASE+$03
PORTB                   EQU REGBASE+$04
PORTCL                  EQU REGBASE+$05
DDRC                    EQU REGBASE+$07
PORTD                   EQU REGBASE+$08
DDRD                    EQU REGBASE+$09
PORTE                   EQU REGBASE+$0A
CFORC                   EQU REGBASE+$0B
OC1M                    EQU REGBASE+$0C
OC1D                    EQU REGBASE+$0D
TCNT                    EQU REGBASE+$0E
TIC1                    EQU REGBASE+$10
TIC2                    EQU REGBASE+$12
TIC3                    EQU REGBASE+$14
TOC1                    EQU REGBASE+$16
TOC2                    EQU REGBASE+$18
TOC3                    EQU REGBASE+$1A
TOC4                    EQU REGBASE+$1C
TI4O5                   EQU REGBASE+$1E
TCTL1                   EQU REGBASE+$20
TCTL2                   EQU REGBASE+$21
TMSK1                   EQU REGBASE+$22
TFLG1                   EQU REGBASE+$23
TMSK2                   EQU REGBASE+$24
TFLG2                   EQU REGBASE+$25
PACTL                   EQU REGBASE+$26
PACNT                   EQU REGBASE+$27
SPCR                    EQU REGBASE+$28
SPSR                    EQU REGBASE+$29
SPDR                    EQU REGBASE+$2A
BAUD                    EQU REGBASE+$2B
SCCR1                   EQU REGBASE+$2C
SCCR2                   EQU REGBASE+$2D
SCSR                    EQU REGBASE+$2E
SCDR                    EQU REGBASE+$2F
ADCTL                   EQU REGBASE+$30
ADR1                    EQU REGBASE+$31
ADR2                    EQU REGBASE+$32
ADR3                    EQU REGBASE+$33
ADR4                    EQU REGBASE+$34
BPROT                   EQU REGBASE+$35
OPTION                  EQU REGBASE+$39
COPRST                  EQU REGBASE+$3A
PPROG                   EQU REGBASE+$3B
HPRIO                   EQU REGBASE+$3C
INIT                    EQU REGBASE+$3D
TEST1                   EQU REGBASE+$3E
CONFIG                  EQU REGBASE+$3F

* 
********************************
*** EEPROM CONFIGURATION ***
*** EEPROM starts at $F800
*** USER at $F820	(total ? bytes)
*** LOADER at $F980	(total ? bytes)
********************************

EEPROM                  EQU $F800
USERPROG		EQU $F820
USERPROGEND		EQU $F980
LOADER			EQU $F9A0

**********************************
*** RAM MEMORY CONFIGURATION *****
*** MESSAGING VARIABLES (4 bytes)
*** STACK $5F to $04	(92 bytes)
*** HEAP $60 to $B7	(88 bytes)  -- also used from RAMPROG
*** MSG OUT $B8		(36 bytes)  -- also used from RAMPROG
*** MSG IN $DC		(36 bytes)
**********************************

COUNT			EQU $00
MSGID			EQU $01
SENDID			EQU $02

STACK                   EQU $5F

LOCRAMPROG		EQU $60

DST                     EQU $B8
SLEN			EQU $B9
SFLAG			EQU $BA
SBUF			EQU $BB

SRC			EQU $DC
RLEN			EQU $DD
RFLAG			EQU $DE
RBUF			EQU $DF

* 
* Overlay for generic header for USERPROG messages:

OUTMSGNUM		EQU $BB      for transferring numbers
OUTMSGTYPE		EQU $BD      message type - for USERPROG interpretation
OUTMSGID		EQU $BF	     to identify this message
OUTMSGSENDID		EQU $C0	     to identify the sender
OUTMSG			EQU $C2	     message text

INMSGNUM		EQU $DF	     for transferring numbers
INMSGTYPE		EQU $E1      message type - for USERPROG interpretation
INMSGID			EQU $E3	     to identify this message
INMSGSENDID		EQU $E4      to identify the sender
INMSG			EQU $E6	     message text


*** VARIABLES ***
* Place your variables in the HEAP REGION *
* TMPA is 2 bytes long
TMPA			EQU $60
TMPC			EQU $62
VERSION                 EQU $64
OSRPCRUNNING		EQU $65
FOOA			EQU $66  -- for program use only
FOOB			EQU $68
FOOC			EQU $6A
FOOD			EQU $6C
TMPB			EQU $6E
TMPMESSAGE		EQU $70  -- This is 36 bytes long.

*** PARAMETERS ***
* parameters for send and recieve
SDELAY			EQU 300
TDELAY			EQU 50
FCOUNT			EQU 15
RDELAY			EQU 200
QTDELAY			EQU 12
TDELAY2			EQU 100
D10ms                   EQU 10000/3

* message protocol
YESACK			EQU $AA 
NOACK			EQU $3C

TAGDATA			EQU $00  -- This must be zero.
TAGVERSION		EQU $20
TAGPROGRAM		EQU $60
TAGOS			EQU $E0
TAGMASK			EQU $E0
LENMASK			EQU $1F

* OS Remote Control  (RPC, etc.)
TAGOSRPC		EQU $E854  -- Tag for RPC
OSREQOK			EQU $D3    -- OS Request return receipt


***********************************************
** The Loader program + Example User Program **
***********************************************

 ORG EEPROM
RESET		LDS  #STACK
		CLR  BPROT	enable EEPROM erase/write 
*				(needs to happen in first 60ms)
		STX SENDID	create a unique stamp for this machine
		JMP OSRUNUSERPROG
EECOUNT		FCB $00		used to determine program validity

* 
******************************
** User Program Starts Here **
******************************
* USER PROGRAM must start with the version number
* User supplied program must poll for new messages
*	 (OSPOLL) at least every RDELAY delay cycles
* User program can use loader supplied subroutines
* User Program must be no larger then 3840 bytes or
*	 run over USERPROGEND
* Program has access to FOOA - FOOD, contiguous 16-bit vars
***************************************************

 ORG USERPROG

*
* Contagious Loader
*

*
* This is THE firefly/circle demo.
*

*
* FOOA my circle demo number (distance)
* FOOA+1 how long I've been displaying it
* FOOB not listening delay
* FOOC firefly times
* FOOC+1 pulse width
* FOOD listening delay
*

VER		FCB $08
PROGBEGIN	LDD SENDID		get a unique ID
		ANDA #$04
		ORA #$01		between #$100-#$400
		STD FOOD		store it as my delay
		LDY #$0200		initialize not-listening delay
		STY FOOB
		LDY #$0020		firefly count/pulse width
		STY FOOC
		LDY #$7F00		start with number 7F
		STY FOOA

		CLRA
		PSHA
STARTLOOP	LDAA FOOA+1
		BNE DISPCIRC

		LDAA #$D3		
		STAA OUTMSGTYPE		label message as a firefly

		LDAA FOOC		increment firefly count
		BNE FIREOK
		LDAB #$7F
		CMPB FOOA		circle been over?
		BEQ FIREOK		if not,

		PULA
		JSR NOHEARFIRE		then display without communication
		PSHA

FIREOK		INCA
		STAA FOOC
		CMPA #$15		timeout for circle (one more 
		BNE DISPFIRE		  than display)

		LDAA #$7F		kill the circle demo number
		STAA FOOA

DISPFIRE	PULA
		COMA			blink
		STAA PORTB		flash lights
		PSHA
		BRA BROAD		go to broadcast it

DISPCIRC	LDAA #$3D
		STAA OUTMSGTYPE		label message as a circle

		DEC FOOA+1		I've displayed it once

		LDAA FOOA		get circle number
		INCA			add one
		STAA PORTB		display it

BROAD		STAA OUTMSGNUM		broadcast what displaying
		LDAA #$04
		STAA SLEN		it's four bytes
		LDAB FOOC+1		pulse width
		CLRA
		XGDY
		CLRB			broadcast the message
		JSR BROADCAST		flash on the air

		LDY FOOB		set natural frequency
		JSR YDELAY		(don't listen to world)

		LDY FOOD
DELAYLOOP	LDAB #$01		specify delay factor
		JSR DELAYINT		delay
		CMPB #$04
		BEQ STARTCIRCLE		was the light sensor hit?
*		CMPB #$05
*		BEQ CONFIGMODE		was the button pressed?
		TSTB
		BEQ DONELOOP		done loop?

		LDAB INMSGTYPE		was it a flash?
		CMPB #$D3
		BEQ FLASHMSG
		CMPB #$3D		was it a circle?
		BEQ CIRCLEMSG
		BRA DELAYLOOP		if not - false alarm

FLASHMSG	PULA
		LDAA INMSGNUM		fix up message if not good
		CMPA #$0F		(set to everyone elses)
		BLO FLASHON
		CLRA
		BRA FLASH
FLASHON		LDAA #$FF
FLASH		PSHA

		LDD FOOD
		SUBD #$04

FIXNUM		ANDA #$04
		ORA #$01
		STD FOOD
		JMP STARTLOOP

DONELOOP	LDD FOOD		drift up
		ADDD #$01

		BRA FIXNUM

CIRCLEMSG	LDAA INMSGNUM		get the number that was broadcast
		CMPA FOOA		is it less?
		BHS GOTOSTART		if so
		PSHA
		LDD FOOA
		CMPA #$7F		is it new/killed?
		BNE NOTNEW
		LDAB #$14		display 20 times
NOTNEW		PULA
		STD FOOA
		BRA CIRCLEEND

STARTCIRCLE	LDD FOOA
		CMPA #$7F
		BNE STARTNOTNEW		is it new/killed?
		LDAB #$14		display 20 times
STARTNOTNEW	CLRA
		STD FOOA
CIRCLEEND	CLR FOOC
GOTOSTART	JMP STARTLOOP

NOHEARFIRE	BSR NOHEARBIGLOOP
		BSR NOHEARBIGLOOP
		BSR NOHEARBIGLOOP
		RTS

NOHEARBIGLOOP	LDY FOOD
		PSHA
NOHEARLOOP	LDAB #$01
		JSR DELAYINT
		TSTB
		BNE NOHEARLOOP
		LDY FOOB
		JSR YDELAY
		PULA
		COMA
		STAA PORTB
		RTS

* CONFIGMODE	LDAA FOOA
*		CMPA #$7F		timeout for config/same for other
*		BNE GOTOSTART		config code below
*		DECA
*		STAA FOOA		clear for new timeout
*		CLR FOOC		clear firefly time
*		LDD FOOB		allow change - FOOB, FOOC+1
*		LSRD
*		LSRD
*		LSRD			/16
*		LSRD
*		CLRA
*		JSR SETNUM
*		LSLD
*		LSLD
*		LSLD			*16
*		LSLD
*		STD FOOB
*		LDAB FOOC+1
*		JSR SETNUM
*		STAB FOOC+1
*		LDY FOOB
*		BSR BROADCONFIG
*		BRA GOTOSTART		

* CONFIGRPC	LDAA FOOA
*		CMPA #$7F		timeout for config/same for other
*		BNE RETURN		config code below
*		DECA
*		STAA FOOA		clear for new timeout
*		CLR FOOC		clear firefly time
*		STAB FOOC+1		change pulse width
*		STY FOOB		change not-listening delay
*		BSR BROADCONFIG
* RETURN	RTS

* BROADCONFIG	LDX #$0008		try 8 times
* BROADLOOP	PSHX
*		PSHB
*		LDX #CONFIGRPC
*		CLR DST
*		JSR OSRPC
*		PULB
*		PULX
*		DEX
*		BNE BROADLOOP
*		RTS

*
* ENCODE gets value in B, puts encoded in A
* DECODE gets encoded in A, puts value in B
* 
*
* Mapping - 1, 2, 3, 4, 6 ,8,10,12,16,20,24,28,36,44,52,60
*           0  0  0  0  0  0  0  0  1  1  1  1  1  1  1  1 
*	    0  0  0  0  1  1  1  1  0  0  0  0  1  1  1  1
*           0  0  1  1  0  0  1  1  0  0  1  1  0  0  1  1
*           0  1  0  1  0  1  0  1  0  1  0  1  0  1  0  1
*

* CONFIGNUM	PSHA
*		BSR ENCODE
*		JSR SETNUM
*		BSR DECODE
*		PULA
*		RTS

* ENCODE	LDAA #$FF		initialize A
* ENCODELOOP	INCA
*		BSR FINDADDER			
*		CLC
*		SBCB TMPB		allow numbers greater or equal to be
*		BHI ENCODELOOP		remapped
*		RTS

* DECODE	CLRB
* DECODELOOP	BSR FINDADDER
*		ADDB TMPB
*		DECA
*		CMPA #$FF
*		BNE DECODELOOP
*		RTS

* FINDADDER	PSHA
*		ANDA #$0C
*		LSRA
*		LSRA
*		CLR TMPB
*		INC TMPB		set TMPB=1
*		INCA
* FINDADDLOOP	LSR TMPB
*		DECA
*		BNE FINDADDLOOP
*		LSL TMPB
*		PULA
*		RTS

*
* Must have this to signal end of user program.
*

PROGEND		NOP
	
*********************************************
*** LIBRARY OF PROCEDURES STARTS HERE *******
*********************************************

* 
**********************************************
** PROCEDURE : OSSEND
** SEND starts here - all labels start with OS
** MUST save all registers, all get trashed
**
** ARGUMENTS:
**	place msg in SBUF
**	length of MSG + msg tag in SLEN (TAG[3]:LENGTH[5])
**        TAG values:
**		DATA    000
**		VERSION 001
**		PROGRAM 011
**              OS	111
**      destination of MSG in DST
**	Clear SFLAG
** RETURN:
** SFLAG =
**      $00 = success
**	$01 = failure, no response
**	$02 = line in use already
**********************************************

************************************
** HANDSHAKE with neighbor      **
** before starting transmission **
************************************
** 
** Handshake protocol (sender):
**
**  1. check if line is LOW.  If LOW, goto receive mode
**  2. hold line LOW for SDELAY (= 300)
**  3. sample line 3 times checking for LOW (i.e. receiver confirmation)
**  4. if line did not go LOW, send failed
**  5. after TDELAY check if line still LOW, if not LOW, goto 8
**  6. after another TDELAY, check if line still LOW, if HIGH goto 8
**  7. not a confirmation, send failed
**  8. handshake complete.  start sending
**
***************************************

 ORG LOADER
OSSEND		LDAA DDRC	store old DDRC on stack
		PSHA		restore at end (ossdone)
*
* check if line is already LOW.  If LOW, then line is in use
*
		CLR DDRC	enable reads c0-c3
		LDAA PORTC    
		ANDA DST
		BNE OSSHANDSHAKE
		JMP OSLINEINUSE

*
* Otherwise, try to transmit beginning of handshake 
*
OSSHANDSHAKE	LDAA #$0E	enable write c1-c3, read c0
		STAA DDRC
		LDAA DST
		COMA           LOWER LINE for delay=SDELAY
		STAA PORTC
		LDX #SDELAY
		JSR DELAY
		LDAA #$FF
		STAA PORTC	then raise line again

*
* wait for confirmation from receiver
*
		LDAB #$03	poll 3 times looking for confirmation
		CLR DDRC	enable reads c0-c3
OSSPOLL1	LDAA PORTC
		ANDA DST
		BEQ OSSWAITHIGH  recieved confirm (= low), then wait for  high
		LDX #TDELAY
		JSR DELAY
		DECB
		BNE OSSPOLL1	
		JMP OSNOCONFIRM	for now an error, usually try again from start

*
* Confirmation must last at most 2*TDELAY
*
OSSWAITHIGH	LDX #TDELAY    wait TDELAY, then check if line is HIGH
		JSR DELAY 
		LDAA PORTC
		ANDA DST
		BNE OSTRANSMIT   if got HIGH, then ready to transmit
		LDX #TDELAY    wait TDELAY, then check if line is HIGH
		JSR DELAY 
		LDAA PORTC
		ANDA DST
		BNE OSTRANSMIT
		BRA OSWRONGCONFIRM      if still LOW, then error

*******************************************
*** TRANMISSION
*** Transmit bytes stored in SBUF 
*** Number of bytes to be transmitted SLEN
*** START transmission with a ZERO BIT
*** send HEADER byte TAG(3):SLEN(5)
*** send SLEN bytes, one byte at a time
*** END transmission with a ONE BIT (reset line)
*******************************************

OSTRANSMIT
*		LDAA #$F9	1001 pattern to say sending msg on c1
*		STAA PORTB
		LDAA #$0E	enable write c1-c3, read c0
		STAA DDRC

*
* Start by Sending Zero 
*
		LDAA DST
		COMA
		STAA PORTC
		LDX #TDELAY	
		JSR DELAY

*** NOTE : cycle counting from this point on

*
* SEND HEADER = TAG(3):SLEN(5)
*
		LDAB SLEN	(3) put header in B
		LDY  #$08	(4)

 JSR OSSENDBITS	send the header
*
* setup
*
		LDAA SLEN	(3) sending SLEN bytes
		ANDA #LENMASK	(2) clear TAG 
		STAA TMPC	(3) store counter in memory
		LDX #SBUF	need 2 byte address for indirect addressing
		STX TMPA	copy address of data being sent to tmpA

*
* SEND SLEN * 8 BITS
*

OSSENDBYTE	LDX  TMPA	(4)
		LDAB 0,X	(4) put msg in B 
		LDY  #$08	(4) send 8 bits

		JSR OSSENDBITS	send 8 bits stored in accumulator B

		LDX TMPA	(4) NOP, add 4 cycles
		LDX TMPA	(4) increment address
		INX		(3)
		STX TMPA	(4)
		DEC TMPC	(6) decrement counter
		BNE OSSENDBYTE	

*
* Send ONE to Terminate Transmission
*
		LDAA #$FF	end with HIGH
		STAA PORTC
		LDX #TDELAY	
		JSR DELAY
		CLR SFLAG	set SFLAG to indicate success
*
* wait, and go back to beginning
*
* LDAA #$FF	1111 pattern to say done with sending
* STAA PORTB
* LDY #$0700
* JSR YDELAY 
*
* reset PORTC STATE
*
OSSDONE		PULA
		STAA DDRC
		RTS

*****************************************************
*
* PROCEDURE : OSSENDBITS
* sends 8 bits stored in accumulator B
* Y must be set = 8 (number of bits)
* trashes X, A, Y
*
OSSENDBITS	TBA				(2)
		ANDA #$01      get bit to send	(2)
		BEQ OSSENDZERO	if bit=0,	(3)
		LDAA #$FF      send a "1"	(2)
		BRA OSCONTSEND			(3)
OSSENDZERO	LDAA DST	send a "0"	(3)
		COMA				(2)
OSCONTSEND	STAA PORTC			(3)
		LDX #TDELAY
		JSR DELAY
		LSRB				(2)
		NOP				(2) just to add 2 cycles
		DEY
		BNE OSSENDBITS
		RTS

*****************************************************
** ERROR STATES **
** FLAG =$00 = success
**	$01 = failure, no response
**	$02 = line in use already
**	$03 = confirmation signal too long 

OSLINEINUSE	LDAA #$02
		STAA SFLAG
*		LDAA #$FE	1110 light pattern for receiving
*		STAA PORTB
*		LDY #$0700
*		JSR YDELAY 
		BRA OSSDONE
 
OSWRONGCONFIRM	LDAA #$03
		STAA SFLAG
*		LDAA #$FA	1010 for incorrect confirm (didn't go HIGH)
*		STAA PORTB
*		LDY #$0700
*		JSR YDELAY 
		BRA OSSDONE

OSNOCONFIRM	LDAA #$01
		STAA SFLAG
*		LDAA #$F3	0011 for no confirmation from receiver
*		STAA PORTB
*		LDY #$0700
*		JSR YDELAY 
		BRA OSSDONE

* 
**********************************************
** PROCEDURE : OSRECV
** RECV starts here - all labels start with OS
** MUST save all registers, all get trashed
**
** ARGUMENTS:
**	set RFLAG to sources mask 
**		(where bit = 1 if want to receive from that source)
**
** RETURN:
**	sets RFLAG = 0 if success, 
**		   = 1 if no msg or failure
**		   = 2 if COLLISION
**	places msg in RBUF, msg source in SRC
**	places length of MSG in RLEN
**********************************************
**********************************************
**
** Handshake protocol (receiver):
**
**  1. sample line
**  2. if line LOW, then sender trying to send
**  3. sample every TDELAY (= 50) until line HIGH again
**  4. send confirmation: wait TDELAY, hold line LOW for 2*TDELAY, 
**  5. reset to HIGH
**  6. monitor line in a tight loop for start of transmission (i.e. LOW)
**
**********************************************

OSRECV		LDAA DDRC	store old DDRC on stack and restore at end
		PSHA
*
* poll to see if any signal
*
		CLR DDRC		enables reads c0-c3
		LDAA RFLAG		complement RFLAG (for the sources mask)
		COMA
		STAA RFLAG
		LDAA PORTC		poll PORTC
		ORA RFLAG		only care about masked srcs (ie = 0)
		COMA
		BNE OSCHECKSRC		if not zero, then got something
		LDAA #$01		else return 1 for failure
		STAA RFLAG
		JMP OSRECVDONE

OSCHECKSRC	CMPA #$02      
		BEQ OSSRC
		CMPA #$04
		BEQ OSSRC
		CMPA #$08
		BEQ OSSRC
		JMP OSTOOMANYSRC 
OSSRC		STAA SRC		set src of message
*
* wait for sender to release line (i.e. line = HIGH)
*
OSPOLLB
*		LDAA #$FE	1110 to signal got LOW
*		STAA PORTB
		LDAA PORTC	wait for it to go high again
		ANDA SRC
		BNE OSCONFIRM
		LDX #TDELAY
		JSR DELAY
		BRA OSPOLLB

*
* Sending Confirmation of length 2*TDELAY
*
OSCONFIRM
*		LDAA #$F3	0011 to signal start of confirm
*		STAA PORTB
		LDAA #$0E	enables write c1-c3, read c0
		STAA DDRC
		LDX #TDELAY	wait, then send confirmation
		JSR DELAY
		LDAA SRC
		COMA           send LOW 
		STAA PORTC
		LDX #TDELAY2   hold low for 2*TDELAY
		JSR DELAY
		LDAA #$FF      then return to high
		STAA PORTC

*******************************************
*** RECEPTION
*** Recieve bytes in RBUF
*** Number of bytes is recieved in header
*** Synchronize by detecting START ZERO BIT and 
*** moving towards middle of the pulse
*** recieve header byte first and set RLEN
*** Then recieve RLEN bytes, one byte at a time
*******************************************

 		CLR DDRC	enables reads c0-c3
*
* Wait for START ZERO bit
*
		LDY #TDELAY2 
OSTIGHT		LDAA PORTC	tight loop, wait for low (zero)
		ANDA SRC
		BEQ OSSHIFT	got zero - synced
		DEY
		BNE OSTIGHT
		BRA OSNOPREAMBLE   Timeout - did not get the first zero bit 

*
* Shift towards middle of the pulse
* (because you probably detected very close to the edge)
*
OSSHIFT		LDX #TDELAY    delay some time (tdelay comparable to send zero)
		JSR DELAY
		LDX #QTDELAY   delay for 1/4 tdelay
		JSR DELAY

*** NOTE : cycle counting from this point on

*
* READ HEADER = TAG(3):RLEN(5)
*
		LDAB #$00	(2) clear B to receive header
		LDY  #$08	(4)

		JSR OSREADBITS
		STAB RLEN	(3) store TAG:LENGTH
		ANDB #LENMASK	(2) mask out tag bits
*

* setup
*
		STAB TMPC	(3) store counter in memory
		LDX #RBUF	need 2 byte address for indirect addressing
		STX TMPA	copy address of data buffer to TMPA

* 
* Read RLEN * 8 BITS
* each delay should be comparable to send bits
*

OSREADBYTE	LDAB #$00	(2) clear B to receive msg
		LDY  #$08	(4) receive 8 bits
		LDX TMPA	(4) NOP, add 6 cycles
		NOP		(2) 

		JSR OSREADBITS	read 8 bits of data into B

		LDX TMPA	(4)
		STAB 0,X	(4) store B to TMPA
		INX		(3) and increment TMPA
		STX TMPA	(4)
		DEC TMPC	(6) decrement counter
		BNE OSREADBYTE

* END of cycle counting

		CLR RFLAG	success

OSRECVDONE	PULA		restore DDRC
		STAA DDRC
		RTS

*****************************************************
*
* PROCEDURE : OSREADBITS
* reads 8 bits into accumulator B
* Y must be set = 8 (number of bits) and B must be clear
* trashes X, A, Y
*
OSREADBITS	LSRB				(2)
		LDAA PORTC			(3)
		ANDA SRC       bit received	(3)
		BEQ  OSRZERO	if bit=0,	(3)
		ORB  #$80      recv a "1"	(2)
		BRA OSCONTRECV			(3)
OSRZERO		ORB #$00	recv a "0"	(2) [only for cycle counting]
		BRA OSCONTRECV                  (3) [only for cycle counting]
OSCONTRECV	LDX #TDELAY
		JSR DELAY
		CMPA SRC			(3)  NOP, just to add 3 cycles
		DEY
		BNE OSREADBITS
		RTS

*****************************************************
** ERROR STATES **
** FLAG = 0 if error

OSNOPREAMBLE
* LDAA #$F9	1001 to signal no preamble
* STAA PORTB
* LDY #$0F00
* JSR YDELAY 
		LDAA #$01	failure
		STAA RFLAG
		BRA OSRECVDONE

OSTOOMANYSRC
* LDAA #$F6	0110 to signal collision = too many sources
* STAA PORTB
* LDY #$0F00
* JSR YDELAY 
		LDAA #$02	collision failure
		STAA RFLAG
		BRA OSRECVDONE

* 
************************************************
* PROCEDURE: OSPOLL
*
*	Polls for a message from any neighbor
*	Trashes B,X,Y
*	may trash RBUF/RLEN/SRC contents if new message
*
*	ARGUMENTS: CLR RFLAG before calling
*	RETURNS: RFLAG = 0 received message
*		 and SRC=source,RLEN=TAG:LENGTH,RBUF=message
*		(see OSRECV for more details)
*		: RFLAG = 1 no message
*		: RFLAG = 2 collision
*		: does not return if NEW PROGRAM
************************************************
*   polls line for message using OSRECV
*   if RFLAG=0, then checks the TAG
*   if TAG=DATA, simply return to caller
*   if TAG=VERSION, compare version
*      if different, call OSRECVPROG
*   if TAG=OS, perform the OS call indicated in RBUF
************************************************
*
*   Now handles unrestricted RPC requests.
*
************************************************

OSPOLL		PSHA
		LDAA #$0E		check for messages from all neighbors
		STAA RFLAG
		JSR OSRECV		call OSRECV to poll line
		LDAA RFLAG		check for success
		BNE OSPOLLRETURN
*
* check tag
* if = DATA, return to caller
* if = VERSION, goto OSRECVPROG
*
		LDAA RLEN
		ANDA #TAGMASK
		BEQ OSPOLLRETURN	TAG = 0 = DATA, so return
		CMPA #TAGVERSION
		BEQ GOTVERSION		TAG = 001 = VERSION
		CMPA #TAGOS
		BEQ GOTOSCALL		TAG = 111 = OS CALL
		LDAA #$01		TAG = anything else is an error
		STAA RFLAG		    = ignore the data
OSPOLLRETURN	PULA
		RTS

GOTOSCALL	LDAA #$01		return receipt (DATA = 0 - 1 byte)
		STAA SLEN
		LDAA SRC
		STAA DST
		LDAA #OSREQOK
		STAA SBUF		
		CLR SFLAG
		JSR OSSEND		send return receipt

		LDX RBUF
		CMPX #TAGOSRPC		is it an RPC request
		BEQ GOTOSRPC		yes - it's an RPC
		BRA OSPOLLRETURN	there are no other requests as of yet
GOTOSRPC	LDAA RLEN
		ANDA #LENMASK
		CMPA #$08		RPC requests are only 8 bytes long
		BNE OSPOLLRETURN	if not - it's an imposter
		LDAA OSRPCRUNNING	change this to modify max OSRPCRUNNING
		BNE OSPOLLRETURN	another RPC is running, so leave

		INC OSRPCRUNNING	an RPC is running
		LDX RBUF+2		load the address
		LDY RBUF+4		set up registers
		LDD RBUF+6		load the last register
		JSR 0,X			call it
		DEC OSRPCRUNNING	it's no longer running

		LDAA #$01
		STAA RFLAG		act like nothing happened
		BRA OSPOLLRETURN	and return


*
* GOT a VERSION #
* send ack based on comparison with current version #
*
GOTVERSION	LDAA SRC
		STAA DST
		LDAA RBUF		extract version number
		CMPA VERSION
		BNE OSRECVPROG		if different version, then send "yes"
		LDAA #NOACK		setup NO message
		STAA SBUF
		LDAA #$01
		STAA SLEN
		CLR SFLAG
		JSR OSSEND		else same version, so send no ack
		LDAA #$01		ignore message and return
		STAA RFLAG
		PULA		
		RTS			OSPOLLRETURN

*
* Send yes acknowledgement then receive the program
* call OSRECV until see program
*

*
* Count contains the current message number.  Bit 7 is 1 only if this is the
* last message to be sent.

OSRECVPROG	CLR COUNT		starting over if from bad transmit
		LDS #STACK-6		set stack to known state
OSRPBIGLOOP	INC COUNT		start with one
		LDAA COUNT
		STAA PORTB

		CMPA #$01		is this the first time?
		BNE OSRPSENDACK		if not, send count
		LDAA #YESACK		setup YES message (diff version #'s)
OSRPSENDACK	STAA SBUF		send one byte of data to DST
                LDAA #$01
		STAA SLEN
		CLR SFLAG
		JSR OSSEND

		LDX #$FFFF		wait 65535 times for program message
OSRPGETMESSAGE	LDAA DST		get program only from sender
		STAA RFLAG		by setting RFLAG mask
		PSHX
		JSR OSRECV
		PULX
		LDAA RFLAG
		BEQ OSRPGOTMESSAGE	have I got the message
		DEX			if not, time out
		BEQ OSRUNUSERPROG       if timed out, try to run the program
		BRA OSRPGETMESSAGE	otherwise, try again
OSRPGOTMESSAGE  LDAA RBUF
		TAB
		ANDB #$7F		strip bit 7
		CMPB COUNT		are they in sync?
		BNE OSRUNUSERPROG       no - try to run program
		STAA COUNT		yes they are in sync - good!
		LDAA DST		save destination (wiped out by RAMPROG)
		PSHA			

*******************************************
* Program has been recieved
* copy New Program to EEPROM
* CHANGE LATER TO GET THE PROGRAM IN CHUNKS
* 
* RAMPROG = RAM program that copies RBUF contents to EEPROM
* First place RAMPROG in RAM (at location LOCRAMPROG)
* Then transfer execution to RAM (jsr LOCRAMPROG)
* copy RBUF contents to USERPROG
* return execution to EEPROM (rts)
* then clear stack of OSPOLL return address and jump to USERPROG
*******************************************

*
* copy RAMPROG to EEPROM
*

		LDD #RAMENDPROG
		SUBD #RAMBEGINPROG  RAMPROG must be < 256, so
		TBA		    put low 8 bits of program length in A
		LDX #RAMBEGINPROG   x = EEPROM address to read RAMPROG program
		LDY #LOCRAMPROG     y = RAM address to store program
		JSR OSCOPY


* locate version number - try to send to neighbors


*
* execute program in RAM
*
OSRUNPROG	LDX #LOCRAMPROG     start address of RAM program
		JSR 0,X             jump to RAM subroutine
		PULA		    restore the destination
		STAA DST		(wiped out by RAMPROG)
		LDAA COUNT	    so, are we done?
		BNE OSRPBIGLOOP     bottom of loop
		LDS #STACK	    restore stack to good condition

*
* returned from RAM
*

OSRUNUSERPROG	LDAA EECOUNT	    check to see if program is valid
		BEQ OSRUPGOOD	    if not, far jump to RPC Request Program
		STAA PORTB	    flash count #
		JMP OSREQPROG       ask for program
OSRUPGOOD	LDAA USERPROG       load version number
                STAA VERSION        store program version number in heap
		STAA PORTB	    display VERSION #
		CLR DDRC	    enable reads from c0-c3

		LDX #$0200	    run OSSENDPROG 512 times
OSRUPSPLOOP	PSHX
		JSR OSSENDPROG	    attempt to send program to neighbors
		PULX
		DEX
		BNE OSRUPSPLOOP

		CLRB		    initialize everything
		CLRA
		CLR PORTB
		CLR RBUF            no RPC calls can be running while
		CLR OSRPCRUNNING    a new program is loaded

		LDX #USERPROG+1
		JMP 0,X		    start newly loaded user program


***-------------------------------------------***
* Beginning of RAM program to copy msg to EEPROM
***-------------------------------------------***

RAMBEGINPROG	BSR RAMCOPYCOUNT    save count - program about to be written
		LDX #RBUF+1	    copy from RBUF, skip over the count
		LDAA COUNT	    calculate place to put in memory
		ANDA #$7F	    mask off high bit
		DECA                formula: (COUNT-1)*(LENMASK-1)+#USERPROG
		LDAB #LENMASK-1	    
		MUL
		ADDD #USERPROG      +#USERPROG
		XGDY		    store the address to copy to
RAMGOTINDX	LDAA RLEN
		DECA		    count is not copied and takes a byte
		ANDA #LENMASK	    A = length
		BSR RAMWRITE        copy it
		LDAA COUNT          check to see if transfer done
		ANDA #$80
		BEQ RAMRETURN       if not, just return
		CLR COUNT	    clear the count - transfer done
		BSR RAMCOPYCOUNT    store it in EEPROM
RAMRETURN	RTS		    return to EEPROM caller

RAMCOPYCOUNT	LDX #COUNT
		LDY #EECOUNT
		LDAA #$01
		BSR RAMWRITE
		RTS

RAMWRITE	LDAB #$16
		STAB PPROG	    set to BYTE erase mode
		STAB 0,Y	    write junk data to address to be erased
		INCB
		STAB PPROG	    turn on high voltage
		BSR RAMWAIT10MS	    wait 10ms
		CLR PPROG
		LDAB #$02
		STAB PPROG          set to BYTE program mode
		LDAB 0,X	    get byte from RAM
		STAB 0,Y	    write byte into EEPROM
		LDAB #$03
		STAB PPROG	    set EELAY and EEPGM
		BSR RAMWAIT10MS	    wait 10ms
		CLR PPROG		
		INY
		INX
		DECA		
		BNE RAMWRITE	    continue to next loop iteration
		RTS

RAMWAIT10MS	PSHX
		LDX #D10ms
RAMWAITLOOP	DEX
		BNE RAMWAITLOOP
		PULX
		RTS

RAMENDPROG	NOP

* 				
************************************************
* PROCEDURE: OSSENDPROG
* 
* attempt to send a program to all your neighbors
* ARGUMENTS :
* RETURNS: nothing 
*
* foreach neighbor
*	send version number
*	  get back yes/no (abort after timeout)
*	  if yes, copy userprog into SBUF and OSSEND
*       
*************************************************

*
* STEP 1: Send Version Number
* loop through neighbors to see if anyone needs a new program
*

OSSENDPROG	LDAB #$02		loop through all neightbors
		LDAA EECOUNT		check to see if program is valid
		BNE OSSENDPGMRET	don't send it if it ain't valid

NBRLOOP		LDAA VERSION		SBUF = VERSION number
		STAA SBUF
		LDAA #$01	length of the message = 1 (for version #)
		ORA #TAGVERSION	
		STAA SLEN
		STAB DST		attempt to send to all 3 neighbors
		PSHB			push B on stack
		CLR SFLAG
		JSR OSSEND		SEND version number
		LDAA SFLAG		if send was successful, wait for ack
		BNE DONTTRANSMIT
		CLR COUNT
		LDX #$1000		poll 4096 times for initial ack
WAITACKLOOP	LDAA DST		only listen to msgs from destination
		STAA RFLAG
		PSHX			push X on stack
		JSR OSRECV
		PULX			restore value of X
		LDAA RFLAG		check if received successfully
		BEQ ACKRECEIVED
		DEX			poll for ack again
		BNE WAITACKLOOP

*
* Neighbor did not respond 
*
DONTTRANSMIT	LDAA #$F6		show 0110 if not successful

*
* Try the next neighbor
*
SENDNEXTNBR	PULB			restore value of B for counting nbrs
		LSLB
		CMPB #$10		sent to all 3 neighbors
		BNE NBRLOOP
OSSENDPGMRET	RTS

*
* if ack = yes, then transmit program
*
ACKRECEIVED	INC COUNT		start with one
		LDAA COUNT
		CMPA #$01		is it the first time - yesack
		BEQ YESACKRECV		
		CMPA RBUF		in sync?
		BEQ OSSENDPROGBYTES	yes - go ahead
		PULB			no - restore count
		BRA NBRLOOP		try the whole thing again
YESACKRECV	LDAA #YESACK		
		CMPA RBUF		YESACK received?
		BNE SENDNEXTNBR		if not, go to the next neighbor

OSSENDPROGBYTES LDAA COUNT
		STAA PORTB
		DECA
		LDAB #LENMASK-1
		MUL
		ADDD #USERPROG
		XGDX
OSSPCHKEND	PSHX
		XGDX
		PULX
		ADDD #LENMASK-1
		CPD #USERPROGEND
		BLO OSSPSEND
		LDAA COUNT
		ORA #$80
		STAA COUNT
OSSPSEND	LDY #SBUF+1	Y stores the send buffer address
		LDAA #LENMASK	A stores the counter
		TAB 
		ORB #TAGPROGRAM	
		STAB SLEN	store the length + tag of the message
		DECA
		JSR OSCOPY	length to copy is one less (minus count)
		LDAA COUNT
		STAA SBUF	store COUNT as first byte
		CLR SFLAG	
		JSR OSSEND	send message
		LDAA COUNT
		ANDA #$80	is it the last message?
		BNE SENDNEXTNBR	if so, go to the next neighbors 
		LDX #$FFFF	poll 65535 times while neighbor is processing
		BRA WAITACKLOOP   for another (mid-program) ack

*****************************************************
* 
* Utilities
*
*****************************************************

* 
************************************
*
* PROCEDURE: OSCOPY
*
*  args: X = from address
*        Y = to address
*        A = number of bytes
************************************

OSCOPY		LDAB 0,X
		STAB 0,Y
		INY
		INX
		DECA		
		BNE OSCOPY
		RTS


** DELAY PROCEDURES **

* 
* DELAY delays for X

DELAY		DEX
		BNE DELAY
		RTS

* 
* DELAYPOLL delays for Y=700 and polls for programs.
*

DELAYPOLL	STAA PORTB
		LDY #$0700
DPOLLLOOP	LDX #$00FF
		BSR DELAY
		PSHY
		CLR RFLAG
		JSR OSPOLL
		PULY
		DEY
		BNE DPOLLLOOP
		RTS

* 
* LIGHTDELAY shows lights in A, and then delays for Y=0700.
* It does not poll.
*

LIGHTDELAY	STAA PORTB
		LDY #$0700
* 
* Y*256 CONTAINS THE FACTOR
YDELAY		LDX #$00FF    (Also called by OS)
		BSR DELAY
		DEY
		BNE YDELAY
		RTS

* 
************************** DELAYINT *******************************
* Delay, but be open to INTerruptions (ie. DATA) coming in
* This delay will automatically change the phase of reception.
* 
* Requires:
*   B=0 Assume a standard delay of $0400, and display A in lights
*   B=1 Specify a delay factor
*   Y=  Delay factor if B=1
* Returns:
*   B=0 Nothing interesting happened
*   B=1 A message was received (SRC contains source)
*   B=2 A new message was received
*   B=3 The new message has a different stamp on it
*   B=4 The light sensor was activated
*   B=5 The button was pressed
*   Y=  When interruption occurred
*******************************************************************

DELAYINT	CMPB #$01
		BEQ DINTLOOP
		STAA PORTB
		LDY #$0400
DINTLOOP	PSHY
		JSR POLLNEWMESSAGE
		PULY
		CMPB #$00
                BNE DINTMESSAGE
		BSR SENSOR
		CMPB #$00
		BNE DINTSENSE
		PSHY
		PULX
		BSR DELAY
		DEY
		BNE DINTLOOP
		CLRB                  Nothing interesting happened	
		RTS
DINTSENSE	ADDB #$03	      A sensor was hit
DINTMESSAGE	RTS		      A message was received

* 
* SENSOR returns:
*	B=0  Nothing interesting happened
*	B=1  The light sensor was hit
*	B=2  The button was pressed
*

SENSOR		LDAB PORTC
		BITB #$01
		BEQ SENSELIGHT		
		BITB #$80
		BEQ SENSEBUTTON
		CLRB
		RTS
SENSEBUTTON	LDAB #$02
		RTS
SENSELIGHT	LDAB #$01
		RTS


* 
* LESSAB returns the lessor of A and B in A and the greator in B
*        this SHOULD be a machine-language instruction!
*

LESSAB		CBA
		BLS LESSRETURN
		PSHB
		TAB
		PULA
LESSRETURN	RTS

*
* Broadcast messages
*

* 
* RESEND broadcasts the message in RBUF
* 
* Requires:	
*	Y= How many times to broadcast
* Returns:
*	B=0  Nothing interesting happened
*	B=1  A message was received
*	B=2  A new message was received
*       B=3  The new message has a different stamp
*	B=4  The light sensor was hit
*       B=5  The button was pressed
*	Y=   When the interruption occurred
*

RESEND		PSHA
		PSHY
		LDX #RBUF
		LDY #SBUF		
		JSR MSGCOPY
		LDAA RLEN
		STAA SLEN
		CLRB
		PULY
		JSR BROADCAST
		PULA		
		RTS

* 
* STAMP identifies this machine as the originator of the message in SBUF.
*

STAMP		PSHA
		PSHB
		INC MSGID		new MSGID for new message
		LDAA MSGID
		STAA OUTMSGID		stamp message ID
		LDD SENDID		
		STD OUTMSGSENDID	stamp machine ID
		PULB
		PULA
		RTS

* 
* Send an OS Remote Procedure Call (proxy) to invoke any (unrestricted) 
* subroutine on another machine.
*

*
* OSRPC requires destination in DST
*	X=address for remote machine to JSR to (preserved)
*       A,B,Y are copied to remote machine
*	if DST = 0, then the message is broadcasted
*
* Returns:
*	B=0 RPC received successfully
*	B=1 RPC timed out (approx. 1 second)
*	B=2 RPC misinterpreted (uh-oh!)


OSRPC		PSHA
		PSHX
		PSHY
		STX SBUF+2		store address for remote machine
		STY SBUF+4		mirror Y on other end
		STD SBUF+6		mirror A, B on other end
		LDX #TAGOSRPC		invoke a remote subroutine
		STX SBUF		put the OS call in the buffer
		LDAA #$08		8 byte message
		STAA SLEN
		JSR OSREQUEST		make the request
		PULY
		PULX
		PULA
		RTS

*
* Examples of RPC:
*

* 
* OSREQPROG requests a program to be transferred and never returns
*

OSREQPROG	LDX #OSSENDPROG
		CLR DST
		BSR OSRPC
		JSR DELAYPOLL
		BRA OSREQPROG

* 
* OSSETRAM stores the value of A in the memory address pointed to by Y 
*   used by RPC to set memory locations
*
* To set a memory location, simply set DST to neighbor or 0 to broadcast:
*	LDX #OSSETMEM
*	JSR OSRPC
*

OSSETRAM	STAA 0,Y
		RTS

* 
* OSREQUEST sends an OS request and waits for a return receipt 
*	DST=destination, if DST=0, message is broadcasted
*	SBUF=message
*
* Returns:
*	B=0 Request received successfully
*	B=1 Request timed out (approx. 1 second for broadcast)
*	B=2 Request misinterpreted (uh-oh!)
*

OSREQUEST	PSHA
		LDAA SLEN
		ORA #TAGOS		tag it as an OS request
		STAA SLEN
		LDAA #OSREQOK
		LDY #$0100
		JSR SENDCHECKRET
		PULA
		RTS

* 
* SENDCHECKRET
*
* Broadcast or send a message while waiting for a return receipt
*
* Requires:
*	A=return receipt to check for
*	Y=timeout
*	SBUF=message to send
*	DST=destination, if DST=0 then the message is broadcasted
*

SENDCHECKRET	PSHA
		LDAA DST		is DST=0?
		BEQ SCHKBROAD		broadcast
SCHKSEND	PSHY	
		CLR SFLAG		otherwise, just send it to DST
		JSR OSSEND		send it
		LDAA DST
		STAA RFLAG		
		JSR OSPOLL		check for response (only from DST)
		PULY
		LDAA RFLAG		
		BEQ SCHK		message received
		DEY
		BNE SCHKSEND		not time out - try again
		BRA SCHKTIMEOUT		timed out
SCHKBROAD	CLRB			message in SBUF
		BSR BROADCAST		broadcast it
		CMPB #$00
		BEQ SCHKTIMEOUT		timed out
		CMPB #$04		sensor hit
		BHS SCHKBROAD		try it again until timeout
SCHK		LDAA RLEN		message received
		CMPA #$01		one byte of data?
		PULA
		BNE SCHKMIS		no - message misinterpreted
		CMPA RBUF		correct return receipt?
		BNE SCHKMIS
		CLRB			successful
		RTS
SCHKMIS		LDAB #$02		message has been misinterpreted
		RTS			uh-oh
SCHKTIMEOUT	PULA			return stack
		LDAB #$01		timed out
		RTS

* 
****************************************************************************
* BROADCAST requires:
*	B=0  Broadcast a message in SBUF of length SLEN
*	B=1  Broadcast a number in A (preserves A) 
*       Y=   How many times to broadcast (#$1000 takes approx. 10 sec.)
* It continuously broadcasts and returns:
*	B=0  Nothing interesting happened
*       B=1  A message was received
*	B=2  A new message was received
*       B=3  The new message has a different stamp
*	B=4  The light sensor was hit
*	B=5  The button was pressed
*	Y=   When the interruption occurred
*
* This section would, ideally, become a background task kicked off or managed
* from a high level by the program and run by the OS using interrupts or a 
* separate thread.
****************************************************************************

BROADCAST	PSHA			Load B into X
		CLRA
		XGDX
		PULA
BLOOP		PSHY
		PSHX
		DEX                     Figure out what you're broadcasting.
		BEQ BNUM
		BSR BROADMESS
		BRA BPOLL
BNUM		BSR BROADNUM
BPOLL		BSR POLLNEWMESSAGE
		PULX
		PULY
		CMPB #$00	
		BNE BRETURN		A new message came in
		JSR SENSOR
		CMPB #$00
		BNE BSENSE
		DEY
		BNE BLOOP
		CLRB			Nothing interesting happened
BRETURN		RTS
BSENSE		ADDB #$03
		RTS

*
* BROADNUM takes a number in A to broadcast (preserves A)
*

BROADNUM	PSHA
		STAA SBUF
		LDAA #$01
		STAA SLEN
		BSR BROADMESS
		PULA
		RTS

*
* BROADMESS trashes all reg's - need to add error detection/handling
* BROADMESS takes:
*      length of MSG in SLEN
*      msg in SBUF
*

BROADMESS	LDAB #$02		loop through all neighbors
NEIGHBORS	PSHB
		CLR SFLAG
		STAB DST                send to all three neighbors
		JSR OSSEND
		PULB
		LSLB		
		CMPB #$10
		BNE NEIGHBORS
		RTS

* 
* POLLNEWMESSAGE takes a message in RBUF and uses MSGCOMPARE to compare it
* with the new message coming in.
*
* Returns:
*	B=0  no message received
*	B=1  message received (hmmm... broken???)
*	B=2  new message received
*	B=3  new message has different stamp
*	trashes X, Y
*

POLLNEWMESSAGE	LDX #RBUF		Save the message
		LDY #TMPMESSAGE
		PSHA
		PSHX
		PSHY
		LDAA RLEN	
		ANDA #LENMASK
		JSR OSCOPY              Copy it
		CLR RFLAG
		JSR OSPOLL		Poll for messages
		PULY
		PULX
		LDAA RLEN
		ANDA #LENMASK
		LDAB RFLAG
		BNE PNOMESSAGE		Was there a message?
		BSR MSGCOMPARE		Is it the same as the old RBUF?
PMESSAGE	INCB
		PULA
		RTS
PNOMESSAGE	CLRB
		PULA
		RTS

* 
* MSGCOMPARE requires:
*	X=Pointer to first message
*	Y=Pointer to second message
*	A=Length of message
* and returns:
*	B=0 messages are the same
*	B=1 messages are different
*	B=2 messages have different stamps
*

MSGCOMPARE	PSHA
		ANDA #LENMASK		Mask off type
		BSR OSCOMPARE
		CMPB #$00		Are the two messages the same?
		BEQ MSGCOMPRETURN
		PSHX			Check stamps
		PSHY
		XGDX			
		ADDD #OUTMSGID-#SBUF
		XGDX
		XGDY
		ADDD #OUTMSGID-#SBUF
		XGDY
		LDAA #$01
		BSR OSCOMPARE
		CMPB #$00		Are the two message ID's the same
		PULY
		PULX
		BNE MSGDIFFSTAMP
		PSHX
		PSHY
		XGDX
		ADDD #OUTMSGSENDID-#SBUF
		XGDX
		XGDY
		ADDD #OUTMSGSENDID-#SBUF
		XGDY
		INCA			This one is two bytes
		BSR OSCOMPARE
		PULY
		PULX
		INCB
		CMPB #$01		Are the two sender ID's the same
		BEQ MSGCOMPRETURN		
MSGDIFFSTAMP	LDAB #$02
MSGCOMPRETURN	PULA
		RTS

* 
* MSGCOPY takes a message pointed to by X and copies it to Y
*

MSGCOPY		PSHA
		LDAA #LENMASK
		JSR OSCOPY
		PULA
		RTS

* 
* OSCOMPARE compares two buffers pointed to by X and Y, of length A
* and returns:
*		B=0 buffer contents are the same
*		B=1 buffer contents are different
*

OSCOMPARE	PSHX
		PSHY
		PSHA
OSCOMPLOOP	LDAB 0,X
		CMPB 0,Y
		BNE OSCOMPDIFF
		INY
		INX
		DECA		
		BNE OSCOMPLOOP
		CLRB			The messages are the same B=0
		BRA OSCOMPRETURN
OSCOMPDIFF	LDAB #$01		The messages are different B=1
OSCOMPRETURN	PULA
		PULY
		PULX
		RTS

*
* User configuration section - routines to allow user to configure demo
*

* 
* SETNUM allows the user to set the number in A
*   (light increments number, button sets it)
*

*
* CONFIGNUM applies the mapping below to the number obtained by SETNUM
*
* Requires: number to change in B
* Returns:  changed number in B    
*
* Note: B is used to facilitate further mappings with the D register
*

SETNUM		STAA PORTB		display the number
		LDY #$0400		pick a pleasing amount of time to
		JSR YDELAY		delay for cycle to pick number
SETSENSE	JSR SENSOR
		CMPB #$01		the light was hit
		BNE NOLIGHT
		INCA
		ANDA #$0F
		BRA SETNUM
NOLIGHT		CMPB #$02		button was hit, so end
		BNE SETSENSE		
		RTS

DONE		BRA DONE       DONE has to be at the end of the file
		ORG $FFFE
		FDB RESET      
*