include "P16f84.inc"

; crystal oscillator on, WDT on, copy protection off, power on timer enabled
__CONFIG	_XT_OSC & _WDT_OFF & _CP_ON & _PWRTE_ON

; PWM LENGTH
PWM_LENGTH	EQU	B'00111111'

; IR COMMANDS

IR_COMMAND_1	EQU	B'01101111'
IR_COMMAND_2	EQU	B'01000111'
IR_COMMAND_3	EQU	B'00000111'
IR_COMMAND_4	EQU	B'01001111'

IR_COMMAND_UP	EQU	B'01011111'
IR_COMMAND_DOWN	EQU	B'10111111'

IR_COMMAND_RED	EQU	B'00111111';FLAT
IR_COMMAND_GRN	EQU	B'01111111';TUNE
IR_COMMAND_BLU	EQU	B'10011111';SHARP

IR_COMMAND_STOP	EQU	B'00001111'

IR_COMMAND_MUTE EQU	B'10010111'
IR_COMMAND_5	EQU	B'01100111'
IR_COMMAND_6	EQU	B'00100111'
IR_COMMAND_7	EQU	B'01110111'
IR_COMMAND_8	EQU	B'01010111'
IR_COMMAND_9	EQU	B'00010111'
IR_COMMAND_0	EQU	B'10110111'

;

; user RAM starts at 0x0C
TEMP		EQU	0X0C

RED_LEVEL	EQU	0X0E
GRN_LEVEL	EQU	0X0F
BLU_LEVEL	EQU	0X10

PWM_COUNT	EQU	0X11
PTEMP1		EQU	0X12
PTEMP2		EQU	0X13

; *******************
; interrupt variables
STATUS_TEMP	EQU	0X14 ; status
W_TEMP		EQU	0X15 ; W reg
; *******************

XRED_LEVEL	EQU	0X16
XGRN_LEVEL	EQU	0X17
XBLU_LEVEL	EQU	0X18
TEMP_LEVEL	EQU	0X19

MODE		EQU	0X1A

DELAY_LENGTH	EQU	0X1B

SYNC		EQU	0X1C

IR_TICKS	EQU	0X1D
IR_STATE	EQU	0X1E
IR_BITCOUNT	EQU	0X1F
IR_INCOMING	EQU	0X20
IR_COMMAND	EQU	0X21

TICKS		EQU	0X22
LED_STATE	EQU	0X23
HI_TICKS	EQU	0X24

RED_TARGET	EQU	0X25
GRN_TARGET	EQU	0X26
BLU_TARGET	EQU	0X27

SPEED		EQU	0X28
CUR_COLOUR	EQU	0X29
SYSTEM		EQU	0X2A
FADE_SUBMODE	EQU	0X2B


SOUND		EQU	0
STANDBY		EQU	1
MUTE		EQU	2


;PORT A
LED_RED		EQU	2	;o/p
LED_BLU2	EQU	1	;o/p
LED_GRN		EQU	0	;o/p
LED_BLU1	EQU	3	;o/p

;PORT B
IR_IP		EQU	0
;TEST_OP		EQU	1
;TEST_OP2	EQU	2
SPEAKER1	EQU	2
SPEAKER2	EQU	3

;---------------------------------------------------------
; reset vector

	ORG     0X00
        GOTO    START

;---------------------------------------------------------
; interrupt vector

        ORG     0X04
        GOTO    INT

;---------------------------------------------------------

LOG_LOOKUP:
	ADDWF PCL, F
	DT 0x3F,0x39,0x33,0x2E,0x2B,0x27,0x24,0x21,0x1F,0x1C,0x1A,0x18,0x16,0x15,0x13,0x12,0x10,0x0F,0x0D,0x0C,0x0B,0x0A,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00


; ~5uS delay ----------------------------------------------------------

; loop is ((20*TEMP1)+1) cycles (TEMP1>=1)

DLY5US:	NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		NOP
		DECFSZ	PTEMP1,F
		GOTO	DLY5US
		RETURN

;---------------------------------------------------------------------

CASE:	MACRO	STATE,VAR
	MOVLW	STATE
	SUBWF	VAR,W
	BTFSC	STATUS,Z
	ENDM


;***** PAUSE MACRO  - Delays for ((DLYF*20)+5) cycles (DLYF>=1) *****
; 5 cycle overhead on this routine

