; -------------------------------------------------------------
; A PIC based version of the TRIKS-C "LEDTRIKS" driver board.
;
; Based reviews of the JEC Pixel FW, Renard FW, and Triks-C FW  
;                                                                          
; (c) 2009, 2010 Andrew Williams, Just Some Guy Productions
;
;
; Originally designed for the 16F688
;
; ---
; Version 3.0 - 2010-09-08 First public release
;
;
;
; -----------------------------
; PORT     PIN      DESCRIPTION
; -----------------------------
; A0        13      SELECT_IN
; A1        12      AUTO_FEED
; A2        11      DATA_STROBE
; C0        10      DATA0
; C1        9       DATA1
; C2        8       DATA2
; C3        7       DATA3
; C4        6       SERIAL TX
; C5        5       SERIAL RX
; MCLR      4       
; A4        3       INIT
; A5        2       STATUS_LED
; GND       14      GND
; VCC       1       Vcc
;

        list      p=16F688      		; list directive to define processor
        #include <p16F688.inc>			; processor specific variable definitions
        errorlevel  -302        		; suppress message 302 from list file

	__CONFIG _FCMEN_OFF & _IESO_OFF & _BOD_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_OFF & _WDT_OFF & _INTOSCIO

; OSC = INTOSCIO
; Watchdog = Disabled
; Power up Timer  = Disabled
; MCLR = Reset
; Brownout = Disabled, SBODEN disabled
; Switchover = Disabled
; Failsave = Disabled
; Code = As needed
; EEPROM = As needed
; bits should be 30F4

#define USE_MSB_ORDER

	; -------------------
	; BANK0 Memory Block
	; -------------------        
	CBLOCK 0x20
		; Top of "Image Frame"
		Fr0Row0:6		; Point to start of the buffer
		Fr0Row1:6
		Fr0Row2:6
		Fr0Row3:6
		Fr0Row4:6
		Fr0Row5:6
		Fr0Row6:6
		Fr0Row7:6
		Fr0End:0		; Point to the end of the buffer, for reverse access

		; INT output routine for BANK0 access
		outByte			; The character being clocked out
		outBitCount 	; 0..7 - loop though bits in the byte
		outColumnCount	; 0..5 - loop through bytes in the column

		
		smSTATE		; ADDR of State Machine handler
		cmdPENDING	; Pending commands require a PAYLOAD to exist before
					; we do anything, this variable records what command
					; is "pending" when the payload is completly loaded.
					; Value of the PENDING command
					; Note PENDING_0 = PikC CONFIG
					;      PENDING_5 = Frame BANK0
					;      PENDING_6 = Frame BANK1
		payloadCount; # of bytes remaining to received in the payload.
		rxBYTE		; Command Byte received (not sure this is needed)
		pikcADDR	; For matching address from the TRIX-C commands
		gSTATUS		; 8 Bits of globals
		gAloneCount ; Count number of TIMER1 ticks
		gAloneFrame	; Which frame to display 

		; Wait/Loop timer/counters
		COUNT
 		timer
        end_bank_0_vars:0	
	ENDC
    if end_bank_0_vars > 0x70
              error "Bank0 variable space overrun"
    endif

	; -------------------
	; BANK 1 Memory Block
	; -------------------
	CBLOCK 0xA0
		Fr1Row0:6		; Point to start of the buffer
		Fr1Row1:6
		Fr1Row2:6
		Fr1Row3:6
		Fr1Row4:6
		Fr1Row5:6
		Fr1Row6:6
		Fr1Row7:6
		Fr1End:0		; Point to the end of the buffer, for reverse access

        end_bank_1_vars:0	
	ENDC
    if end_bank_1_vars > 0xF0
              error "Bank1 variable space overrun"
    endif

	; -------------------
	; Global Memory Block
	; -------------------
	CBLOCK 0x70
        wsave   ; Save W, STATUS, and PCLATH on entry to interrupt
        ssave   
        psave
		fsrsave
		temp
		outRowIndex		; 0..15 - index of row being written.
		outRowMapped	; Inverted Nibble

		; --- The rxBuffer --- 
		; Multi-Purpose RAM space
		; For Roll Left/Right
		;   rxBuffer:0 = Row Counter
		;   rxBuffer:1 = Column Counter
		;   rxBuffer=4 = Frame1 Input Data
		;   rxBuffer=6 = Frame0 Input Data
		; For Roll Up/Down 
		;   rxBuffer[0..5] = Incoming Data
		rxBuffer:0
			row_count:1
			column_count:1
			bitShifter:1
			voldemort:1		; The BYTE that shall not be named
			input2:1
			input1:0		; Maps onto rxBufferEnd
		rxBufferEnd:1 		; Point to last BYTE of rxBuffer
		; MemCopy variables
		memcpy_i
		memcpy_a
		memcpy_b
        end_global_vars:0	
	ENDC
    if end_global_vars > 0x80
              error "Global Variable Space overrun"
    endif	


; -----------------------------------
; Macro's to help with BANK selection
; -----------------------------------
#define   BANK0   bcf STATUS,RP0
#define   BANK1   bsf STATUS,RP0

FRAMESIZE 			EQU	d'96'
HALFFRAMESIZE 		EQU	d'48'

; -----------------------------------
; Global Status Bits (gSTATUS)
; -----------------------------------
g_SHOW  			EQU		d'0'
g_ESCAPE			EQU		d'1'
g_STANDALONE		EQU		d'2'


; ---------------------------------
; Triks-C commands 
; 0b 1CCCCxxx - C=Channel x = CMD
; ---------------------------------
; Trik-c backwards compatability
;
;   Cmd_DISP_OFF  		EQU	h'00'
;   Cmd_ROLL_L    		EQU	h'01'
;   Cmd_ROLL_R    		EQU	h'02'
;   Cmd_ROLL_U    		EQU	h'03'
;   Cmd_ROLL_D    		EQU	h'04'
;   Cmd_FRAME     		EQU	h'05'
;   Cmd_CLR_FRAME 		EQU	h'06'
;   Cmd_DISP_ON   		EQU	h'07'
;
; ---------------------------------
; Pik-C commands 
; 0b 0CCCCxxx - C=Channel, x=CMD
; ---------------------------------
;   (payload size in brackets)
;   FRAME_SELECT - read the frame from the ROM/EEPROM(1)
;   FRAME_EE_STORE - write the frame to the EEPROM   (1)
;
;   Cmd_FRAME_SELECT	EQU	h'01'
;   Cmd_FRAME_EE_STORE	EQU	h'02'   I changed this.. need to update the "PENDING" state machine
;
;  Note: No PIX-C cmd 5 or 6 as these are SYNC and ESCAPE characters

