/////////////////////////////////
//
//    FastLED6502
//    by Mark Kriegsman
//
// Device driver and animation 
// library for connecting addressable 
// LED strips to an Apple II.
// The full "FastLED" library is
// available for Arduino and related
// microcontrollers.
//
/////////////////////////////////
//
// HOST COMPATIBILITY:
// Apples with 16-pin DIP "game ports"
// are fully supported; Apples with only
// 9-pin "game ports" are NOT supported.
//
//   Apple ][ fully supported
//	 Apple ][+ fully supported
//	 Apple //e fully supported
//
//	 Apple //c and //c+ NOT supported
//    as they lack the required 16-pin
//    DIP game port for digital I/O.
//   
//	 Apple //gs: 
//    motherboard game port IS supported
//    back panel connector NOT supported
//    See Notes section below.
//
// C64, PET, VIC-20, Atari400/800, 
// NES, SYM, KIM-1, and other 6502
// systems are NOT supported at this
// time, but porting should be
// relatively easy for someone familiar
// with each target platform.
//
//
// LED STRIP COMPATIBILITY:
// In general, "four-wire" (clocked) 
// LED strips can be supported, but
// "three-wire" (clockless) LED strips
// cannot be supported.
//
//   APA102 tested & working
//	 Adafruit DotStar tested & working
//	 LPD8806 should work (untested)
//	 WS2801 should work (untested)
//
// WS2811/WS2812/NeoPixel can NOT work
// due to timing incompatibilities,
// namely that the 1MHz Apple is far
// too slow to drive them correctly.
//
//
// USAGE - HARDWARE:
// Connect an external power source to
// +5 and GND on the LED strip.
// Connect GND on the LED strip to GND
// on the game port connector (pin 8)
// Connect DATA IN on the LED strip to
// pin 12, 13, or 14 on the game port.
// Connect CLOCK IN on the LED strip to
// pin 5 (preferred), 12, 13, or 14 on
// the game port. Note: Apple //gs users
// cannot use pin 5.
//
//
// USAGE - SOFTWARE:
// At build time provide definitions for
//   CHIPSET, DATA_PIN, CLOCK_PIN,
//   NUM_LEDS, & BRIGHTNESS.
// Inside "Setup":
//	 Store LED count into
//     FastLED_NumPixels,
//	 Store brightness into
//     FastLED_Brightness
// Inside "Loop":
//	 Update the leds array, found in
//     ledsR, ledsG, and ledsB
//	 Call FastLED_Show
//   Jump back to top of "Loop"
//
//
// REFERENCE:
// FastLED_Show:
//   display led array on LED strip
// FastLED_FillBlack: 
//   fill led array to black
// FastLED_FillSolid_RGB_AXY: 
//   fill led array with RGB color
// FastLED_FillSolid_Hue_X: 
//   fill led array with solid HSV Hue
// FastLED_Random8: 
//   return a pseudorandom number in A
// FastLED_FillRainbow_XY:
//   fill led array with HSV rainbow
//   starting at hue X, incrementing by
//   huedelta Y each pixel.
// FastLED_SetHue_XY:
//   set pixel Y to HSV hue X
// FastLED_Beat8:
//   takes a speed increment in A, and
//   returns a triangle wave in A.
//
//
// NOTES:
// For speed and size, there IS some
//   self-modifying code in this
//   library, so it cannot be burned
//   into ROM without modification.
// Brightness control only works on
//   APA102 at this point.
// Pin 15 is currently used as a
//   'frame start' signal for protocol
//   diagnostics - makes frames more 
//   visible with an oscilloscope.
// If Pin 5 is specified for the CLOCK
//   output pin, FastLED6502 will
//   automatically use the high speed
//   C040STROBE signal for clock.  Note
//   that the Apple //gs lacks this
//   signal, even on the motherboard
//   game port.
// The Apple joystick/mouse port on the
//   rear of the //c, //c+, and //gs
//   can NOT be used for LED connections
//   because it lacks the necessary
//   digital output pins.
// This library can drive 100 LED pixels
//   at more than 30 frames per second.
//
//
// VERSION HISTORY
// 	2015-02-07 - first version, by MEK
//	  assembled with xa65
//      www.floodgap.com/retrotech/xa/


/////////////////////////////////
//
// ENTRY POINT
//

FastLED_Entry
		jsr FastLED_FillBlack
		jmp Setup


/////////////////////////////////
//
// FASTLED6502 GLOBALS
//

FastLED_NumPixels   	.byt NUM_LEDS
FastLED_Brightness 		.byt BRIGHTNESS