PAUSE:	MACRO	DLYF
		MOVLW	DLYF
		MOVWF	PTEMP1
		CALL	DLY5US
	ENDM

;***********************

;**** ~1 sec delay ******
P01SEC:	
	MOVFW	DELAY_LENGTH
	MOVWF	PTEMP2

P1LOOP:	PAUSE	D'255'

	DECFSZ	PTEMP2,F
        GOTO    P1LOOP
	RETURN

;***********************
; ISR - DRIVE LEDs WITH PWM, HANDLE IR RX
; CK IS 10 MHz

INT
	MOVWF	W_TEMP		; Copy W to TEMP register,
	MOVF	STATUS, W	; status to be saved into W
	MOVWF	STATUS_TEMP	; Save status to STATUS_TEMP register

	; decide which interrupt we've got
	BTFSC	INTCON,T0IF
	CALL	PWM_INTERRUPT

	BTFSC	INTCON,INTF
	CALL	IR_INTERRUPT

	MOVF	STATUS_TEMP,W
	MOVWF	STATUS		; Move W into STATUS register
	MOVF	W_TEMP,W

	RETFIE

;***********************

START
	; configure pull-ups/interrupts edge config/clock prescaler
        BSF     STATUS,RP0              ; BANK 1

        MOVLW   B'00000000'             ; Pull ups ON,
					; Prescale = 1
					; INT ENABLED, TIMER assigned to INT
					; INT ON FALLING EDGE (BIT 6 = 0)
        MOVWF   OPTION_REG

	; configure I/O pins
        BSF     STATUS,RP0              ; BANK 1
        MOVLW   B'00000000'             ; Set Port A I/O pins (all o/p)
	MOVWF	TRISA

        MOVLW   B'00000001'             ; Set Port B I/O pins
	MOVWF	TRISB

        BCF     STATUS,RP0              ; BANK 0

	; initialise ports
	CLRF	PORTA
	CLRF	PORTB

	; set speaker line high
	BSF	PORTB,SPEAKER1

	CLRF	RED_LEVEL
	CLRF	GRN_LEVEL
	CLRF	BLU_LEVEL

	CLRF	MODE
	BSF	MODE,0

	MOVLW	B'00000111'
	MOVWF	XRED_LEVEL
	MOVWF	XGRN_LEVEL
	MOVWF	XBLU_LEVEL

	CLRF	PWM_COUNT
	CLRF	IR_TICKS
	CLRF	IR_STATE

	CLRF	TICKS
	CLRF	HI_TICKS
	BSF	HI_TICKS,0

	CALL	IRI_TIMEOUT

	CLRF	RED_TARGET
	CLRF	GRN_TARGET
	CLRF	BLU_TARGET

	MOVLW	5
	MOVWF	SPEED
	CLRF	CUR_COLOUR
	CLRF	SYSTEM

	CLRF	FADE_SUBMODE

	; configure interrupts
	BCF	STATUS,RP0	; BANK 0
	MOVLW	B'10110000'
	MOVWF	INTCON

	CLRF	LED_STATE

	BSF	SYSTEM,SOUND; START SOUND

; Main program loop
MAIN

; CALL MODE HERE

	BTFSC	MODE,0
	CALL	FADE_MODE

	BTFSC	MODE,1
	CALL	MULTICOLOUR_MODE

	BTFSC	MODE,2
	CALL	KIRAKIRA_MODE

	; MODE 4, BIT 3 (CUSTOM MODE) DOESN'T NEED A FUNCTION

	; sync to interrupt
SYNC_LOOP

	; GO BACK TO SLEEP IF IN SLEEP MODE
	BTFSS	SYSTEM,STANDBY
	GOTO	SYNC1
	CALL	STANDBY_MODE
	GOTO	SYNC_LOOP
SYNC1
	MOVF	SYNC,F
	BTFSS	STATUS,Z
	GOTO	SYNC_LOOP

	MOVLW	0XFF
	MOVWF	SYNC
	; end sync to interrupt

	GOTO	MAIN	; for ever...