; ---------------------------------
; Triks-C Broadcast commands 
; 0b 10000xxx - x=CMD
; ---------------------------------
;   (payload size in brackets)
;   STAND_ALONE                                      (0)
;   Cmd_STAND_ALONE     EQU h'01'

; ---------------------------------
; Pix-C Broadcast commands 
; 0b 00000xxx - x=CMD
; ---------------------------------
;   (payload size in brackets)
;   PIKC_CONFIG - program the device address         (6)
;      expect payload= 50h,49h,58h,2Dh,43h,xx
;      xx = panel address
;   Cmd_CONFIG			EQU	h'01'
;

; ------------------------------------
; Constant Definitions to map function
; to the associated PORT. 
; ------------------------------------
#define		mDATA0 		PORTC,0			; DATA0
#define		mDATA1 		PORTC,1			; DATA1
#define		mDATA2 		PORTC,2			; DATA2
#define 	mDATA3 		PORTC,3			; DATA3


#define 	mROWLATCH	PORTA,0			; Latch ADDR from PORTC0-3
#define 	mSHIFTLATCH	PORTA,1			; Latch COLUMN data already CLOCKED out
#define		mSHIFTCLOCK	PORTA,2			; DATA_STROBE
#define		mINHIBIT	PORTA,4			; INIT
#define		mSTATUS_LED	PORTA,5			; STATUS LED for development

; ------------------------------------
; Memory map of the EEPROM
; ------------------------------------
EE_PIKC_FRAME0 		EQU D'0'
EE_PIKC_FRAME1 		EQU D'160'
EE_PIKC_ADDR 		EQU	D'96'

; ------------------------------------
; Constant Definitions SERIAL PROTOCOL  
; ------------------------------------
RX_SYNC 		EQU	 h'7E' 
RX_PAD  		EQU	 h'7D' 
RX_ESC			EQU	 h'7F' 

; ------------------------------------
; MACRO Definitions 
; ------------------------------------
chgState macro newState		 
		movlw	newState
		movwf	smSTATE
   endm

;branch not equal
bne     MACRO fr1,fr2,address
		movf	fr2,W
		subwf	fr1,W
		btfss	STATUS,Z
		goto address
	endm

bnel     MACRO fr1,literal,address
		movf	fr1,W
		sublw	literal
		btfss	STATUS,Z
		goto address
	endm

;branch if equal
beq     MACRO fr1,fr2,address
		movf fr2,W
		subwf fr1,W
		btfsc STATUS,Z
		goto address
	endm

beql     MACRO fr1,literal,address
		movf fr1,W
		sublw literal
		btfsc STATUS,Z
		goto address
	endm

; ----------------------------------------------
; Start of the "CODE" section 
; ----------------------------------------------
	ORG 0x000                      		; Main Program

        clrf PCLATH
        goto start

	ORG 0x004                       	; Interrupt handler goes here

intHandler
		movwf   wsave                   ; Store the usual bits when interrupting
		swapf   STATUS, w
		clrf    STATUS
		movwf   ssave
		movf    PCLATH, w
		movwf   psave
		movf	FSR,w					; Also store the FSR
		movwf	fsrsave

	; Actually output the DATA
		btfss	gSTATUS,g_SHOW
		goto	irqFrameDone

	; Determine the ROW and set FSR to point to it. 
		movf	outRowIndex, W
		movwf	outRowMapped

	BANKISEL Fr0Row0 ; DEBUG
		; Determine if this is Frame0 or Frame1
		btfsc	outRowMapped,3			; Check for larger than 7 (Second Frame)
	BANKISEL Fr1Row0
		call	getRowPtr ; Map out line counter to the "OUTPUT LINE" 
		movwf	FSR

irqDoRow
	; For each byte in the row...
	; Clock out the BITs (LSB/MSB first - check compile flag)
		movlw	d'6'
		movwf	outColumnCount
irqDoByte
		movlw 	d'8'
		movwf	outBitCount
		movf	INDF,W
		movwf	outByte
irqDoBit
		bcf		mDATA0
#ifdef USE_MSB_ORDER
		rlf		outByte,F ; Shift and store in outByte
#else
		rrf		outByte,F ; Shift and store in outByte
#endif
		btfsc 	STATUS,C  ; Skip if CARRY bit is CLEAR
		bsf		mDATA0
		; Clock the Latch line
		bcf		mSHIFTCLOCK
		bsf		mSHIFTCLOCK	 	; Clocks the data out
		decf	outBitCount,f	;
		btfss	STATUS,Z		; Skip if we're down to zero
		goto	irqDoBit
	
		incf	FSR				; Goto the Next Byte
		decf	outColumnCount,F
		btfss	STATUS,Z		; Skip if we're down to zero
		goto 	irqDoByte

	; Output the ROW onto the PORTC0.. PORTC3
		movf	PORTC,W 		; Read PORTC
		ANDLW	h'F0'			; Clear the bottom 4 bits
		IORWF	outRowMapped,W
	; Inhibit the display
		bsf		mINHIBIT
		movwf	PORTC
	
	; Latch the rows
		bsf 	mROWLATCH
		bcf 	mROWLATCH

	; Latch the columns
		bsf		mSHIFTLATCH
		bcf 	mSHIFTLATCH

		ANDLW	h'F0'			; Clear the bottom 4 bits
		movwf	PORTC

	; RE-enable the display
		bcf 	mINHIBIT
		incf	outRowIndex,F
		btfsc	outRowIndex,4	; Do out MOD operation. 
		clrf	outRowIndex		; When we get to 16 CLEAR it back to 0
	
irqFrameDone
; ------- Actual Interrupt Routine Here --------------------
		;movlw   D'223'                  ; TMR0 will roll over every 40.0 uS
		movlw   D'0'                  ; TMR0 ??
		movwf   TMR0                    ; 
    
; ------- Actual Interrupt Routine Ends --------------------
intHandlerExit 
		BCF     INTCON,T0IF             ; Clear the TMR0 interrupt flag
		movf	fsrsave,w				; Re-Store the FSR
		movwf	FSR						;
        movf    psave,w                 ; Restore whatever was happening prior
        movwf   PCLATH                  ; to the interrupt
        swapf   ssave,w                 ; 
        movwf   STATUS
        swapf   wsave,f
        swapf   wsave,w

        retfie
;----------
; getRowPtr
; return pointer to start of the row
; *fastest method = lookup table
getRowPtr
	andlw	h'0F'
	addwf   PCL      
	retlw	Fr0Row0	
	retlw	Fr0Row1	
	retlw	Fr0Row2	
	retlw	Fr0Row3	
	retlw	Fr0Row4	
	retlw	Fr0Row5	
	retlw	Fr0Row6
	retlw	Fr0Row7
	retlw	Fr1Row0	
	retlw	Fr1Row1	
	retlw	Fr1Row2	
	retlw	Fr1Row3	
	retlw	Fr1Row4	
	retlw	Fr1Row5	
	retlw	Fr1Row6
	retlw	Fr1Row7	

