;--------------------------------------------------------
;
; Emulation of Olympus RM-1 IR remote control using PIC 12F629.
;
; The PIC GPIO 5 controls an IR-LED via one BC547 and a 2.7Ohm
; resistor in series.
;
; Olympus control codes are:
;
; Button GPIO Code
;
; Fire 0 0110 0001 1101 1100 1000 0000 0111 1111
; W 1 0110 0001 1101 1100 0100 0000 1011 1111
; T 2 0110 0001 1101 1100 1100 0000 0011 1111
; - 3 0110 0001 1101 1100 0010 0000 1101 1111
; + 4 0110 0001 1101 1100 1010 0000 0101 1111
;
; Modulation is 40 kHz symmetrical pulse modulation.
;
; Each command starts with 3.8 ms 40kHz pulse train followed by
; 4ms Low state on GP5 and finished off with 550us 40kHz pulse train.
;
; 1 = 1500us GP5 Low state followed by 500us 40kHz pulse train.
; 0 = 500us GP5 Low state followed by 500us 40kHz pulse train.
;
; After each button press there is a 500ms button repeat delay.
;
;
	title "Olyremote-1"

	include "P12F629.INC"
	__config _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _BODEN_OFF

	errorlevel -302 ; No bank selection messages

;--------------------------------------------------------
;
; REGISTER DEFINITION
;
;--------------------------------------------------------


DELAY_H equ 0x20
DELAY_L equ 0x21
IR_LENGTH equ 0x22

;--------------------------------------------------------
;
;
; CODE
;
;--------------------------------------------------------


	org 0x0000 ; RESET VECTOR

;--------------------------------------------------------
;
; Initialize PIC
;
initialize_pic

	bsf STATUS,RP0 ; Sel Bank 1
	call 0x3ff ; Get OSCAL value
	movwf OSCCAL ; write to OSCCAL register

	bcf OPTION_REG,7 ; Enable weak pullups
	movlw b'00010111' ; on GPIO 0-4
	movwf WPU

	movlw b'00001000' ; Enable port change interrupt
	movwf INTCON

	bcf STATUS,RP0 ; Select bank 0
	clrf GPIO ; Init GPIO
	movlw 0x07 ; set GP2 to digital
	movwf CMCON

	bsf STATUS,RP0
	movlw b'00011111'
	movwf TRISIO ; Set I/O 5 as outputs

	movlw 0x1f ; Enable port change IRQ on GPIO 0-4
	movwf IOC

	bcf STATUS,RP0 ; Select bank 0
	bcf GPIO,5 ; Set GPIO 5 Low

;--------------------------------------------------------
;
led_main_loop

	bcf INTCON,GPIF ; Clear interrupt flag
	bcf GPIO,5 ; Set GPIO 5 Low

	sleep ; and go to sleep to save power
;
; Wake up from sleep
; Check which button generated wake-up
;
Test_W
	MOVF GPIO,W ; Read GPIO and test for W button
	ANDLW b'00000001' ; Mask for the W switch
	BTFSS STATUS,Z ; Check ZERO first
	goto Test_F
	call Exec_W
	goto led_main_loop

Test_F
	MOVF GPIO,W ; Read GPIO and test for Fire button
	ANDLW b'00000010' ; Mask for the Fire switch
	BTFSS STATUS,Z ; Check ZERO
	goto Test_T ; Not Z
	call Fire
	goto led_main_loop

Test_T
	MOVF GPIO,W ; Read GPIO and test for Fire button
	ANDLW b'00000100' ; Mask for the Fire switch
	BTFSS STATUS,Z ; Check ZERO
	goto Test_M ; Not Z
	call Exec_T
	goto led_main_loop

Test_M
	MOVF GPIO,W ; Read GPIO and test for Fire button
	ANDLW b'00001000' ; Mask for the Fire switch
	BTFSS STATUS,Z ; Check ZERO
	goto Test_P ; Not Z
	call Exec_M
	goto led_main_loop

Test_P
	MOVF GPIO,W ; Read GPIO and test for Fire button
	ANDLW b'00010000' ; Mask for the Fire switch
	BTFSS STATUS,Z ; Check ZERO
	goto led_main_loop ; Not Z
	call Exec_P
	goto led_main_loop

;--------------------------------------------------------
;
; SUBROUTINES
;
;--------------------------------------------------------

;--------------------------------------------------------
;
; The FIRE button was pressed, execute control sequence
;
; Fire = 0110 0001 1101 1100 1000 0000 0111 1111
;
Fire
	call Send_Header

	call Send_One
	call Send_Null
	call Send_Null
	call Send_Null

	call Send_Null
	call Send_Null
	call Send_Null
	call Send_Null

	call Send_Null
	call Send_One
	call Send_One
	call Send_One

	call Send_One
	call Send_One
	call Send_One
	call Send_One

	movlw .250
	call DELAY_X_msec ; 250ms delay before return
	movlw .250
	call DELAY_X_msec ; 250ms delay before return
	return

;--------------------------------------------------------
;
; The W button was pressed, execute control sequence
;
; W = 0110 0001 1101 1100 0100 0000 1011 1111
;
Exec_W
	Call Send_Header

	Call Send_Null
	Call Send_One
	Call Send_Null
	Call Send_Null

	Call Send_Null
	Call Send_Null
	Call Send_Null
	Call Send_Null

	Call Send_One
	call Send_Null
	call Send_One
	call Send_One

	call Send_One
	call Send_One
	call Send_One
	call Send_One

	movlw .250
	call DELAY_X_msec ; 250ms delay before return
	movlw .250
	call DELAY_X_msec ; 250ms delay before return
	return