FastLED_RandomState		.byt 17
FastLED_BeatState		.byt 0


/////////////////////////////////
//
// API FUNCTIONS
//

FastLED_FillBlack
		lda FastLED_NumPixels
		pha
		lda #255
		sta FastLED_NumPixels
		lda #0
		tax
		tay
		jsr FastLED_FillSolid_RGB_AXY
		jsr FastLED_Show
		pla
		sta FastLED_NumPixels
		rts


FastLED_FillRainbow_XY
		sty rbHueDelta
		ldy #0
FR1
		lda FastLED_RainbowR,x
		sta ledsR,y
		lda FastLED_RainbowG,x
		sta ledsG,y
		lda FastLED_RainbowB,x
		sta ledsB,y
	
		txa
		clc
		adc rbHueDelta
		tax
	
		iny
		cpy FastLED_NumPixels
		bne FR1
		rts
	
rbHueDelta	.byt 0


FastLED_SetHue_XY
		lda FastLED_RainbowR,x
		sta ledsR,y
		lda FastLED_RainbowG,x
		sta ledsG,y
		lda FastLED_RainbowB,x
		sta ledsB,y
		rts		
	
	
FastLED_FillSolid_RGB_AXY
		sta ledsR
		stx ledsG
		sty ledsB
		ldy #0
FillSolidRGBAXY1
		lda ledsR
		sta ledsR,y
		lda ledsG
		sta ledsG,y
		lda ledsB
		sta ledsB,y
		iny
		cpy FastLED_NumPixels
		bne FillSolidRGBAXY1
		rts

FastLED_FillSolid_Hue_X
		ldy #0
FillSolidHX1
		lda FastLED_RainbowR,x
		sta ledsR,y
		lda FastLED_RainbowG,x
		sta ledsG,y
		lda FastLED_RainbowB,x
		sta ledsB,y
		iny
		cpy FastLED_NumPixels
		bne FillSolidHX1
		rts


; NOTE: USES SELF-MODIFYING CODE
FastLED_Random8
		inc Random8GetLo
		bne Random8Get
		inc Random8GetHi
		bne Random8Get
		lda #$F8
		sta Random8GetHi
		lda #03
		sta Random8GetLo
Random8Get 
Random8GetLo = Random8Get + 1
Random8GetHi = Random8Get + 2
		lda $F803
		adc FastLED_RandomState
		sta FastLED_RandomState
		rts


FastLED_Beat8
		clc
		adc FastLED_BeatState
		sta FastLED_BeatState
		bit FastLED_BeatState
		bmi FastLED_Beat8Neg
		asl
		rts		
FastLED_Beat8Neg
		lda #$ff
		sec
		sbc FastLED_BeatState
		sbc FastLED_BeatState
		rts


FastLED_Show
		jmp CHIPSET

		
/////////////////////////////////
//
// HARDWARE INTERFACING
//

PINOFF_BASE	=	PIN15OFF
PINON_BASE	=	PIN15ON

#define PINON(P) PINON_BASE+((15-P)*2)
#define PINOFF(P) PINOFF_BASE+((15-P)*2)

DATAOFF = PINOFF(DATA_PIN)
DATAON  = PINON(DATA_PIN)
CLKOFF  = PINOFF(CLOCK_PIN)
CLKON   = PINON(CLOCK_PIN)

// Special handling if CLOCK_PIN
// is 5: the C040STROBE line.
#if CLOCK_PIN = 5
#define CLOCK_ON 	bit PIN5STROBE
#define CLOCK_OFF
#else
#define CLOCK_ON 	bit CLKON
#define CLOCK_OFF	bit CLKOFF
#endif

FRAMEON		= PINON(15)
FRAMEOFF	= PINOFF(15)

/////////////////////////////////
APA102
		bit FRAMEON
		jsr FastLED_Send00
		jsr FastLED_Send00
		jsr FastLED_Send00
		jsr FastLED_Send00

		lda FastLED_Brightness
		lsr
		lsr
		lsr
		ora #$E0
		tax
	
		ldy FastLED_NumPixels
APA102PX	
		txa
		jsr FastLED_SendA
		lda ledsB,y
		jsr FastLED_SendA
		lda ledsG,y
		jsr FastLED_SendA
		lda ledsR,y
		jsr FastLED_SendA
		dey
		bne APA102PX

		lda FastLED_NumPixels
		lsr
		lsr
		lsr
		lsr
		lsr
		lsr
		tay
		iny
APA102CL
		jsr FastLED_SendFF
		jsr FastLED_Send00
		jsr FastLED_Send00
		jsr FastLED_Send00
		dey
		bne APA102CL
		bit FRAMEOFF
		rts