; -----------------------------------------------------------------------------
; ----------------------- Main Program Starts Here ----------------------------
; -----------------------------------------------------------------------------
start:
    	call    pikcInit                ; Initialize pins, oscillator, etc

; ---------------
; Serial Rx Loop 
; ---------------
mLoop
	BANKSEL PIR1
		btfss		PIR1,RCIF 					; Has a Byte arrived?
		goto		mLoop_Czeck_Standalone
	
		movlw		d'64'						; Restart the StandAlone countdown
		movwf		gAloneCount
		movlw		d'02'						; Skip the two LABRAT splash screens
		movwf		gAloneFrame

 		movf    	RCREG,W     				; Then, capture & move to 'w'...  
		movwf		rxBYTE						; Store the BYTE for comparison

		movlw		d'6'						; Rx error mask (framing error, overrun error)
		andwf		RCSTA,w						; get (masked) rx status
		btfss		STATUS,Z
		goto		rxError						; goto error routine
		beql		rxBYTE,RX_PAD,mLoop 		; Ignore PAD bytes 

		movf		rxBYTE,W					; Echo the character to the serial port
		movwf		TXREG

		; BugFix : 2010-08-17 PIX-C would lock up when parsing data for a different
 		; panel in the network. Issue was that ESCAPE encoded data in the stream was
		; being interpreted as a SYNC. 
		; Resolution: do not allow escape encoded sequences when waiting for a SYNC
		beql		smSTATE,smWait4Sync,smWait4Sync

		btfsc		gSTATUS,g_ESCAPE			; Is there an Escape pending?
		goto		rxEscapeData
		beql		rxBYTE,RX_ESC,rxEscape		; Is this an Escape character?
		movf		smSTATE,W					; Jump to STATE, and let it handle the rxBYTE
		movwf		PCL

rxEscape
		bsf			gSTATUS, g_ESCAPE			; Record that we have an ESCAPE pending
		goto		mLoop

rxEscapeData
		bcf			gSTATUS, g_ESCAPE			; Stop waiting on the ESCAPE encoded byte
		movf		rxBYTE, w					; Calculate the "Escape Encoded" value
		addlw		h'4E'						; Maps 2F::7D, 30::7E, 31::7F
		movwf		rxBYTE						; Place the results in the BYTE
		movf		smSTATE,W					; Jump to STATE, and let it handle the rxBYTE
		movwf		PCL

mLoop_Czeck_Standalone
		; Are we running in STANDALONE mode?
		; Was there a timer1 overflow?
	BANKSEL PIR1
		btfss	PIR1,TMR1IF		; Was there a timer overflow?
		goto 	mLoop 			; No - keep waiting
mLoop_Run_Standalone
		bcf		PIR1,TMR1IF		; Yes - clear the event
		decfsz	gAloneCount		; Have we had enough TIMER1 events?
		goto	mLoop			; No - keep waiting
		movlw	d'8'			; Rotate images - about every 2 seconds
		movwf	gAloneCount

		btfsc	gAloneFrame, 3	; Special handling required for EEPROM frames (8&9)
		goto	mLoop_Handle_EEPROM
		call	displayFrame

			; Determine which frame to display NEXT time?
		incf	gAloneFrame,f
		goto 	mLoop
mLoop_Handle_EEPROM
		incf	gAloneFrame,f	; Squirrel logice - but it works
		beql	gAloneFrame,h'09',frameReadEEPROM0 
		movlw	h'02'
		movwf	gAloneFrame		; Setup to ignore the two LABRAT splash pages
		goto	frameReadEEPROM1
		goto	mLoop
; --------------
; End of Rx Loop

getFramePtrLow
	andlw	h'07'
	addwf   PCL      
	retlw	low Frame00
	retlw	low Frame01
	retlw	low Frame02
	retlw	low Frame03
	retlw	low Frame04
	retlw	low Frame05
	retlw	low Frame06
	retlw	low Frame07

getFramePtrHigh
	andlw	h'07'
	addwf   PCL      
	retlw	high Frame00
	retlw	high Frame01
	retlw	high Frame02
	retlw	high Frame03
	retlw	high Frame04
	retlw	high Frame05
	retlw	high Frame06
	retlw	high Frame07


; -------------------------------------------------------
; From here down the "state machine" states to handle the 
; commands from the PC
; -------------------------------------------------------

smWait4Sync
		bnel		rxBYTE,RX_SYNC,mLoop  ; Wait for a SYNC otherwise loop
		chgState	smWait4Cmd
		goto 		mLoop		; Continue waiting

smWait4Cmd
		beql		rxBYTE,RX_SYNC,mLoop	; IF was a SYNC - stay in this state
						; Test for FUNKY Broadcast messages
		beql		rxBYTE,h'81', cmdStandAlone 
		beql		rxBYTE,h'09', setupFrameRead 
						; Test for messages addressed to this PIX-C
		movf		rxBYTE,w				; Was this addressed to me?
		andwf		pikcADDR,w				; Compare against saved address
		btfss		STATUS,Z				; If zero bits match go back to waiting
		goto		w4CmdParse				; Jump to the Command interpreter
		chgState	smWait4Sync				; or go Back to waiting for SYNC
		goto		mLoop

w4CmdParse
		btfsc		rxBYTE,7				; Test for TRICK-C vs PIK-C 
		goto		w4CmdTrikC				; High order BIT
w4CmdPikC
		movf		rxBYTE,w				; Mask out the COMMAND bits
		andlw		h'07'			; For "PENDING" messages (those with payloads)
		iorlw		h'08'			;   set the HIGH BIT for PIX-C requests
		movwf		cmdPENDING		;   required to determine what command was pending 
		andlw		h'07'			;   when we determine the full payload has arrived.
    	addwf   	PCL,F       	; Use the JUMP table to jump to the appropriate handler
	    goto    	cmdError		; cmd=0 PIK-C setAddress
      	goto    	setupSetAddr	; cmd=1	Payload = BYTE indicating which frame 0,1 = EEPROM 2-9 = ROM
     	goto    	setupFrameWrite	; cmd=2 Payload = BYTE indicating which frame 0,1 of EEPROM
     	goto    	cmdError		; cmd=3 
     	goto		cmdError		; cmd=4	
     	goto		cmdError		; cmd=5 These are all error conditions, as we only have
     	goto		cmdError		; cmd=6 three additional PIK-C commands at this time.
    	goto		cmdError		; cmd=7
		chgState smWait4Sync 
		goto	mLoop