MULTICOLOUR_MODE

	MOVFW	SPEED	;D'100'
	MOVWF	DELAY_LENGTH

	INCF	LED_STATE,F

	CASE	1,LED_STATE
	GOTO	RED
	CASE	2,LED_STATE
	GOTO	GREEN
	CASE	3,LED_STATE
	GOTO	BLUE
	CASE	4,LED_STATE
	GOTO	YELLOW
	CASE	5,LED_STATE
	GOTO	MAGENTA
	CASE	6,LED_STATE
	GOTO	CYAN
	CASE	7,LED_STATE
	GOTO	WHITE

	;DEFAULT
	CLRF	LED_STATE
	GOTO	MULTICOLOUR_MODE

KIRAKIRA_MODE

	MOVFW	SPEED
	MOVWF	DELAY_LENGTH

	INCF	LED_STATE,F

	CASE	D'1',LED_STATE
	GOTO	RED
	CASE	D'2',LED_STATE
	GOTO	KKOFF
	CASE	D'3',LED_STATE
	GOTO	KKOFF
	CASE	D'4',LED_STATE
	GOTO	KKOFF
	CASE	D'5',LED_STATE
	GOTO	KKOFF

	CASE	D'6',LED_STATE
	GOTO	GREEN
	CASE	D'7',LED_STATE
	GOTO	KKOFF
	CASE	D'8',LED_STATE
	GOTO	KKOFF
	CASE	D'9',LED_STATE
	GOTO	KKOFF
	CASE	D'10',LED_STATE
	GOTO	KKOFF

	CASE	D'11',LED_STATE
	GOTO	BLUE
	CASE	D'12',LED_STATE
	GOTO	KKOFF
	CASE	D'13',LED_STATE
	GOTO	KKOFF
	CASE	D'14',LED_STATE
	GOTO	KKOFF
	CASE	D'15',LED_STATE
	GOTO	KKOFF

	CASE	D'16',LED_STATE
	GOTO	YELLOW
	CASE	D'17',LED_STATE
	GOTO	KKOFF
	CASE	D'18',LED_STATE
	GOTO	KKOFF
	CASE	D'19',LED_STATE
	GOTO	KKOFF
	CASE	D'20',LED_STATE
	GOTO	KKOFF

	CASE	D'21',LED_STATE
	GOTO	MAGENTA
	CASE	D'22',LED_STATE
	GOTO	KKOFF
	CASE	D'23',LED_STATE
	GOTO	KKOFF
	CASE	D'24',LED_STATE
	GOTO	KKOFF
	CASE	D'25',LED_STATE
	GOTO	KKOFF

	CASE	D'26',LED_STATE
	GOTO	CYAN
	CASE	D'27',LED_STATE
	GOTO	KKOFF
	CASE	D'28',LED_STATE
	GOTO	KKOFF
	CASE	D'29',LED_STATE
	GOTO	KKOFF
	CASE	D'30',LED_STATE
	GOTO	KKOFF

	CASE	D'31',LED_STATE
	GOTO	WHITE
	CASE	D'32',LED_STATE
	GOTO	KKOFF
	CASE	D'33',LED_STATE
	GOTO	KKOFF
	CASE	D'34',LED_STATE
	GOTO	KKOFF
	CASE	D'35',LED_STATE
	GOTO	KKOFF
	CASE	D'36',LED_STATE ; dummy pause state - this ends immediately
	GOTO	KKOFF

	;DEFAULT
	CLRF	LED_STATE
	GOTO	KIRAKIRA_MODE

FADE_MODE

	MOVFW	SPEED
	MOVWF	DELAY_LENGTH

	CASE 0,FADE_SUBMODE
	GOTO	FM_0

	CASE 1,FADE_SUBMODE
	GOTO	FM_1

	CASE 2,FADE_SUBMODE
	GOTO	FM_2

	CASE 3,FADE_SUBMODE
	GOTO	FM_3

	CASE 4,FADE_SUBMODE
	GOTO	FM_4

	CASE 5,FADE_SUBMODE
	GOTO	FM_5

	CLRF	FADE_SUBMODE
FM_0
	INCF	XRED_LEVEL,F

	INCF	XGRN_LEVEL,F
	INCF	XGRN_LEVEL,F

	INCF	XBLU_LEVEL,F
	INCF	XBLU_LEVEL,F
	INCF	XBLU_LEVEL,F

	GOTO	FM_MAIN

FM_1
	INCF	XRED_LEVEL,F
	INCF	XRED_LEVEL,F

	INCF	XGRN_LEVEL,F
	INCF	XGRN_LEVEL,F
	INCF	XGRN_LEVEL,F

	INCF	XBLU_LEVEL,F

	GOTO	FM_MAIN