/////////////////////////////////
LPD8806
		bit FRAMEON
		ldy FastLED_NumPixels
LPD8806PX	
		lda ledsG,y
		lsr
		ora #$80
		jsr FastLED_SendA
		lda ledsR,y
		lsr
		ora #$80
		jsr FastLED_SendA
		lda ledsB,y
		lsr
		ora #$80
		jsr FastLED_SendA
		dey
		bne LPD8806PX

		bit FRAMEOFF
		rts


/////////////////////////////////
WS2801
		bit FRAMEON
		ldy FastLED_NumPixels
WS2801PX	
		lda ledsG,y
		jsr FastLED_SendA
		lda ledsR,y
		jsr FastLED_SendA
		lda ledsB,y
		jsr FastLED_SendA
		dey
		bne WS2801PX

		bit FRAMEOFF
		rts


/////////////////////////////////
FastLED_SendFF
		bit DATAON
		jmp FastLED_SendXX
		;
FastLED_Send00
		bit DATAOFF	
		;
FastLED_SendXX
		CLOCK_ON
		CLOCK_OFF
		CLOCK_ON
		CLOCK_OFF
	
		CLOCK_ON
		CLOCK_OFF
		CLOCK_ON
		CLOCK_OFF
	
		CLOCK_ON
		CLOCK_OFF
		CLOCK_ON
		CLOCK_OFF
	
		CLOCK_ON
		CLOCK_OFF
		CLOCK_ON
		CLOCK_OFF
	
		rts

FastLED_SendA	
		cmp #0
		beq FastLED_Send00
		cmp #$FF
		beq FastLED_SendFF

		asl
		bcc S0x0
S0x1	bit DATAON
		bcs S0xK
S0x0    bit DATAOFF
S0xK	CLOCK_ON
		CLOCK_OFF

		asl
		bcc S1x0
S1x1	bit DATAON
		bcs S1xK
S1x0    bit DATAOFF
S1xK	CLOCK_ON
		CLOCK_OFF

		asl
		bcc S2x0
S2x1	bit DATAON
		bcs S2xK
S2x0    bit DATAOFF
S2xK	CLOCK_ON
		CLOCK_OFF

		asl
		bcc S3x0
S3x1	bit DATAON
		bcs S3xK
S3x0    bit DATAOFF
S3xK	CLOCK_ON
		CLOCK_OFF

		asl
		bcc S4x0
S4x1	bit DATAON
		bcs S4xK
S4x0    bit DATAOFF
S4xK	CLOCK_ON
		CLOCK_OFF

		asl
		bcc S5x0
S5x1	bit DATAON
		bcs S5xK
S5x0    bit DATAOFF
S5xK	CLOCK_ON
		CLOCK_OFF

		asl
		bcc S6x0
S6x1	bit DATAON
		bcs S6xK
S6x0    bit DATAOFF
S6xK	CLOCK_ON
		CLOCK_OFF

		asl
		bcc S7x0
S7x1	bit DATAON
		bcs S7xK
S7x0    bit DATAOFF
S7xK	CLOCK_ON
		CLOCK_OFF

		rts


/////////////////////////////////
//
// Force page allignment for speed
// for leds array and Rainbow table
//
		.dsb 256-(* & $FF),0


/////////////////////////////////
//
// LED ARRAY
//

ledsR	.dsb 256,0 
ledsG	.dsb 256,0
ledsB	.dsb 256,0
		
/////////////////////////////////
//
// HSV RAINBOW DEFINITION
//
// Generated directly from FastLED.
//