w4CmdTrikC
		movf	rxBYTE,w		; Mask out the COMMAND bits
		andlw	h'07'
		movwf	cmdPENDING
    	addwf   PCL,F       	; Use the JUMP table to goto the appropriate handler
w4Cmdtable                   
	    goto    cmdBlank  		; cmd=0 Trik-C Blank (turn Off)
      	goto    setupVertical	; cmd=1 Trik-C Roll Left
     	goto    setupVertical	; cmd=2 Trik-C Roll Right
     	goto    setupHorizontal	; cmd=3 Trik-C Roll Up
     	goto    setupHorizontal	; cmd=4 Trik-C Roll Down
     	goto    setupFrame		; cmd=5 Trik-C Full Frame
     	goto    cmdClear		; cmd=6 Trik-C Clear image
    	goto    cmdShow		  	; cmd=7 Trik-C Show (turn On)

smWait4Packet
		; Copy data into packet until full
		; Note "filling in reverse order"
		; why? because that's how the PC sends it. (TriksC Protocol)
	BANKSEL rxBuffer
		movf	rxBYTE,w
		movwf	INDF
		decf	FSR,F
		decfsz	payloadCount,F
		goto	mLoop
		movf	cmdPENDING,W	; Use the cmdPending as an offset to the jump table
    	addwf   PCL,F       	; Use the JUMP table to jump to the appropriate handler
w4packetTable
									; TRICK-C Pending Commands
	    goto    cmdError			; cmd=0  No payload for TRICKS-C "BLANK"
      	goto    cmdLeft				; cmd=1
     	goto    cmdRight			; cmd=2
     	goto    cmdUp				; cmd=3
     	goto    cmdDown				; cmd=4
     	goto    cmdFrame1			; cmd=5
     	goto    cmdFrame0			; cmd=6 command doubling atop "Clear"
    	goto    cmdError	  		; cmd=7 No payload for TRICKS-C "Show"

									; PIX-C Pending Commands
	    goto    cmdSetAddr			; cmd=0 
      	goto    cmdFrameRead		; cmd=1
     	goto    cmdFrameWrite		; cmd=2
     	goto    cmdError			; cmd=3
     	goto    cmdError			; cmd=4
     	goto    cmdError			; cmd=5
     	goto    cmdError			; cmd=6 
    	goto    cmdError	  		; cmd=7 

; ----------- Command Handlers -----------------------
cmdBlank
		bcf		gSTATUS,g_SHOW		; Clear the SHOW bit in the gSTATUS register
		bsf		mINHIBIT
		bcf 	mDATA0
		bcf		mDATA1
		bcf		mDATA2
		bcf		mDATA3
#ifdef USE_A_REAL_BLANK_ROUTINE
	BANKSEL FSR
		movlw	Fr0Row0 			; Start Address of RAM copy
		movwf	FSR	
	BANKISEL Fr0Row0
		call 	wipe48				; Erase 1/2 frame

		movlw	Fr1Row0 			; Start Address of RAM copy 
		movwf	FSR
	BANKISEL Fr1Row0					
		call	wipe48				; Erase 1/2 frame
		goto	doneCmd
wipe48
		movlw	HALFFRAMESIZE
		movwf	temp				; Number of bytes to Erase
wipe48Loop
		clrf	INDF
		incf	FSR
		decfsz	temp,f
		goto wipe48Loop
		return
#else
		goto	doneCmd
#endif

cmdClear		; Can't for the life of me determine what the difference was
cmdShow			; between these two. But if we attempt to "clean" the RAM 
				; then the PIC can't keep up with the serial stream. 
		bsf		gSTATUS,g_SHOW		; Set the SHOW bit in the gSTATUS register
		bcf		mINHIBIT
		goto	doneCmd

; ----------------
; "Setup" routines - configure the state machine to await 'N' bytes of payload
; ----------------
setupFrame
		movlw 	HALFFRAMESIZE		; Numer of bytes in the payload (1st 1/2 a frame)
		movwf 	payloadCount
	BANKISEL Fr1Row0
		movlw	(Fr1End-1)			; Point to last BYTE of BANK1 Buffer
		movwf	FSR					; as the data arrives in that order		
		goto	doneSetup

setupVertical
		movlw 	d'2'				; Numer of bytes in the payload
		movwf 	payloadCount
		movlw	rxBufferEnd			; Point to the RxBufferEnd
		movwf	FSR
		goto	doneSetup

setupHorizontal
		movlw 	d'6'				; Numer of bytes in the payload
		movwf 	payloadCount
		movlw	rxBufferEnd			; Point to the RxBufferEnd
		movwf	FSR
		goto	doneSetup

; --------------
; More COMMAND handlers
; --------------

cmdRight
	BANKISEL Fr0Row0
		movlw	Fr0Row0
		movwf	FSR				; Point in the BANK 
		movf	input1,W		; Get the appropriate byte from the payload
		movwf	bitShifter		; Everything is where we want it.
		clrf	voldemort		; Indicate 1st time throught this loop
cmr_forEachBank 
		movlw 	d'8'			; 8 rows per frame
		movwf	row_count		; 
cmr_forEachRow
		movlw	d'6'			; 6 bytes per row
		movwf	column_count	;
		rlf		bitShifter,F	; Put the "next" highest bit into 'C'
cmr_forEachColumn
		rlf		INDF,F			; Rotate the payload NOTE: inverse rotate due to msb output ordering
		incf	FSR,F			; Increment to the next BYTE in the stream
		decfsz	column_count	; Count down all 6 bytes in the ROW
		goto 	cmr_forEachColumn

		decfsz	row_count
		goto 	cmr_forEachRow

		btfsc	voldemort,1		; Was this the second frame?
 	BANKSEL Fr0Row0
		goto	doneCmd			; Yes - we are done

	BANKISEL Fr1Row0
		movlw	Fr1Row0
		movwf	FSR
		movf	input2,W
		movwf	bitShifter
		bsf		voldemort,1		; Flag that we are executing the SECOND 1/2 of the shiftloop
		goto	cmr_forEachBank

cmdLeft
	BANKISEL Fr0Row0
		movlw	(Fr0End-1)
		movwf	FSR				; Point in the BANK 
		movf	input1,W		; Get the appropriate byte from the payload
		movwf	bitShifter		; Everything is where we want it.
		clrf	voldemort		; Indicate 1st time throught this loop

cml_forEachBank 
		movlw 	d'8'			; 8 rows per frame
		movwf	row_count		; 
cml_forEachRow
		movlw	d'6'			; 6 bytes per row
		movwf	column_count	;
		rrf		bitShifter,F	; Put the "next" lowest bit into 'C'