FM_2
	INCF	XRED_LEVEL,F
	INCF	XRED_LEVEL,F
	INCF	XRED_LEVEL,F

	INCF	XGRN_LEVEL,F

	INCF	XBLU_LEVEL,F
	INCF	XBLU_LEVEL,F

	GOTO	FM_MAIN
FM_3
	INCF	XRED_LEVEL,F

	INCF	XGRN_LEVEL,F
	INCF	XGRN_LEVEL,F
	INCF	XGRN_LEVEL,F

	INCF	XBLU_LEVEL,F
	INCF	XBLU_LEVEL,F

	GOTO	FM_MAIN
FM_4
	INCF	XRED_LEVEL,F
	INCF	XRED_LEVEL,F

	INCF	XGRN_LEVEL,F

	INCF	XBLU_LEVEL,F
	INCF	XBLU_LEVEL,F
	INCF	XBLU_LEVEL,F

	GOTO	FM_MAIN
FM_5
	INCF	XRED_LEVEL,F
	INCF	XRED_LEVEL,F
	INCF	XRED_LEVEL,F

	INCF	XGRN_LEVEL,F
	INCF	XGRN_LEVEL,F

	INCF	XBLU_LEVEL,F

FM_MAIN
	MOVFW	XRED_LEVEL
	CALL	SET_LEVEL
	CALL	LIN_LOG
	MOVWF	RED_LEVEL

	MOVFW	XGRN_LEVEL
	CALL	SET_LEVEL
	CALL	LIN_LOG
	MOVWF	GRN_LEVEL

	MOVFW	XBLU_LEVEL
	CALL	SET_LEVEL
	CALL	LIN_LOG
	MOVWF	BLU_LEVEL

	; DETECT SUBMODE CHANGE
	MOVFW	RED_LEVEL
	ADDWF	GRN_LEVEL,W
	ADDWF	BLU_LEVEL,W

	BTFSC	STATUS,Z
	INCF	FADE_SUBMODE,F

	RETURN

SET_LEVEL

	MOVWF	TEMP_LEVEL		;y = w;
	RRF	TEMP_LEVEL,F		;y >>= 3;
	RRF	TEMP_LEVEL,F
;	RRF	TEMP_LEVEL,F
	
	MOVLW	0x3F			;y &= 0x3F // 31  -> 0
	ANDWF	TEMP_LEVEL,W
;W
	SUBLW	0x1F			;y = y - 0x0F;// +16 -> -15
	MOVWF	TEMP_LEVEL
;F
	MOVLW	0X80			;if(y & 0x80)
	ANDWF	TEMP_LEVEL,W
	BTFSC	STATUS,Z
	GOTO	SL1
;{
	MOVFW	TEMP_LEVEL
;W
	XORLW	0xFF			;y^=0xFF;
	ANDLW	0X1F			;y&=0x0F;
	ADDLW	0x01			;y++;
	MOVWF	TEMP_LEVEL
;F
;}

SL1
;F
	MOVLW	0X20			;if(y & 0x20)
	ANDWF	TEMP_LEVEL,W
	BTFSC	STATUS,Z
	GOTO	SL2
;{
	MOVLW	0X1F			;y=0x0F;
	MOVWF	TEMP_LEVEL
;}

SL2
;F
	MOVFW	TEMP_LEVEL
;W
	ANDLW	0X1F			;y&=0x0F;

	RETURN

PWM_INTERRUPT

	; TOGGLE SPEAKER
	BTFSS	SYSTEM,SOUND
	GOTO	SP1

	; BUT NOT IF MUTED
	BTFSC	SYSTEM,MUTE
	GOTO	SP1

	MOVFW	PORTB
	XORLW	B'00001100'
	MOVWF	PORTB
SP1
	
	INCF	IR_TICKS,F
	BTFSS	STATUS,Z
	GOTO	PI1
	; MAKE IR_TICKS STOP AT 255
	MOVLW	D'255'
	MOVWF	IR_TICKS
	BCF	SYSTEM,SOUND; STOP SOUND
	CALL	IRI_TIMEOUT