FastLED_RainbowR
	.byt $FF,$FD,$FA,$F8,$F5,$F2,$F0,$ED
	.byt $EA,$E8,$E5,$E2,$E0,$DD,$DA,$D8
	.byt $D5,$D2,$D0,$CD,$CA,$C8,$C5,$C2
	.byt $C0,$BD,$BA,$B8,$B5,$B2,$B0,$AD
	.byt $AB,$AB,$AB,$AB,$AB,$AB,$AB,$AB
	.byt $AB,$AB,$AB,$AB,$AB,$AB,$AB,$AB
	.byt $AB,$AB,$AB,$AB,$AB,$AB,$AB,$AB
	.byt $AB,$AB,$AB,$AB,$AB,$AB,$AB,$AB
	.byt $AB,$A6,$A1,$9C,$96,$91,$8C,$86
	.byt $81,$7C,$76,$71,$6C,$66,$61,$5C
	.byt $56,$51,$4C,$47,$41,$3C,$37,$31
	.byt $2C,$27,$21,$1C,$17,$11,$0C,$07
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$02,$05,$07,$0A,$0D,$0F,$12
	.byt $15,$17,$1A,$1D,$1F,$22,$25,$27
	.byt $2A,$2D,$2F,$32,$35,$37,$3A,$3D
	.byt $3F,$42,$45,$47,$4A,$4D,$4F,$52
	.byt $55,$57,$5A,$5C,$5F,$62,$64,$67
	.byt $6A,$6C,$6F,$72,$74,$77,$7A,$7C
	.byt $7F,$82,$84,$87,$8A,$8C,$8F,$92
	.byt $94,$97,$9A,$9C,$9F,$A2,$A4,$A7
	.byt $AB,$AD,$B0,$B2,$B5,$B8,$BA,$BD
	.byt $C0,$C2,$C5,$C8,$CA,$CD,$D0,$D2
	.byt $D5,$D8,$DA,$DD,$E0,$E2,$E5,$E8
	.byt $EA,$ED,$F0,$F2,$F5,$F8,$FA,$FD
FastLED_RainbowG
	.byt $00,$02,$05,$07,$0A,$0D,$0F,$12
	.byt $15,$17,$1A,$1D,$1F,$22,$25,$27
	.byt $2A,$2D,$2F,$32,$35,$37,$3A,$3D
	.byt $3F,$42,$45,$47,$4A,$4D,$4F,$52
	.byt $55,$57,$5A,$5C,$5F,$62,$64,$67
	.byt $6A,$6C,$6F,$72,$74,$77,$7A,$7C
	.byt $7F,$82,$84,$87,$8A,$8C,$8F,$92
	.byt $94,$97,$9A,$9C,$9F,$A2,$A4,$A7
	.byt $AB,$AD,$B0,$B2,$B5,$B8,$BA,$BD
	.byt $C0,$C2,$C5,$C8,$CA,$CD,$D0,$D2
	.byt $D5,$D8,$DA,$DD,$E0,$E2,$E5,$E8
	.byt $EA,$ED,$F0,$F2,$F5,$F8,$FA,$FD
	.byt $FF,$FD,$FA,$F8,$F5,$F2,$F0,$ED
	.byt $EA,$E8,$E5,$E2,$E0,$DD,$DA,$D8
	.byt $D5,$D2,$D0,$CD,$CA,$C8,$C5,$C2
	.byt $C0,$BD,$BA,$B8,$B5,$B2,$B0,$AD
	.byt $AB,$A6,$A1,$9C,$96,$91,$8C,$86
	.byt $81,$7C,$76,$71,$6C,$66,$61,$5C
	.byt $56,$51,$4C,$47,$41,$3C,$37,$31
	.byt $2C,$27,$21,$1C,$17,$11,$0C,$07
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
FastLED_RainbowB
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$00,$00,$00,$00,$00,$00,$00
	.byt $00,$02,$05,$07,$0A,$0D,$0F,$12
	.byt $15,$17,$1A,$1D,$1F,$22,$25,$27
	.byt $2A,$2D,$2F,$32,$35,$37,$3A,$3D
	.byt $3F,$42,$45,$47,$4A,$4D,$4F,$52
	.byt $55,$5A,$5F,$64,$6A,$6F,$74,$7A
	.byt $7F,$84,$8A,$8F,$94,$9A,$9F,$A4
	.byt $AA,$AF,$B4,$B9,$BF,$C4,$C9,$CF
	.byt $D4,$D9,$DF,$E4,$E9,$EF,$F4,$F9
	.byt $FF,$FD,$FA,$F8,$F5,$F2,$F0,$ED
	.byt $EA,$E8,$E5,$E2,$E0,$DD,$DA,$D8
	.byt $D5,$D2,$D0,$CD,$CA,$C8,$C5,$C2
	.byt $C0,$BD,$BA,$B8,$B5,$B2,$B0,$AD
	.byt $AB,$A9,$A6,$A4,$A1,$9E,$9C,$99
	.byt $96,$94,$91,$8E,$8C,$89,$86,$84
	.byt $81,$7E,$7C,$79,$76,$74,$71,$6E
	.byt $6C,$69,$66,$64,$61,$5E,$5C,$59
	.byt $55,$53,$50,$4E,$4B,$48,$46,$43
	.byt $40,$3E,$3B,$38,$36,$33,$30,$2E
	.byt $2B,$28,$26,$23,$20,$1E,$1B,$18
	.byt $16,$13,$10,$0E,$0B,$08,$06,$03