cml_forEachColumn
		rrf		INDF,F			; Rotate the payload NOTE: inverse rotate due to msb output ordering
		decf	FSR,F			; Decrement to the next BYTE in the stream
		decfsz	column_count	; Count down all 6 bytes in the ROW
		goto 	cml_forEachColumn

		decfsz	row_count
		goto 	cml_forEachRow

		btfsc	voldemort,1		; Was this the second frame?
		goto	doneCmd			; Yes - we are done
		
	BANKISEL Fr1Row0
		movlw	(Fr1End-1)
		movwf	FSR
		movf	input2,W
		movwf	bitShifter
		bsf		voldemort,1		; Flag that we are executing the SECOND 1/2 of the shiftloop
		goto	cml_forEachBank


cmdUp
	; Ship the Top 7 lines of the Bank 0 frame
    ; Copy 1 line from Top of Bank 1 frame
    ; Ship the Top 7 lines of the Bank 1 frame
		movlw  Fr0Row0
		movwf  memcpy_b
		movlw  Fr0Row1
		movwf  memcpy_a
		movlw  d'42'
		movwf	memcpy_i
	BANKISEL Fr0Row0
		call 	memCpyUp

		; Copy the 6 bytes from Bank1 to Bank 0
		movlw  Fr0Row7
		movwf  memcpy_b
		movlw  Fr1Row0
		movwf  memcpy_a
		movlw  d'6'
		movwf	memcpy_i
		call 	memCpyUpBanks	; Copy from Bank 1 to Bank 0 

		movlw  Fr1Row0
		movwf  memcpy_b
		movlw  Fr1Row1
		movwf  memcpy_a
		movlw  d'42'
		movwf	memcpy_i
	BANKISEL Fr1Row0
		call 	memCpyUp

		movlw  Fr1Row7
		movwf  memcpy_b
		movlw  rxBuffer
		movwf  memcpy_a
		movlw  d'6'
		movwf	memcpy_i
	BANKISEL Fr1Row0
		call 	memCpyUp
		goto	doneCmd

cmdDown
	; Ship the Bottom 7 lines of the Bank 1 frame
    ; Copy 1 line from Bottom of Bank 0 frame
    ; Ship the Bottom 7 lines of the Bank 0 frame
		movlw  (Fr1End-1)
		movwf  memcpy_b
		movlw  (Fr1Row7-1)
		movwf  memcpy_a
		movlw  d'42'
		movwf	memcpy_i
	BANKISEL Fr1Row0
		call 	memCpyDown

		; Copy the 6 bytes from Bank1 to Bank 0
		movlw  (Fr1Row1-1)
		movwf  memcpy_b
		movlw  (Fr0End-1)
		movwf  memcpy_a
		movlw  d'6'
		movwf	memcpy_i
		call 	memCpyDownBanks	; Copy from Bank 1 to Bank 0 

		movlw  (Fr0End-1)
		movwf  memcpy_b
		movlw  (Fr0Row7-1)
		movwf  memcpy_a
		movlw  d'42'
		movwf	memcpy_i
	BANKISEL Fr1Row0
		call 	memCpyDown

		movlw  Fr0Row0
		movwf  memcpy_b
		movlw  rxBuffer
		movwf  memcpy_a
		movlw  d'6'
		movwf	memcpy_i
	BANKISEL Fr0Row0
		call 	memCpyUp	; Can use Use Forward copy now
		goto	doneCmd

cmdFrame1
		; BANK0 Copy of Frame is completed
		; NOTE - we don't change the primary state, we will continue to receive data.
		;        instead we change the command pending, to be Frame1
		movlw	d'6' 			; Update the cmdPENDING to be the BANK1 data
		movwf	cmdPENDING 		; 
		movlw	HALFFRAMESIZE	; Another 48 bytes expected
		movwf	payloadCount
	BANKISEL Fr0Row0
		movlw	(Fr0End-1)		; Point to the last byte of the BANK1 Buffer
		movwf	FSR				; because the data arrives in this order
		goto 	mLoop			; Stay in w4Packet state (for second half of FRAME)

cmdFrame0
		; BANK1 copy of frame is completed - just exit clean.
		; These are not the droids you want... move along.
		goto	doneCmd

; - - - - - - - - - - - ------------- - - - - - - - - - - - -
; - - - - - - - - - - - PikC commands - - - - - - - - - - - -
; - - - - - - - - - - - ------------- - - - - - - - - - - - -

; -------------
; cmdError - should not occur as these are invalid commands at this time.
; 		Payload = none
; -------------
cmdError
		call	BlinkStatus
		goto	doneCmd


; -------------
; cmdStandAlone - invoke the standAlone functionality
; 		Payload = none
; -------------
cmdStandAlone
		bsf		gSTATUS,g_STANDALONE
		movlw	d'8'			; Rotate images - about every 2 seconds
		movwf	gAloneCount
		call	displayFrame
		goto	doneCmd

; -------------
; cmdFrameRead - Read a frame from ROM or EEPROM
; 	Payload = 1
;		FrameId - <0,1> = EEPROM Frame 0 or 1, and  <2..9> = ROM Frame 0..8
; -------------
setupFrameRead
		movlw	h'09' 		; Update the cmdPENDING to be a 'FRAME READ' command
		movwf	cmdPENDING 	; 
		movlw 	d'1'			; Numer of bytes in the payload
		movwf 	payloadCount
		movlw	rxBufferEnd		; Point to the RxBufferEnd
		movwf	FSR
		goto	doneSetup

cmdFrameRead
		; ToDo - 
		; Use payload byte to select image to read 0/1 = EEPROM
		; 2..N = ROM images
		movf	rxBYTE,W
		beql	rxBYTE,h'08',frameReadEEPROM0
		beql   	rxBYTE,h'09',frameReadEEPROM1
		movf	rxBYTE,W
		andlw	h'07'
	BANKSEL gAloneFrame
		movwf   gAloneFrame
		call	displayFrame
		goto	doneCmd
frameReadEEPROM0
	BANKSEL EEADR					; Set target to eepromFrame0
		movlw 	EE_PIKC_FRAME0		; Frame 0 Start Address
		movwf 	EEADR 				; Data Memory Address to write
		goto frameRead
frameReadEEPROM1
	BANKSEL EEADR					; Set target to eepromFrame0
		movlw 	EE_PIKC_FRAME1		; Frame 0 Start Address
		movwf 	EEADR 				; Data Memory Address to write
		goto frameRead