PI1

	; BACKGROUND PAUSE COUNTER
	DECFSZ	TICKS,F
	GOTO	PI2

	DECFSZ	HI_TICKS,F
	GOTO	PI2

	MOVFW	DELAY_LENGTH
	MOVWF	HI_TICKS
	CLRF	SYNC
PI2

; MAIN PWM CONTROL

	; LIGHT ALL THE LEDs
	INCF	PWM_COUNT,F
	MOVLW	PWM_LENGTH
	ANDWF	PWM_COUNT,F

	BTFSS	STATUS,Z
	GOTO	I3
	
	MOVF	RED_LEVEL,F
	BTFSS	STATUS,Z
	BSF	PORTA,LED_RED

	MOVF	GRN_LEVEL,F
	BTFSS	STATUS,Z
	BSF	PORTA,LED_GRN

	MOVF	BLU_LEVEL,F
	BTFSS	STATUS,Z
	BSF	PORTA,LED_BLU1

	MOVF	BLU_LEVEL,F
	BTFSS	STATUS,Z
	BSF	PORTA,LED_BLU2
I3

; IF F>=W C=1
; IF F<W C=0

	; EXTINGUISH RED LED
	MOVFW	PWM_COUNT
	SUBWF	RED_LEVEL,W	; RED_LEVEL - W
;	BTFSS	STATUS,Z
	BTFSC	STATUS,C
	GOTO	I1
	BCF	PORTA,LED_RED
I1

	; EXTINGUISH GREEN LED
	MOVFW	PWM_COUNT
	SUBWF	GRN_LEVEL,W
;	BTFSS	STATUS,Z
	BTFSC	STATUS,C
	GOTO	I2
	BCF	PORTA,LED_GRN
I2

	; EXTINGUISH BLUE LED
	MOVFW	PWM_COUNT
	SUBWF	BLU_LEVEL,W
;	BTFSS	STATUS,Z
	BTFSC	STATUS,C
	GOTO	I4
	BCF	PORTA,LED_BLU1
	BCF	PORTA,LED_BLU2
I4

	BCF	INTCON,T0IF	; clear interrupt
	RETURN

IR_INTERRUPT

;BCF	PORTB,TEST_OP
	
	; BRANCH DEPENDING ON THE 'IR_TICKS' VARIABLE
; SUBWF		F-W

; IF F-W < 0  THEN C=0
; IF F-W >=0  THEN C=1

; IF F>=W C=1
; IF F<W C=0

	MOVF	IR_STATE,F	; GET READY FOR IR
	BTFSS	STATUS,Z	; DON'T GO BACK TO SLEEP!
	GOTO	IRI1

	CLRF	IR_INCOMING
	CLRF	IR_COMMAND

	MOVLW	D'8'
	MOVWF	IR_BITCOUNT
	
	MOVLW	D'1'
	MOVWF	IR_STATE

	GOTO	IRI_END

IRI1
;	MOVLW	D'65'
	MOVLW	D'45'; NEEDS A BIT OF TIME TO WAKE UP FROM SLEEP
	SUBWF	IR_TICKS,W
	BTFSC	STATUS,C
	GOTO	IRI_START	; IR RX START

	MOVLW	D'10'
	SUBWF	IR_TICKS,W
	BTFSC	STATUS,C
	GOTO	IRI_ZERO	; IR RX ZERO

	MOVLW	D'3'
	SUBWF	IR_TICKS,W
	BTFSC	STATUS,C
	GOTO	IRI_ONE		; IR RX ONE

	;DEFAULT - ERROR
	GOTO	IRI_TIMEOUT

IRI_END

	CLRF	IR_TICKS
	BCF	INTCON,INTF		; clear interrupt
	RETURN

; TIMEOUT - RESET ALL IR RX REGISTERS
IRI_TIMEOUT
	CLRF	IR_STATE

; **** debug
;BCF	PORTB,TEST_OP2

	GOTO	IRI_END

; GET READY TO RECEIVE 32 BIT CODE
IRI_START

	; CHECK WE'RE IN IR_STATE '0x01'
	MOVLW	D'1'
	SUBWF	IR_STATE,W
	BTFSS	STATUS,Z
	GOTO	IRI_TIMEOUT	; WRONG STATE - RESET
	INCF	IR_STATE,F	; GO TO NEXT STATE
	GOTO	IRI_END

; '0' RX'ed
IRI_ZERO
	MOVLW	D'0'
	GOTO	IRI_RX_BIT