;--------------------------------------------------------
;
; The T button was pressed, execute control sequence
;
; T = 0110 0001 1101 1100 1100 0000 0011 1111
;
Exec_T
	Call Send_Header

	Call Send_One
	Call Send_One
	call Send_Null
	call Send_Null

	call Send_Null
	call Send_Null
	call Send_Null
	call Send_Null

	call Send_Null
	call Send_Null
	call Send_One
	call Send_One

	call Send_One
	call Send_One
	call Send_One
	call Send_One

	movlw .250
	call DELAY_X_msec ; 250ms delay before return
	movlw .250
	call DELAY_X_msec ; 250ms delay before return
	return

;--------------------------------------------------------
;
; The - button was pressed, execute control sequence
;
; - = 0110 0001 1101 1100 0010 0000 1101 1111
;
Exec_M
	Call Send_Header

	Call Send_Null
	Call Send_Null
	Call Send_One
	Call Send_Null

	Call Send_Null
	Call Send_Null
	Call Send_Null
	call Send_Null

	call Send_One
	call Send_One
	call Send_Null
	call Send_One

	call Send_One
	call Send_One
	call Send_One
	call Send_One

	movlw .250
	call DELAY_X_msec ; 250ms delay before return
	movlw .250
	call DELAY_X_msec ; 250ms delay before return
	return

;--------------------------------------------------------
;
; The + button was pressed, execute control sequence
;
; + = 0110 0001 1101 1100 1010 0000 0101 1111
;
Exec_P
	call Send_Header

	call Send_One
	call Send_Null
	call Send_One
	call Send_Null

	call Send_Null
	call Send_Null
	call Send_Null
	call Send_Null

	call Send_Null
	call Send_One
	call Send_Null
	call Send_One

	call Send_One
	call Send_One
	call Send_One
	call Send_One

	movlw .250
	call DELAY_X_msec ; 250ms delay before return
	movlw .250
	call DELAY_X_msec ; 250ms delay before return
	return

;--------------------------------------------------------
;
; Send_Header: Remote codes must starts with this sequence.
;
Send_Header
	movlw .120 ; Pulse 8ms
	call Send_IR_Pulse
	movlw .200
	call Send_IR_Pulse
	movlw .4 ; Space 4ms
	call DELAY_X_msec
	movlw .22 ; Pulse 550us
	call Send_IR_Pulse

	call Send_Null
	call Send_One
	call Send_One
	call Send_Null

	call Send_Null
	call Send_Null
	call Send_Null
	call Send_One

	call Send_One
	call Send_One
	call Send_Null
	call Send_One

	call Send_One
	call Send_One
	call Send_Null
	call Send_Null

	return

;--------------------------------------------------------
;
; Send_One: Sends 1677us low signal followed by pulse
; modulated by 40kHz (25us) symetrical pulses sent
; for 559us. Corresponds to Olympus IR code "1"
Send_One
	Call Delay_1500us ; Space 1677us
	movlw .22
	call Send_IR_Pulse
	return

;--------------------------------------------------------
;
; Send_Null: Sends 559us low signal followed by pulse
; modulated by 40kHz (25us) symetrical pulses sent
; for 559us. Corresponds Olympus IR code "0"
Send_Null
	call Delay_500us ; Space 559us
	movlw .22 ; Pulse
	call Send_IR_Pulse
	return

;--------------------------------------------------------
;
; Send_IR_Pulse will send a 50% duty cycle pulse until
; IR_LENGTH is zero. Puls sent on GPIO 5
;
Send_IR_Pulse
	movwf IR_LENGTH ; Save number of IR cycles
IR_Pulse ; loop
	movlw .3 ; set this to 3 to get 40kHz modulation
	movwf DELAY_L
	bsf GPIO,5 ; Set GPIO 5 High
High_20
	decfsz DELAY_L,F ; This gives about 12 us High
	goto High_20
	nop ; set this two nops to get 40kHz modulation
	nop
	movlw .2 ; set this to 2 to get 40kHz modulation
	movwf DELAY_L
	bcf GPIO,5 ; Set GPIO 5 Low
Low_20
	decfsz DELAY_L,F ; This gives about 12 us Low
	goto Low_20
	nop
	decfsz IR_LENGTH,F ; Decrement IR cycle counter
	goto IR_Pulse ; and loop if not zero
	nop
	return

;--------------------------------------------------------
;
; Delay routines for correct output pulse width
;
; This delay is used for output pulse width control
;
DELAY_X_msec ; Call here with W = X msec delay
	MOVWF DELAY_H

DELAY_1msec
	MOVLW .250 ; 1 msec delay loop counter
	MOVWF DELAY_L

DELAY_1ms ; 1 msec delay loop
	NOP
	DECFSZ DELAY_L, F
	GOTO DELAY_1ms

	DECFSZ DELAY_H, F ; Loop counter 1 msec delay loop
	GOTO DELAY_1msec ; until counter is zero
	RETLW 0

;--------------------------------------------------------
;
Delay_1500us

	call Delay_500us
	call Delay_500us

;--------------------------------------------------------
;
Delay_500us
	movlw .122
	MOVWF DELAY_L
	call DELAY_4us
	nop
	nop
	return

;--------------------------------------------------------
;
DELAY_4us ; 4usec delay loop.
	NOP
	DECFSZ DELAY_L, F
	GOTO DELAY_4us
	return
	end 