frameRead
	BANKSEL PIR1	
		bcf		PIR1,EEIF			; clear the EEIF interupt bit
	BANKSEL EEDAT
		bcf		EECON1, EEPGD 		; Point to DATA memory
	BANKSEL FSR
		movlw	Fr0Row0 			; Start Address of RAM copy
		movwf	FSR	
	BANKISEL Fr0Row0
		call 	eeFrameRead			; Clock data out to EEPROM

	BANKSEL FSR
		movlw	Fr1Row0 			; Start Address of RAM copy 
		movwf	FSR
	BANKISEL Fr1Row0					
		call	eeFrameRead			; Clock data out to EEPROM

	BANKSEL EECON1
		bcf		EECON1, WREN 		; Disable writes to EEPROM
		goto	doneCmd


; -------------
; cmdFrameWrite - Copy existing RAM image to EEPROM Frame 0/1 location
;   Payload = 1
;       FrameId - <0,1> = EEPROM Frame 0 or 1 
; -------------
setupFrameWrite
		movlw 	d'1'			; Numer of bytes in the payload
		movwf 	payloadCount
		movlw	rxBufferEnd		; Point to the RxBufferEnd
		movwf	FSR
		goto	doneSetup

cmdFrameWrite
		; Copy to determine which frame to write to
		movf	rxBYTE,W
		beql	rxBYTE,9,cmdFrameWrite1
		beql	rxBYTE,8,cmdFrameWrite0
		goto	cmdError

cmdFrameWrite0
	BANKSEL EEADR					; Set target to eepromFrame0
		movlw 	EE_PIKC_FRAME0		; Frame 0 Start Address
		movwf 	EEADR 				; Data Memory Address to write
		goto frameWrite
cmdFrameWrite1
	BANKSEL EEADR					; Set target to eepromFrame1
		movlw 	EE_PIKC_FRAME1		; Frame 1 Start Address
		movwf 	EEADR 				; Data Memory Address to write

frameWrite							; Copy RAM frame to the EEPROM address
	BANKSEL PIR1	
		bcf		PIR1,EEIF			; clear the EEIF interupt bit
	BANKSEL EEDAT
		bcf		EECON1, EEPGD 		; Point to DATA memory
		bsf		EECON1, WREN 		; Enable writes	

	BANKSEL FSR
		movlw	Fr0Row0 			; Start Address of RAM copy
		movwf	FSR	
	BANKISEL Fr0Row0
		call 	eeFrameWrite		; Clock data out to EEPROM

	BANKSEL FSR
		movlw	Fr1Row0 			; Start Address of RAM copy 
		movwf	FSR
	BANKISEL Fr1Row0					
		call	eeFrameWrite		; Clock data out to EEPROM

	BANKSEL EECON1
		bcf		EECON1, WREN 		; Disable writes to EEPROM
		goto	doneCmd

; -------------
; cmdSetAddr - Program the device ADDRESS
; 	Payload = 1 <address>  NOTE: ADDRESS IN BITS 4..7 (NOT SHIFTED RIGHT)
; -------------
setupSetAddr
		movlw	h'08' 		; Override the mapping - use slot '0'
		movwf	cmdPENDING 	; 
		movlw	d'6'
		movwf 	payloadCount
		movlw	rxBufferEnd			; Point to the RxBufferEnd
		movwf	FSR
		goto	doneSetup

cmdSetAddr
#ifndef ORIGINAL_PIX_C
		; Scan the input buffer for the string...
		; TRIX#<newId>
		; Reject the request if doesn't match
#endif
		; Copy to pikcADDR
		movf	rxBYTE,W
	BANKSEL pikcADDR
		movwf	pikcADDR			; Store it in the global
		call 	eeWriteAddr			; Write into EE
		goto	doneCmd

; Generic "Setup" exit handler - wait for the payload packets
doneSetup
		chgState	smWait4Packet	;
		goto	mLoop

; Generic "Command" exit handler - wait for next SYNC
doneCmd
	BANKSEL Fr0Row0
		chgState	smWait4Sync		;
		goto	mLoop

; -----------------------------------------------------------------------
; Rx Loop Utils. - utility calls for receiving packet payloads
;    moved here in order to keep all the JUMP tables on the first page
; -----------------------------------------------------------------------
rxError:
		call BlinkStatus
		bcf		RCSTA,CREN
		bsf		RCSTA,CREN
		bcf		gSTATUS,g_ESCAPE 	; Don't wait for ESC anymore.. it's an error
		chgState smWait4Sync		; Wait for the SYNC byte
		goto	mLoop

; ------------
; displayFrame - display the ROM/EPROM frame indexed by gAloneFrame
; ------------
displayFrame
	BANKSEL gAloneFrame
		movf	gAloneFrame,w
		call	getFramePtrHigh
		
	BANKSEL EEADR
		movwf	EEADRH
	BANKSEL gAloneFrame
		movf	gAloneFrame,w
		call	getFramePtrLow
		bcf		gSTATUS,g_SHOW
	BANKSEL EEADR
		movwf	EEADR
		bsf		EECON1, EEPGD	; Reading from ROM (not eeprom)
		call	meminit_frameCopy

	BANKSEL gSTATUS
		bsf		gSTATUS,g_SHOW		; Set the SHOW bit in the gSTATUS register
		return;

; ----------- Routines for Starting the Chip ---------
pikcInit
    BANKSEL OSCCON
		movlw 0x71			; 8 MHz internal oscillator
		movwf OSCCON
		
Wait4Clock2Settle
		btfss OSCCON,HTS
		goto Wait4Clock2Settle
		clrf OSCTUNE

	BANKSEL PORTA			; Memory bank 0
		clrf	PORTA		; All PORTA Pins off
		movlw	0x07
		movwf	CMCON0		; disable the comparators
		bcf		WDTCON,0	; turn off WDT
		bcf		ADCON0,0	; turn off AD Convert
		clrf	PORTC		; All PORTC Pins off
		
	BANKSEL ANSEL			; Switch to memory bank 1
		clrf 	ANSEL		; Turn off A/D Converters

		; setup porta & portc 
		bcf	TRISC,0			; DATA0
		bcf	TRISC,1			; DATA1
		bcf	TRISC,2			; DATA2
		bcf	TRISC,3			; DATA3

		bcf TRISA,0			; mROWLATCH
		bcf	TRISA,1			; mSHIFTLATCH
		bcf	TRISA,2			; mDATACLOCK
		bcf	TRISA,4			; mINHIBIT
		bcf	TRISA,5			; mSTATUS_LED

	BANKSEL PORTA			; Memory bank 0
		call	meminit
    	call    timerinit	; Initialize TIMER0 and enable TMRO interrupts
    	call    rxinit		; Set up the EUSART to receive DMX at 250,000 baud
		return