; '1' RX'ed
IRI_ONE
	MOVLW	D'1'
; ADD BIT TO THE RX BUFFER
IRI_RX_BIT

	MOVF	IR_STATE,F	; CHECK STATE > 0
	BTFSC	STATUS,Z
	GOTO	IRI_TIMEOUT	; WRONG STATE - RESET
	
	IORWF	IR_INCOMING,F
	DECFSZ	IR_BITCOUNT,F
	GOTO	IRI_RB1

	; END OF THIS BYTE
;BSF	PORTB,TEST_OP
	MOVLW	D'8'
	MOVWF	IR_BITCOUNT

	INCF	IR_STATE,F; GO TO NEXT STATE

	MOVLW	D'3'
	SUBWF	IR_STATE,W
	BTFSS	STATUS,Z
	GOTO	IRI_RB2

	; STORE 1ST BYTE
	MOVFW	IR_INCOMING
	MOVWF	IR_COMMAND
	CLRF	IR_INCOMING
	GOTO	IRI_END

IRI_RB2

	MOVLW	D'4'
	SUBWF	IR_STATE,W
	BTFSS	STATUS,Z
	GOTO	IRI_RB3

	; COMPARE 1ST AND SECOND BYTES (SHOULD BE OxFF AND COMPLEMENTARY)
	MOVFW	IR_INCOMING
	XORWF	IR_COMMAND,W
	SUBLW	0XFF
	BTFSS	STATUS,Z
	GOTO	IRI_TIMEOUT	; RX ERROR - RESET

	; BYTE OKAY
;BSF	PORTB,TEST_OP2
	CLRF	IR_INCOMING
	GOTO	IRI_END

IRI_RB3

	MOVLW	D'5'
	SUBWF	IR_STATE,W
	BTFSS	STATUS,Z
	GOTO	IRI_RB4

	; STORE 3RD BYTE
	MOVFW	IR_INCOMING
	MOVWF	IR_COMMAND
	CLRF	IR_INCOMING
	GOTO	IRI_END

IRI_RB4

	MOVLW	D'6'
	SUBWF	IR_STATE,W
	BTFSS	STATUS,Z
	GOTO	IRI_RB5

	; COMPARE 1ST AND SECOND BYTES (SHOULD BE COMPLEMENTARY)
	MOVFW	IR_INCOMING
	XORWF	IR_COMMAND,W
	SUBLW	0XFF
	BTFSS	STATUS,Z
	GOTO	IRI_TIMEOUT	; RX ERROR - RESET

	; BYTE OKAY - GOT COMMAND!
	GOTO	EXECUTE_COMMAND

IRI_RB5
	; SHOULDN'T GET HERE, SO RESET
	GOTO	IRI_TIMEOUT	; RX ERROR - RESET

IRI_RB1
	; ROTATE BYTE
	BCF	STATUS,C
	RLF	IR_INCOMING,F
	GOTO	IRI_END

EXECUTE_COMMAND

	; INDICATE RX BY BLINKING LAMPS

	CASE IR_COMMAND_1,IR_COMMAND
	GOTO	SETMODE_1

	CASE IR_COMMAND_2,IR_COMMAND
	GOTO	SETMODE_2

	CASE IR_COMMAND_3,IR_COMMAND
	GOTO	SETMODE_3

	CASE IR_COMMAND_4,IR_COMMAND
	GOTO	SETMODE_4

	CASE IR_COMMAND_UP,IR_COMMAND
	GOTO	SETMODE_UP

	CASE IR_COMMAND_DOWN,IR_COMMAND
	GOTO	SETMODE_DOWN

	CASE IR_COMMAND_RED,IR_COMMAND
	GOTO	SETMODE_RED

	CASE IR_COMMAND_GRN,IR_COMMAND
	GOTO	SETMODE_GRN

	CASE IR_COMMAND_BLU,IR_COMMAND
	GOTO	SETMODE_BLU

	CASE IR_COMMAND_STOP,IR_COMMAND
	GOTO	SETMODE_STOP

	CASE IR_COMMAND_MUTE,IR_COMMAND
	GOTO	MUTE_MODE

	CASE IR_COMMAND_5,IR_COMMAND
	GOTO	SETMODE_5

	CASE IR_COMMAND_6,IR_COMMAND
	GOTO	SETMODE_6

	CASE IR_COMMAND_7,IR_COMMAND
	GOTO	SETMODE_7

	CASE IR_COMMAND_8,IR_COMMAND
	GOTO	SETMODE_8

	CASE IR_COMMAND_9,IR_COMMAND
	GOTO	SETMODE_9

	CASE IR_COMMAND_0,IR_COMMAND
	GOTO	SETMODE_0

	GOTO	EC_END2	;NO SOUND/WAKEUP FOR UNRECOGNISED COMMANDS	