; ----------- Memory Initalization ---------
meminit
		bsf			mINHIBIT 	; TURN OFF THE LEDTRIKS
		clrf		outRowIndex ; Ensure we start at ROW 0
		chgState	smWait4Sync	; Default to w4SYNC state
		movlw		d'01';
		movwf		gAloneCount	; Default to counting 1 "tick"
		clrf		gAloneFrame ; Default to FRAME00
		clrf		gSTATUS
		call		eeReadAddr

	BANKSEL pikcADDR
		; If value is OUT OF RANGE, then default to 0x78
		movf 	pikcADDR,w		; Redundant copy into W.. but safer
		andlw 	h'87'			; Check for bits "outside" the ADDR mask
		btfsc	STATUS,Z
		goto	meminit_pikcADDR_OK
		; Address BYTE was invalid - assume un-initialized so default to 0x78
		; (respond to ANYTHING)
		movlw	h'78'		
		movwf	pikcADDR		; store the address
		call BlinkStatus

meminit_pikcADDR_OK
		call BlinkStatus		; Second Blink - tells user address was not found in eeprom

	BANKSEL EEADR
		movlw	high Frame00
		movwf	EEADRH
		movlw	low Frame00
		movwf	EEADR
		bsf		EECON1, EEPGD	; Reading from ROM (not eeprom)

meminit_frameCopy				; Sneaky entry point to "just copy" the frame
	BANKISEL Fr0Row0			; Setup to fill BANK0 (TOP) Buffer
		movlw	Fr0Row0			; Store target into FSR for INDF use
		movwf	FSR				;
		call	flashCpy
						
	BANKISEL Fr1Row0				; Setup to fill BANK1 (BOTTOM) Buffer
		movlw	Fr1Row0			; Store target into FSR for INDF use
		movwf	FSR		
		call	flashCpy
	return

; ----------- Serial Routines ---------
rxinit
    BANKSEL PORTC
		bsf     PORTC,5                 ; PORTC.5 is input for EUSART
		clrf    SPBRGH                  ; 8 = 57.6, 25 = 19.2
		movlw   d'8'                     
		movwf   SPBRG 
		clrf    BAUDCTL
		bsf     BAUDCTL,BRG16           ; receiving serial at 57.6k bits per second                 
		movlw   0x20                    ; Initialize the TXSTA
		movwf   TXSTA                   ; 
		movlw   0x90                    ; Serial Port and continuous receive enabled
		movwf   RCSTA
		return                         
; ----------- timerinit ---------
timerinit
		BANKSEL	T1CON
		bcf		T1CON,TMR1ON			; Make sure timer is disabled
		bsf		T1CON,T1CKPS1
		bsf		T1CON,T1CKPS0
		clrf	TMR1H
		clrf	TMR1L
		bsf		T1CON,TMR1ON			; Enable the timer

		BANKSEL	INTCON
        movlw   B'10100000'             ; Enable global and TMR0 interrupts
        movwf   INTCON
    BANK1
        clrf    OPTION_REG              ; No prescaler for TMR0 needed
    BANK0   
        return

; ----------------- eeFrameRead ------
eeFrameRead
		movlw	HALFFRAMESIZE
		movwf	temp				; Number of bytes to copy
eeFrameReadLoop
	BANKSEL EEADR
		bsf		EECON1, RD
		movf	EEDAT,W
		movwf	INDF
		incf	EEADR
		incf	FSR
		decfsz	temp,f
		goto eeFrameReadLoop
	return

; ----------------- eeReadAddr -------	
eeReadAddr
	; read the pix-c address from the eeprom
	BANKSEL EEADR
		movlw	EE_PIKC_ADDR	; eeprom addr
		movwf 	EEADR			; data address to read
		bcf		EECON1, EEPGD 	; point to adata memory
		bsf		EECON1, RD		; EE read
		movf	EEDAT, w		; w = eeprom data.
	BANKSEL pikcADDR
		movwf	pikcADDR		; store for later use
		return

; ----------------- eeWriteAddr -------	
eeWriteAddr
	BANKSEL PIR1
		bcf	PIR1,EEIF				; clear the EEIF interupt bit
	BANKSEL EEADR
		movlw 	EE_PIKC_ADDR		;PIKC HIGH ADDRESS
		movwf 	EEADR 				;Data Memory Address to write
	BANKSEL pikcADDR
		movf	pikcADDR,w 			;
	BANKSEL EEDAT
		movwf	EEDAT 				;Data Memory Value to write
		bcf		EECON1, EEPGD 		;Point to DATA memory
		bsf		EECON1, WREN 		;Enable writes
		bcf		INTCON, GIE 		;Disable INTs.
		btfsc	INTCON, GIE 		;SEE AN576
		goto	$-2
		movlw	0x55 ;
		movwf	EECON2 				;Write 55h
		movlw	0xAA 				;
		movwf	EECON2 				;Write AAh
		bsf		EECON1, WR 			;Set WR bit to begin write
		
	BANKSEL PIR1		
		btfss	PIR1,EEIF			; need to keep checking for EEIF being set (write complete.)
		goto	$-2
		bcf		PIR1,EEIF			; clear the EEIF write complete interupt
		
	BANKSEL EECON1
		bcf		EECON1, WREN 		;Disable writes
		bsf		INTCON, GIE			;Re-enable interrupts
	return

; ----------------- eeFrameWrite ---------------	
eeFrameWrite
		movlw	HALFFRAMESIZE
		movwf	temp				; Number of bytes to copy
eeFrameWriteLoop
		movf	INDF,W

	BANKSEL EEDAT
		movwf	EEDAT 				;Data Memory Value to write
		bcf		INTCON, GIE 		;Disable INTs.
		btfsc	INTCON, GIE 		;SEE AN576
		goto	$-2
		movlw	0x55 ;
		movwf	EECON2 				;Write 55h
		movlw	0xAA 				;
		movwf	EECON2 				;Write AAh
		bsf		EECON1, WR 			;Set WR bit to begin write

	BANKSEL PIR1
		btfss	PIR1,EEIF			; need to keep checking for EEIF being set (write complete.)
		goto	$-2
		bcf		PIR1,EEIF			; clear the EEIF write complete interupt
		bsf		INTCON, GIE			;Re-enable interrupts
		incf	FSR,f				; Point at the next byte
	BANKSEL EEADR
		incf	EEADR,f
		decfsz	temp,f
		goto eeFrameWriteLoop
	return

; ------------------ flashCopy ----------------
; Copies a 48 byte 1/2 frame from ROM or EEPROM
; 		EEADR and EECON1 - must already be set up
; 		FSR - also already setup to point at destination of the copy
;
flashCpy
		movlw HALFFRAMESIZE
		movwf temp				; Going to copy 48 bytes
	BANKSEL EEADR