EC_END
	BCF	SYSTEM,STANDBY
	BSF	SYSTEM,SOUND; START SOUND
EC_END2
	GOTO	IRI_TIMEOUT
	GOTO	IRI_END

SETMODE_1
	CLRF	SYNC	; BREAK PAUSE
	CLRF	CUR_COLOUR
	CLRF	MODE
	BSF	MODE,0
	GOTO	EC_END

SETMODE_2
	CLRF	SYNC	; BREAK PAUSE
	CLRF	CUR_COLOUR
	CLRF	MODE
	BSF	MODE,1
	GOTO	EC_END

SETMODE_3
	CLRF	SYNC	; BREAK PAUSE
	CLRF	CUR_COLOUR
	CLRF	MODE
	BSF	MODE,2
	GOTO	EC_END

SETMODE_4
	CLRF	SYNC	; BREAK PAUSE
	CLRF	MODE
	BSF	MODE,3
	GOTO	EC_END

SETMODE_5
	CLRF	SYNC	; BREAK PAUSE
	CLRF	MODE
	BSF	MODE,4	; DUMMY MODE (NO ANIMATION)
	CALL	RED
	GOTO	EC_END

SETMODE_6
	CLRF	SYNC	; BREAK PAUSE
	CLRF	MODE
	BSF	MODE,4	; DUMMY MODE (NO ANIMATION)
	CALL	GREEN
	GOTO	EC_END

SETMODE_7
	CLRF	SYNC	; BREAK PAUSE
	CLRF	MODE
	BSF	MODE,4	; DUMMY MODE (NO ANIMATION)
	CALL	BLUE
	GOTO	EC_END

SETMODE_8
	CLRF	SYNC	; BREAK PAUSE
	CLRF	MODE
	BSF	MODE,4	; DUMMY MODE (NO ANIMATION)
	CALL	MAGENTA
	GOTO	EC_END

SETMODE_9
	CLRF	SYNC	; BREAK PAUSE
	CLRF	MODE
	BSF	MODE,4	; DUMMY MODE (NO ANIMATION)
	CALL	CYAN
	GOTO	EC_END

SETMODE_0
	CLRF	SYNC	; BREAK PAUSE
	CLRF	MODE
	BSF	MODE,4	; DUMMY MODE (NO ANIMATION)
	CALL	YELLOW
	GOTO	EC_END

SETMODE_UP
	MOVF	CUR_COLOUR,F
	BTFSS	STATUS,Z
	GOTO	COLOUR_UP

	DECFSZ	SPEED,F
	GOTO	EC_END
	BSF	SPEED,0

	GOTO	EC_END

SETMODE_DOWN
	MOVF	CUR_COLOUR,F
	BTFSS	STATUS,Z
	GOTO	COLOUR_DOWN

	INCFSZ	SPEED,F
	GOTO	EC_END
	COMF	SPEED

	GOTO	EC_END

SETMODE_RED
	BTFSS	MODE,3
	GOTO	EC_END

	CLRF	CUR_COLOUR
	BSF	CUR_COLOUR,0
	CALL	UPDATE_COLOURS
	GOTO	EC_END

SETMODE_GRN
	BTFSS	MODE,3
	GOTO	EC_END

	CLRF	CUR_COLOUR
	BSF	CUR_COLOUR,1
	CALL	UPDATE_COLOURS
	GOTO	EC_END

SETMODE_BLU
	BTFSS	MODE,3
	GOTO	EC_END

	CLRF	CUR_COLOUR
	BSF	CUR_COLOUR,2
	CALL	UPDATE_COLOURS
	GOTO	EC_END

SETMODE_STOP
	BSF	SYSTEM,STANDBY
	GOTO	EC_END2

COLOUR_DOWN
	BTFSS	CUR_COLOUR,0
	GOTO	CU1
	INCF	XRED_LEVEL,W
	ANDLW	0X1F
	BTFSC	STATUS,Z
	MOVLW	0X1F
	MOVWF	XRED_LEVEL
CU1

	BTFSS	CUR_COLOUR,1
	GOTO	CU2
	INCF	XGRN_LEVEL,W
	ANDLW	0X1F
	BTFSC	STATUS,Z
	MOVLW	0X1F
	MOVWF	XGRN_LEVEL
CU2

	BTFSS	CUR_COLOUR,2
	GOTO	CU3
	INCF	XBLU_LEVEL,W
	ANDLW	0X1F
	BTFSC	STATUS,Z
	MOVLW	0X1F
	MOVWF	XBLU_LEVEL
CU3
	CALL	UPDATE_COLOURS
	GOTO	EC_END

UPDATE_COLOURS

	MOVFW	XRED_LEVEL
	CALL	LIN_LOG
	MOVWF	RED_LEVEL

	MOVFW	XGRN_LEVEL
	CALL	LIN_LOG
	MOVWF	GRN_LEVEL

	MOVFW	XBLU_LEVEL
	CALL	LIN_LOG
	MOVWF	BLU_LEVEL

	RETURN

COLOUR_UP
	BTFSS	CUR_COLOUR,0
	GOTO	CD1

	MOVF	XRED_LEVEL,W
	BTFSS	STATUS,Z
	DECF	XRED_LEVEL,W
	MOVWF	XRED_LEVEL
CD1
	BTFSS	CUR_COLOUR,1
	GOTO	CD2

	MOVF	XGRN_LEVEL,W
	BTFSS	STATUS,Z
	DECF	XGRN_LEVEL,W
	MOVWF	XGRN_LEVEL
CD2
	BTFSS	CUR_COLOUR,2
	GOTO	CD3

	MOVF	XBLU_LEVEL,W
	BTFSS	STATUS,Z
	DECF	XBLU_LEVEL,W
	MOVWF	XBLU_LEVEL
CD3
	CALL	UPDATE_COLOURS
	GOTO	EC_END

LIN_LOG ; in: W = LIN
	;out: W = LOG
	ANDLW 0X1F	; MAKE SURE IN RANGE
	CALL LOG_LOOKUP
	RETURN

RED
	; RED
	MOVLW	0XFF
	MOVWF	RED_LEVEL
	CLRF	GRN_LEVEL
	CLRF	BLU_LEVEL
	RETURN

GREEN
	; GREEN
	MOVLW	0XFF
	MOVWF	GRN_LEVEL
	CLRF	RED_LEVEL
	CLRF	BLU_LEVEL
	RETURN

BLUE
	; BLUE
	MOVLW	0XFF
	MOVWF	BLU_LEVEL
	CLRF	GRN_LEVEL
	CLRF	RED_LEVEL
	RETURN

YELLOW
	; YELLOW
	MOVLW	0XFF
	MOVWF	RED_LEVEL
	MOVWF	GRN_LEVEL
	CLRF	BLU_LEVEL
	RETURN

MAGENTA
	; MAGENTA
	MOVLW	0XFF
	MOVWF	RED_LEVEL
	CLRF	GRN_LEVEL
	MOVWF	BLU_LEVEL
	RETURN

CYAN
	; CYAN
	MOVLW	0XFF
	CLRF	RED_LEVEL
	MOVWF	GRN_LEVEL
	MOVWF	BLU_LEVEL
	RETURN

WHITE
	; WHITE
	MOVLW	0XFF
	MOVWF	RED_LEVEL
	MOVWF	GRN_LEVEL
	MOVWF	BLU_LEVEL
	RETURN

KKOFF
	CLRF	RED_LEVEL
	CLRF	GRN_LEVEL
	CLRF	BLU_LEVEL
	RETURN

STANDBY_MODE
;	CLRF	PORTB
	CLRF	PORTA
	MOVF	IR_STATE,F; DON'T SLEEP IF WE'RE IN THE MIDDLE OF RECEPTION (!0)
	BTFSC	STATUS,Z
	SLEEP
	RETURN

MUTE_MODE
	BTFSS	SYSTEM,MUTE
	GOTO	MM1
	BCF	SYSTEM,MUTE
	RETURN
MM1
	BSF	SYSTEM,MUTE
	RETURN

	END