flashCpyLoop
		bsf		EECON1,	RD
		NOP						; Required for ROM reads, and won't hurt 
		NOP						; for EEPROM reads either... 
		movf	EEDAT,W
		movwf	INDF
		incf	FSR,f
		incf	EEADR,f
		decfsz	temp,f
    	goto	flashCpyLoop
	return

;===================================PIC16CXXX===================================
; memcpy_a ; src pointer base
; memcpy_b ; dst pointer base
; memcpy_i ; byte count held in reg file
; USES:
; memcpy_temp ; temp data storage
memCpyUp
		movf 	memcpy_a,W
		movwf 	FSR 					
		movf 	INDF,W
		movwf 	temp
		incf	memcpy_a,f

		movf 	memcpy_b,W
		movwf 	FSR
		movf 	temp,W
		movwf 	INDF

		incf	memcpy_b,f
		decfsz 	memcpy_i, F 		
		goto memCpyUp
		return

memCpyUpBanks
	BANKISEL Fr0Row0
		movf 	memcpy_a,W
		movwf 	FSR 					
		movf 	INDF,W
		movwf 	temp
		incf	memcpy_a,f
	BANKISEL Fr1Row1
		movf 	memcpy_b,W
		movwf 	FSR
		movf 	temp,W
		movwf 	INDF

		incf	memcpy_b,f
		decfsz 	memcpy_i, F 		
		goto memCpyUpBanks
		return

memCpyDown
		movwf	memcpy_a
		movwf 	FSR 					
		movf 	INDF,W
		movwf 	temp
		decf 	memcpy_a,W

		movwf	memcpy_b
		movwf 	FSR
		movf 	temp,W
		movwf 	INDF

		decf 	memcpy_b,W
		decfsz 	memcpy_i, F 		
		goto memCpyDown
		return

memCpyDownBanks
	BANKISEL Fr1Row0
		movwf	memcpy_a
		movwf 	FSR 					
		movf 	INDF,W
		movwf 	temp	
		decf 	memcpy_a,W
	BANKISEL Fr0Row1
		movwf	memcpy_b
		movwf 	FSR
		movf 	temp,W
		movwf 	INDF

		decf 	memcpy_b,W
		decfsz 	memcpy_i, F 		
		goto memCpyDownBanks
		return

;----------
BlinkStatus
	BANKSEL PORTC
		bcf 	mSTATUS_LED			; Turn on Status
		call    loop
		call    loop
		bsf		mSTATUS_LED
		call 	loop
		call    loop
		return

; ----------- loop1sec ------------
loop1sec
	call	loop
	call	loop
	call	loop
	call 	loop
	return

; ----------- 250ms delay ---------
loop  
	movlw    d'250'    		; 250mS
	call     WaitNms   		;
    	return

; ----------------- WaitNms --------
WaitNms  
	movf    timer,W			; timer_local=W
loopNms  
	movlw    d'248'			; revised value due to extras
    call     Wait1ms    	;
    goto     $+1        	; 2 clock cycles
    decfsz   timer,f		; Dec loop variable and check
   	goto     loopNms     	;  No, keep looping
    return 		            ;  Yes, Nms done	

; ----------------- 1 ms delay -------	
Wait1ms  
	movlw	d'255'  	    ; Initial value - tweak if req.
    movwf	COUNT
loop1ms 
	decfsz	COUNT,1
    goto    loop1ms     	;  No, keep looping
    return 		         	;  Yes, 1ms done


;*******************************************************************************
; Frame table (lookup)
; This is where the 8 Frames + init frame are stored for stand alone mode
; Note thes two frames are "splash" pages and are only displayed when the 
; device is first powered up. There is no need to change *THESE* frames.
; Focus on the frames in the .INC files, and the two to be stored in EEPROM.
;*******************************************************************************

	ORG 0xC00                      		; Data Tables
Frame00:
	dt	.16	,	.12	,	.142,	.99	,	.126,	.115	
	dt	.8	,	.10	,	.73	,	.82	,	.8	,	.10	
	dt	.4	,	.143,	.231,	.121,	.4	,	.48	
	dt	.130,	.72,	.146,	.68	,	.2	,	.32	
	dt	.95	,	.232,	.137,	.66	,	.1	,	.28	
	dt	.0	,	.0	,	.0	,	.0	,	.0	,	.0	
	dt	.0,		.0	,	.0	,	.0	,	.0	,	.0	
	dt	.240,	.200,	.0	,	.60	,	.64	,	.4	
	dt	.16	,	.141,	.0	,	.66	,	.128,	.2	
	dt	.16	,	.129,	.12	,	.2	,	.144,	.19	
	dt	.240,	.140,	.2	,	.2	,	.80	,	.21	
	dt	.16	,	.136,	.225,	.2	,	.224,	.15	
	dt	.16	,	.136,	.226,	.66	,	.224,	.15	
	dt	.16	,	.136,	.4	,	.66	,	.64	,	.4	
	dt	.56	,	.220,	.13	,	.60	,	.32	,	.8	
	dt	.0	,	.0	,	.0	,	.0	,	.64	,	.4


Frame01:
 	dt	.16	,	.12	,	.142,	.99	,	.126,	.115
	dt	.8	,	.10	,	.73	,	.82	,	.8	,	.10	
	dt	.4	,	.143,	.231,	.121,	.4	,	.48	
	dt	.130,	.72,	.146,	.68	,	.2	,	.32	
	dt	.95	,	.232,	.137,	.66	,	.1	,	.28	
	dt	.0	,	.0	,	.0	,	.0	,	.0	,	.0	
	dt	.0,		.0	,	.0	,	.0	,	.0	,	.0	
	dt	.240,	.200,	.0	,	.60	,	.64	,	.4	
	dt	.16	,	.141,	.0	,	.66	,	.128,	.2	
	dt	.16	,	.129,	.12	,	.2	,	.144,	.35	
	dt	.240,	.140,	.2	,	.2	,	.80	,	.21	
	dt	.16	,	.136,	.225,	.2	,	.224,	.15	
	dt	.16	,	.136,	.226,	.66	,	.224,	.15	
	dt	.16	,	.136,	.4	,	.66	,	.64	,	.4	
	dt	.56	,	.220,	.13	,	.60	,	.32	,	.8	
	dt	.0	,	.0	,	.0	,	.0	,	.16	,	.16

	ORG 0xD00                      		; Data Tables
Frame02:
#include "daniel.inc"


Frame03:
#include "tristan1.inc"

	ORG 0xE00                      		; Data Tables
Frame04:
#include "listen.inc"

Frame05:
#include "kaitlin.inc"

	ORG 0xF00                      		; Data Tables
Frame06:
#include "mom.inc"

Frame07:
#include "diagnostic.inc"

EndofData:
	dt "(c) 2010 Andrew Williams"
; ----------------- end! -------	
        END
