
;************************************************************************************************************************
; 
;     RECEPTOR DE CONTROLE REMOTO PARA PORTÃO
;
;
;     BY CLÁUDIO LÁRIOS      17-11-2011    PUBLICADO:19/05/2012
;
;
;
;
;	PROJETO BASEADO EM 'NOTE APLICATTION MICROCHIP/KEELOG' ADAPTADO PARA FUNCIONAR COM EEPROM INTERNA DO
;	PIC 12F629 E PARA ESTA APLICAÇÃO ESPECIFICA. USE OSCILADOR INTERNO DE 4 MHZ. RESET INTERNO (PINO COMO ENTRADA)
;     USO RESTRITO PARA FINS NÃO COMERCIAIS APENAS.
;     (CUIDADOS ESPECIAIS DEVEM SER TOMADOS AO MANUSEAR EQUIPAMENTO ELETRICO LIGADOS NA REDE ELETRICA.)
;	FUNÇÃO: RECEBER SINAL DE UM HCS200/201/300/301  E DECODIFICAR
;     ACIONANDO  SAIDAS TEMPORIZADAS NO PIC.
;	OBS.  GRAVAR A MESMA CHAVE NO HCS E NO PIC PARA FUNCIONAR.
;	GRAVADOR: USE HCS_PROG OU HCS_PROG_TINY  PARA GRAVAR HCS200...301.
;     USE A MESMA 'KEY' AQUI E NO TRANSMISSOR. USE:DISC=SERIAL 
;     PODE APRENDER ATÉ 15 'CHAVEIRINHOS' (TRANSMISSORES)
;     APERTE 'LRN' E DEPOIS ACIONE O CONTROLE REMOTO PARA APRENDER SEU CÓDIGO.
;     APERTE 'LRN' POR MAIS DE 15 SEG PARA APAGAR TODOS OS CONTROLES DA MEMÓRIA (PERDA/ROUBO DE CONTROLE).
;     APÓS ISTO, OS CONTROLES RESTANTES TEM QUE SEREM REAPRENDIDOS.
;     USA O PINO 2 (GP5) TANTO COMO SAIDA PARA APAGAR LED LEARN COMO ENTRADA PARA RECONHECER APRENDIZADO.
;    
;------------------------------------------------------------------------------
;	PINAGEM DO PIC 12F629:
;	PINO 1- +VCC
;	PINO 2- IN/OUT - LED 'LEARN' AO +VCC VIA RESISTOR DE 4K7 AO PINO 2 E  DO PINO 2 AO RESISTOR DE 470 A CHAVE 'LRN' A MASSA 
;  	PINO 3- IN - INTERRUPTOR FIM DE CURSO S2 A MASSA.NÃO NECESSITA DE PULL-UP.  USE REEDSWITCH COM UM IMÃ PERMANENTE.
;	PINO 4- IN - PULLUP 10K AO VCC E  INTERRUPTOR FIM DE CURSO S1 A MASSA.      USE REEDSWITCH COM UM IMÃ PERMANENTE.
;	PINO 5- SAIDA RELE M1 VIA TRANSISTOR NPN
;	PINO 6- SAIDA RELE M2 VIA TRANSISTOR NPN
;	PINO 7- IN RF  (ENTRADA DE PULSOS)OBS. USE UM DIODO E RESISTORES PARA REDUZIR RUIDO DO TX
;	PINO 8-	MASSA

;------------------------------------------------------------------------------
; SIMPLE DECODER WITH ONE STEP LEARN AND SINGLE KEY


	LIST P=12f629 , R=DEC
	INCLUDE "P12F629.INC"

;--------------------------
	ERRORLEVEL      -302   
	__CONFIG _CP_OFF & _PWRTE_ON & _WDT_ON & _INTRC_OSC_NOCLKOUT  & _BODEN_ON & _MCLRE_OFF       
;----------------------------------------------------
;******USER DEFINITIONS******
MAX_USERS	EQU	.15
; This is the maximum number of transmitters that the system is able to 
; learn (1 to 15).  
;------------------------------------------------------------------------------
#DEFINE		BANK0	BCF	STATUS,RP0 	;SETA BANK0 DE MEMORIA
#DEFINE		BANK1	BSF	STATUS,RP0	;SETA BANK1
; GENERAL PURPOSE REGISTERS

IND		EQU	00H		; INDIRECT ADDRESS REGISTER
RTCC	EQU	01H		; REAL TIME COUNTER CLOCK
PC		EQU	02H		; PROGRAM COUNTER
STATUS	EQU	03H             ; STATUS REGISTER
FSR		EQU	04H		; FILE SELECT REGISTER
PORTA   EQU 05H		; PORT A
PORTB   EQU 06H		; PORT B
;CMCON   EQU 1FH	;CONTROLE DOS COMPARADORES

; USER DEFINED REGISTER
AFLAG   EQU  40H	     ;FLAG PARA O ALARME
#DEFINE  FLEDP  AFLAG,4  ;FLAG AUXILIAR P/ O PISCAR DO  LED
#DEFINE  ON     AFLAG,0  ;FLAG AUXILIAR P/ ON/OFF DO ALARME
#DEFINE  FLRN	AFLAG,2  ;FLAG AUXILIAR DE LEARN ATIVADO
#DEFINE  FPA    AFLAG,3 ; FLAG DE PORTA ABERTA
#DEFINE  ONA    AFLAG,1 ; FLAG DE LIGAR POR TEMPO INICIAL
;--------------------------------------------------------
FLAGS	EQU	20H		; USER FLAG REGISTER
ADDRESS	EQU	21H		; ADDRESS REGISTER
TXNUM	EQU	22H		; CURRENT TX
OUTBYT	EQU	23H		; GENERAL DATA REGISTER
MASK	EQU	OUTBYT		; MASK REGISTER USED IN DECRYPTION
TMP_CNT	EQU	OUTBYT		; TEMPORARY COUNTER

; COUNTER REGISTERS

CNT0    EQU     24H		; LOOP COUNTERS
CNT1    EQU		25H		
CNT2    EQU     26H		

CNT_HI	EQU	27H		; 16 BIT CLOCK COUNTER
CNT_LW	EQU	28H	

CNT_HIX EQU 41H		;CONTADOR EXTRA PARA ALARME HIGH (TEMPO DE 3 MIN)
CNT_LWX EQU 42H		;CONTADOR EXTRA PARA ALARME  LOW	

; CIRCULAR BUFFER REGISTER

CSR0    EQU     29H            	; 64 BIT RECEIVE SHIFT REGISTER
CSR1    EQU     2AH            
CSR2    EQU     2BH            
CSR3    EQU     2CH            
CSR4    EQU     2DH            	
CSR5    EQU     2EH            
CSR6    EQU     2FH            
CSR7    EQU     30H            

; TEMP REGISTERS
TMP1	EQU	31H		; TEMP REGISTER FOR READ AND WRITE
TMP2	EQU	32H		; TEMP REGISTER FOR READ AND WRITE
REG		EQU	33H		; NOT USED
REG1	EQU	34H		; NOT USED

KEY0	EQU	35H		; 64 BIT KEY SHIFT REGISTER
KEY1	EQU	36H
KEY2	EQU	37H
KEY3	EQU	38H
KEY4	EQU	CNT2
KEY5	EQU	CSR5
KEY6	EQU	CSR6
KEY7	EQU	CSR7
AUX		EQU 39H
AUX8    EQU 46H
SITUAÇÃO EQU 47H
R1	EQU 3AH
R2	EQU 3BH
STMP1  EQU 3CH
STMP2  EQU 3DH
SADDRESS EQU 3EH
SW		EQU  3FH
CP      EQU  43H
FILTRO1  EQU  44H
FILTRO2  EQU  45H

TF2		EQU  .5
; ***** USER REGISTER RE-MAPPINGS ***************

HOP1	EQU	CSR0		; 32 BIT HOPCODE REGISTER
HOP2	EQU	CSR1
HOP3	EQU	CSR2
HOP4	EQU	CSR3

; RECEIVED TRANSMISSION OPEN 32 BITS 

SER_0	EQU	CSR7		; 28 BIT SERIAL NUMBER
SER_1	EQU	CSR6
SER_2	EQU	CSR5
SER_3	EQU	CSR4

; RECEIVED TRANSMISSION ENCRYPTED 32 BITS 

FUNC	EQU	CSR3		; BUTTON CODE & USER BIT FUNCTION BYTE
DISC	EQU	CSR2		; DISCRIMINATION VALUE
CNTR_HI	EQU	CSR1		; 16 BIT RX COUNTER HIGH BYTE
CNTR_LW	EQU	CSR0		; 16 BIT RX COUNTER LOW BYTE

; ********* EEPROM MEMORY *******
LRNPTR	EQU	3FH		; LEARN POINTER 01H


;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


#DEFINE RFIN 		GPIO,0  ;PINO 7 IN RF
#DEFINE LRN  		GPIO,5	;PINO 4 IN LEARN BOTTON
#DEFINE LED  		GPIO,5  ;PINO 2 OUT LED (MESMO PINO DO ACIMA)
#DEFINE S2      	GPIO,4  ;PINO 3- ENTRADA DE S2 ,ACIONA COM NEGATIVO
#DEFINE M1      	GPIO,2	;PINO 5 -SAIDA DO MOTOR
#DEFINE M2      	GPIO,1  ;PINO 6-SAIDA DO MOTOR
#DEFINE S1      	GPIO,3  ;PINO 3- ENTRADA DE S1 ,ACIONA COM NEGATIVO

; ********* COMPILER DEFINES ******************
NBITS   EQU     .64      	; MAXIMUM TRANSMISSION BIT LENGTH
MIN     EQU     .560            	; TRANSMISSION HEADER MINIMUM LENGTH [ S]
ITRISA	EQU	B'111001'		; PORTA: TRI-STATE VALUE  GP5 LED/LRN COMO ENTRADA INICIALMENTE
OTRISA  EQU B'011001'       ; PORTA: TRI-STATE VALUE  GP5 LED/LRN COMO SAIDA PARA APAGA LED
;****** FLAGS DEFINITIONS **************
BITIN	EQU	0H		; RF BIT VALUE 
LRNF	EQU	1H		; LEARN FLAG
SEC_CNT	EQU	2H		; SECOND COUNTER IS BEING CHECKED
RELEARN	EQU	3H		; RELEARNING A TRANSMITTER

;****** STATUS REGISTER BIT DEFINITIONS *****************
C       EQU       0		; CARRY
DC      EQU       1		; DIGIT CARRY
Z       EQU       2		; ZERO
PD      EQU       3		; POWER DOWN
TO      EQU       4		; TIMEOUT
PA0     EQU       5		; NOT USED
PA1     EQU       6		; NOT USED 

;------------------------------------------------------------------------------
 	ORG	H'2100'  ;vetor de eeprom
;------------------------------------------------------------------------------
	ORG 00H
	goto RESET

	ORG 04H
	RETFIE
;------------------------------------------------------------------------------
;
; FUNCTION     : RESET ()	      			
;
;
;------------------------------------------------------------------------------

RESET
	

	MOVLW   0X07
	MOVWF	CMCON			;DESLIGA COMPARADORES	

	MOVLW	B'000111'			; SETUP RTCC PRESCALER
	OPTION
	CLRF	GPIO			; RESET PORTA
	MOVLW	ITRISA			; SETUP PORTA
	TRIS	GPIO
	CLRF    CNT_HIX
	CLRF	CNT_LWX			;APAGA CONTADORES AUXILIARES DE TEMPO
	CLRF	FLAGS			; RESET FLAGS
	GOTO	M_LOOP			; GOTO MAIN PROGRAM LOOP



;-----------------------------------------------------------------

; FUNCTION     	: ROT_SHIFT()	      			
;
; DESCRIPTION  	: RIGHT ROTATE 64 BIT RECEIVE SHIFT REGISTER
;
;------------------------------------------------------------------------------

ROT_SHIFT
        RRF     CSR7,F
        RRF     CSR6,F
        RRF     CSR5,F                     
        RRF     CSR4,F                     
        RRF     CSR3,F                     
        RRF     CSR2,F                     
        RRF     CSR1,F                    
        RRF     CSR0,F                    
	RETLW	.0

;------------------------------------------------------------------------------
;
; FUNCTION     	: TX_LOOKUP ()	      			
;
; DESCRIPTION  	: TRANSMITTER ADDRESS CALCULATION
;
;------------------------------------------------------------------------------

TX_LOOKUP
	MOVF	TXNUM,W			; USE TRANSMITTER NUMBER TO CALCULATE 
	MOVWF	ADDRESS			; ADDRESS OF TRANSMITER BLOCK
	CLRC				; MULTIPLY BY 4 
	RLF	ADDRESS,F
	RLF	ADDRESS,F
	RETLW	.0			; RETURN

;------------------------------------------------------------------------------
;
; FUNCTION     	: TST_RTCC ()	      			
;
; DESCRIPTION  	: UPDATE RTCC COUNTER 
;
;------------------------------------------------------------------------------
TST_RTCC
	CLRWDT				; RESET WATCHDOG TIMER
	MOVLW	ITRISA			; UPDATE TRI-STATE REGISTER FOR PORTA
	TRIS	GPIO

	BTFSS	RTCC,7			; TEST FOR 32MS TIMEOUT	ON RTCC MSB
	RETLW	.0			; ... DO QUICK RETURN TO RECEIVE ROUTINE

; **** INCREASE 16 BIT CLOCK TIMER *******
	BTFSS	CNT_HIX,2
	GOTO    Y8
    BCF     M1          ;DESLIGA MOTORES APOS 22 SEG (CNT_HIX,2) [PARA 44SEG USE CNT_HIX,3]
    BCF     M2	
    CLRF   CNT_HIX
    CLRF   CNT_LWX

	INCF   SITUAÇÃO,F    ;EVITA UM APERTO A MAIS QUANDO MOTOR PARA POR TEMPO
Y8
	BCF	RTCC,7			; CLEAR MSB OF RTCC
	INCF	CNT_LW,F		; INCREASE 16 COUNTER
	SKPNZ				; INCREASE UPPER BYTE IF ZERO ( OVERFLOW )
	INCF	CNT_HI,F
	INCF	CNT_LWX,F	; INCREASE 16 COUNTER ADICIONAL
	SKPNZ				; INCREASE UPPER BYTE IF ZERO ( OVERFLOW )
	INCF	CNT_HIX,F	;CONTAGEM MAXIMA 34 MIN.
	RETURN

;------------------------------------------------------------------------------
;
; FUNCTION     	: TST_TIMER()	      			
;
; DESCRIPTION  	: TEST 32MS TIMER AND UPDATE OUTPUTS IF REQUIRED
;
;
;------------------------------------------------------------------------------

TST_TIMER
; ***** TEST FOR 500 MS TIMEMOUT ON OUTPUTS **********
;	BTFSS	CNT_LW,4		; TEST FOR 500 MS TIMEOUT
;	GOTO	TST_30			; ... IF NOT TEST 30S TIMEOUT

;	MOVLW	0F0H
;	ANDWF	PORTB,F			; DOWN ALL PULSE OUTPUTS 
;	CLRF    GPIO            ;DESLIGA SAIDAS
 ; ********* TEST FOR 30 S LEARN TIMEOUT *************
TST_30
	BTFSS	FLAGS,LRNF
	GOTO	TST_END	
	BTFSC	CNT_HI,2		; TEST FOR LEARN TIMEOUT
	BCF	FLRN				;APAGA FLAG 'LEARN'
	RETLW   1H

TST_END	
	RETLW	0H

;------------------------------------------------------------------------------
AGUARDE		;ROTINA DE ATRASO ENTRE OPERAÇÕES DE EEPROM

	MOVLW  .64
	MOVWF	R1
CG2
	CLRWDT
	MOVLW	.255
	MOVWF	R2
	
	DECFSZ	R2,F
	GOTO $-1
	DECFSZ	R1,F
	GOTO CG2
	RETURN
;------------------------------------------------------------------------------
;
; FUNCTION     	: EEWRITE ()	      			
;
; DESCRIPTION  	: WRITE 16 BIT VALUE TO EEPROM 
;
; 
;------------------------------------------------------------------------------

EEWRITE

; ******* EEPROM WRITE ENABLE ******************
;endereço esta em ADDRESS
;DADOS A ESCREVER ESTA EM TMP1(MSB)  E TMP2 (LSB)
	CALL AGUARDE
 	clrwdt	
	movfw ADDRESS	
	MOVWF	AUX
	BCF	STATUS,C
	RLF	AUX,F	;AUXILIAR X 2 
	MOVFW	AUX
	
	BANK1
	movwf EEADR	
	BANK0
	MOVFW  TMP1		;PEGA PRIMEIRO DADO
	BANK1
	movwf EEDATA
	bcf EECON1, EEIF	
	bsf EECON1, WREN ; enable Write\par
	movlw 0x55	
	movwf EECON2	
	movlw 0xAA	
	movwf EECON2	
	bsf EECON1, WR	
WRITE_SN_A clrwdt	
	btfsc EECON1, WR ; Write complete ?\par
	goto WRITE_SN_A	
	bcf EECON1, WREN ; disable Write\par
 	BANK0

	clrwdt	
	
ESPERA1			;DELAY ENTRE APAGAMENTOS
	CALL  AGUARDE
	
	INCF AUX,F
	MOVFW	AUX
	BANK1
	movwf EEADR	
	BANK0
	MOVFW  TMP2		;PEGA SEGUNDO DADO
	BANK1
	movwf EEDATA
	bcf EECON1, EEIF	
	bsf EECON1, WREN ; enable Write\par
	movlw 0x55	
	movwf EECON2	
	movlw 0xAA	
	movwf EECON2	
	bsf EECON1, WR	
WRITE_SN_B clrwdt	
	btfsc EECON1, WR ; Write complete ?\par
	goto WRITE_SN_B	
	bcf EECON1, WREN ; disable Write\par
 	BANK0
	CALL AGUARDE
	RETURN

;------------------------------------------------------------------------------
;
; FUNCTION     	: EEREAD ()	      			
;
; DESCRIPTION  	: READ 16 BIT VALUE FROM EEPROM 
;
; 
;
;------------------------------------------------------------------------------

EEREAD
;endereço esta em ADDRESS
;DADOS LIDOS SERÃO ESCRITOS EM TMP1(MSB)  E TMP2 (LSB)
        
	clrwdt	
	MOVFW  ADDRESS
	MOVWF	AUX
	BCF	STATUS,C
	RLF	AUX,F
	MOVFW	AUX

	BANK1
	movwf EEADR	
	bsf EECON1, RD ; do a read\par
	clrwdt	
	btfsc EECON1, RD ; Read done ?\par
	goto $-2	
	movf EEDATA,W
	BANK0
	MOVWF	TMP1	;RECUPERA PRIMEIRO NUMERO DA EEPROM
	clrwdt	

	INCF	AUX,F
	MOVFW	AUX
	BANK1
	movwf EEADR	
	bsf EECON1, RD ; do a read\par
	clrwdt	
	btfsc EECON1, RD ; Read done ?\par
	goto $-2	

	movf EEDATA,W
	BANK0
	MOVWF	TMP2	;RECUPERA SEGUNDO  NUMERO DA EEPROM
	clrwdt	
	RETLW	0H
;------------------------------------------------------------------------------
APAGAEEPROM ;OK TESTADA E APROVADA
; ROTINA PARA APAGAR TODAS AS POSIÇOES DA EEPROM DO 16F628
	


	MOVLW 0X80		;TOTAL DE 128 + 1 BYTES DE EEPROM
	MOVWF	AUX
RET6
	CLRWDT
	MOVFW	AUX
	MOVLW   .1  ;ACERTA ENDEREÇO TIRANDO 1
	SUBWF	AUX,W
	BANK1
	movwf EEADR	
	MOVLW	0XFF
	movwf EEDATA
	bcf EECON1, EEIF	
	bsf EECON1, WREN ; enable Write\par
	movlw 0x55	
	movwf EECON2	
	movlw 0xAA	
	movwf EECON2	
	bsf EECON1, WR	
WRITE_SN_C clrwdt	
	btfsc EECON1, WR ; Write complete ?\par
	goto WRITE_SN_C	
	bcf EECON1, WREN ; disable Write\par
 	BANK0
	DECFSZ	AUX,F
	GOTO  ESPERA
	clrwdt	
	RETLW 0H
ESPERA			;DELAY ENTRE APAGAMENTOS
	MOVLW  .8
	MOVWF	R1
CG1
	MOVLW	.255
	MOVWF	R2
	
	DECFSZ	R2,F
	GOTO $-1
	DECFSZ	R1,F
	GOTO CG1
	GOTO RET6
;------------------------------------------------------------------------------
;
; FUNCTION     	: DECRYPT ()	      			
;
; DESCRIPTION  	: DECRYPTS 32 BIT [HOP1:HOP4] USING [CSR0:CSR7]
;
;------------------------------------------------------------------------------



;ATENÇÃO!!!   ABAIXO ESTÁ A 'KEY' QUE TEM QUE SER A MESMA DO TRANSMISSOR
; SERVINDO QUALQUER ENCODER COMO HCS200 , 201, 300, 301 (O QUE TIVER DISPONIVEL )


; MUDE AQUI PARA O MESMO VALOR PARA SEU TRANSMISSOR (KEY QUE FOI PROGRAMADO NO HCS 200...301)	
DECRYPT
	MOVLW	001H		;MENOS SIGNIFICATIVO (LSB)
	MOVWF	KEY0
	MOVLW	023H
	MOVWF	KEY1
	MOVLW	045H
	MOVWF	KEY2
	MOVLW	067H
	MOVWF	KEY3
	MOVLW	089H
	MOVWF	KEY4
	MOVLW	0ABH
	MOVWF	KEY5
	MOVLW	0CDH
	MOVWF	KEY6
	MOVLW	0EFH		; LOAD FIXED 64 BIT KEY MSB
	MOVWF	KEY7

        MOVLW   .12            ; OUTER LOOP 11+1 TIMES 
        MOVWF   CNT1          	; OUTER LOOP 11+1 TIMES 

DECRYPT_OUTER

        MOVLW   .48              ; INNER LOOP 48 TIMES
        MOVWF   CNT0          	; INNER LOOP 48 TIMES

DECRYPT_INNER
	CLRWDT			; RESET WATCHDOG TIMER
        MOVFW   CNT1		; LAST 48 LOOPS RESTORE THE KEY
        XORLW   .1               ; LAST 48 LOOPS RESTORE THE KEY
        SKPNZ                   ; LAST 48 LOOPS RESTORE THE KEY
        GOTO    ROTATE_KEY      ; LAST 48 LOOPS RESTORE THE KEY

        ; THE LOOKUP TABLE IS COMPRESSED INTO IN 4 BYTES TO SAVE SPACE
        ; USE THE 3 LOW INDEX BITS TO MAKE UP AN 8-BIT BIT MASK
        ; USE THE 2 HIGH INDEX BITS TO LOOK UP THE VALUE IN THE TABLE
        ; USE THE BIT MASK TO ISOLATE THE CORRECT BIT IN THE BYTE
        ; PART OF THE REASON FOR THIS SCHEME IS BECAUSE NORMAL TABLE LOOKUP
        ; REQUIRES AN ADDITIONAL STACK LEVEL

        CLRC                    ; CLEAR CARRY (FOR THE LEFT SHIFT)
       
        MOVLW   .1               ; INITIALISE MASK = 1
        BTFSC   HOP3,3       	; SHIFT MASK 4X IF BIT 2 SET
        MOVLW   B'10000'          ; SHIFT MASK 4X IF BIT 2 SET
        MOVWF   MASK            ; INITIALISE MASK = 1

        BTFSS   HOP2,0       	; SHIFT MASK ANOTHER 2X IF BIT 1 SET
        GOTO    $+3
        RLF     MASK,F
        RLF     MASK,F            

        BTFSC   HOP1,0       	; SHIFT MASK ANOTHER 1X IF BIT 0 SET
        RLF     MASK,F

        ; MASK HAS NOW BEEN SHIFTED 0-7 TIMES ACCORDING TO BITS 2:1:0

        MOVLW   .0               ; TABLE INDEX = 0
        BTFSC   HOP4,1
        IORLW   .2               ; IF BIT 3 SET ADD 2 TO THE TABLE INDEX
        BTFSC   HOP4,6
        IORLW   .4               ; IF BIT 4 SET ADD 4 TO THE TABLE INDEX

		movwf	AUX
		MOVLW	.6
		SUBWF	AUX,W
		BTFSC	STATUS,Z
		GOTO  SEIS
		MOVLW	.4
		SUBWF	AUX,W
		BTFSC	STATUS,Z
		GOTO	QUATRO
		MOVLW	.2
		SUBWF	AUX,W
		BTFSC	STATUS,Z
		GOTO	DOIS
		MOVLW	02EH
		GOTO  TABLE_END
DOIS
		MOVLW	074H
		GOTO  TABLE_END
QUATRO
		MOVLW	05CH
		GOTO  TABLE_END
SEIS
		MOVLW	03AH
		GOTO  TABLE_END

 
                                 
TABLE_END

        ANDWF   MASK,F          ; ISOLATE THE CORRECT BIT BY ANDING WITH MASK
        MOVLW   .0               ; COPY THE BIT TO BIT 7
        SKPZ                    ; COPY THE BIT TO BIT 7
        MOVLW   B'10000000'       ; COPY THE BIT TO BIT 7

        XORWF   HOP2,W    	; ONLY INTERESTED IN BIT HOP2,7
        XORWF   HOP4,W    	; ONLY INTERESTED IN BIT HOP4,7
        XORWF   KEY1,W		; ONLY INTERESTED IN BIT KEYREG1,7

        MOVWF   MASK            ; STORE W TEMPORARILY (WE NEED BIT 7)
        RLF     MASK,F          ; LEFT ROTATE MASK TO GET BIT 7 INTO THE CARRY

        RLF     HOP1,F         	; SHIFT IN THE NEW BIT
        RLF     HOP2,F
        RLF     HOP3,F
        RLF     HOP4,F

ROTATE_KEY

        CLRC			; CLEAR CARRY
        BTFSC   KEY7,7       	; SET CARRY IF LEFTMOST BIT SET
        SETC                    ; SET CARRY IF LEFTMOST BIT SET

        RLF     KEY0,F         	; LEFT-ROTATE THE 64-BIT KEY 
        RLF     KEY1,F
        RLF     KEY2,F
        RLF     KEY3,F
        RLF     KEY4,F
        RLF     KEY5,F
        RLF     KEY6,F
        RLF     KEY7,F         

        DECFSZ  CNT0,F         	; INNER LOOP 48 TIMES
        GOTO    DECRYPT_INNER   ; INNER LOOP 48 TIMES

        DECFSZ  CNT1,F         	; OUTER LOOP 12 TIMES (11 + 1 TO RESTORE KEY)
        GOTO    DECRYPT_OUTER   ; OUTER LOOP 12 TIMES (11 + 1 TO RESTORE KEY)

        RETLW   0               ; RETURN 

;------------------------------------------------------------------------------
;
; FUNCTION     	: LOAD_CNT_VALS()	      			
;
; DESCRIPTION  	: LOAD COUNTERS INTO WRITE BUFFERS
;
;------------------------------------------------------------------------------

LOAD_CNT_VALS
	MOVFW	CNTR_HI			; LOAD MSB OF COUNTER
	MOVWF	TMP1
	MOVFW	CNTR_LW			; LOAD LSB OF COUNTER
	MOVWF	TMP2
	RETLW	.0

;------------------------------------------------------------------------------
;
; FUNCTION     	: RECEIVE()	      			
;
; DESCRIPTION  	: RECEPTION ROUTINE FOR PWM TRANSMISSIONS
;
;
;------------------------------------------------------------------------------

RECEIVE

;******** WAIT FOR HEADER AND CALIBRATE *******************

	BTFSS   RFIN              ; INPUT LOW?
	GOTO    RMT_0                   ; YES; RECEIVE ERROR

	MOVLW   .10                      ; 10 ms TIMER
	MOVWF   CNT1
RCV0
	MOVLW   .200
	MOVWF   CNT0
RCV1
	BTFSS   RFIN              ; [2] INPUT HIGH?
	GOTO    RCV2                    ; [0] NO, JUMP OUT OF LOOP
	DECFSZ  CNT0,1                  ; [1] YES, CONTINUE WITH TIMING LOOP
	GOTO    RCV1                    ; [2] 5 us X CNT0
	DECFSZ  CNT1,1                  ; [0] DO 1 ms LOOP CNT1 TIMES
	GOTO    RCV0			; [0]

RCV2
	CLRF    CNT0                    ; [1] CLEAR CALIB COUNTER LOW BYTE
	CLRF    CNT1                    ; [1] CLEAR CALIB COUNTER HIGH BYTE

;*************************************************************************
;  2.5 IS AVERAGE FOR DETECTING FALLING EDGE IN RCV1
;  2   INSTRUCTIONS FOR JUMP OUT RCV1 TO RCV2
;  2   INSTRUCTIONS FOR RCV2 - CLEAR CALIBRATION COUNTER
;  TOTAL 6.5 INSTRUCTIONS < 1 CALIBRATION LOOP SO DISCARD
;*************************************************************************

RCV3
	BTFSC   RFIN              ; [2][2] INPUT HIGH?
	GOTO    RCV6                    ; [0][0] YES--END CALIBRATION
	INCF	CNT0,1			; [1] INCREMENT 16BIT COUNTER	
	SKPNZ	      			; [2]
	INCF	CNT1,1			; [0]
	CLRWDT				; [1] RESET WATCH DOG TIMER
	NOP				; [1]
	BTFSS	CNT1,3			; [1]
	GOTO	RCV3  			; [2]
	GOTO	RMT_0 			; [0]
		      			; TOTAL = 10
		      			
RCV6
	CLRC				; [1] DIVIDE CNT1:CNT0 BY 8 (600/8=75)
	RRF     CNT1,1			; [1]
	RRF     CNT0,1			; [1]
	RRF     CNT1,1			; [1]
	RRF     CNT0,1			; [1]
	RRF     CNT1,1			; [1]
	RRF     CNT0,1                  ; [1] 
					
	MOVLW   MIN/80			; [1]
	SUBWF   CNT0,W			; [1]
	BTFSS   STATUS,C		; [2] NEGATIVE?
	GOTO    RMT_0                   ; [0] YES--HEADER SHORTER THAN MIN.
					; TOTAL = 11
; ************* VALID HEADER RECEIVED *********************
RCV7
	MOVLW   NBITS                   ; [1] VALID START MARKER WAS RECEIVED
	MOVWF   CNT1			; [1]
	MOVF    CNT0,W			; [1]
	MOVWF   CNT2                    ; [1] CNT2 = CNT0
	MOVLW   6H			; [1] SEE NOTE BELOW
	SUBWF   CNT2,1			; [1]
	GOTO    DL1                   	; [2] COMPENSATE FOR FIRST BIT
					; TOTAL = 8

;**********************************************************************************
;  2.5 IS AVERAGE PLAY BETWEEN RISING EDGE AND JUMP OUT OF CALIBRATION LOOP.
;  2   FOR JUMP OUT OF RCV3 TO RCV6
; 11   INSTRUCTIONS FOR RVC6 - CAIBRATION COUNTER DIVIDE
;  8   INSTRUCTIONS FOR RCV7 - COMPENSATE FOR POST CALIBRATION CALCUATIONS
; TOTAL 22.5 INSTRUCTIONS BETWEEN RISING EDGE AND ENTERING DL1
;  THEREFORE SUBTRACT 22.5/4 = 5.625 TO COMPENSATE FOR POST CALCULATION ON 1ST BIT
;**********************************************************************************

RCV8					
	MOVLW	4H			; [1] WAIT A MAXIMUM OF 4 Te
	MOVWF	TMP_CNT			; [1] SET TEMP LOOP COUNTER

RCV10A
	MOVFW	CNT0                  	; [1] and CSR processing
	MOVWF   CNT2			; [1] Refer to explanation above

RCV10B
	BTFSC   RFIN              ; [2] Wait for rising edge
	GOTO    RCV11                   ; [0] Edge found--Process
	CLRWDT                          ; [1] Clear watchdog Timer
	BTFSC   RFIN              ; [2] Wait for Next rising edge
	GOTO    RCV11                   ; [0] Edge found--Process
	DECFSZ  CNT2,1                  ; [1] Decrement Timeout counter
	GOTO    RCV10B                  ; [2] Loop Back
					; TOTAL = 8, RFIN CHECKED EVERY 4uS ON AVERAGE

	DECFSZ	TMP_CNT,1		; [1] ALL Te PERIODS
	GOTO	RCV10A			; [2] ... NO, THEN WAIT FOR NEXT ONE
	GOTO    RMT01                   ; [0] ... YES, [0] TIMEOUT--no edge found

RCV11
	MOVLW	3H			; [1]  SEE NOTE BELOW
	SUBWF	CNT0,W			; [1]
	MOVWF	CNT2			; [1]

;*************************************************************************
; 2   SETUP OF TEMP LOOP COUNTER  ( ONLY ONCE )
; 2   SETUP TE LOOP COUNTER       ( MAX 4 )
; 3   DECREMENT TEMP LOOP COUNTER ( MAX 4 )
; 4   IS THE AVERAGE PLAY BETWEEN EDGE AND EDJE BEING DETECTED IN RCV9
; 2   JUMP OUT OF RCV10B TO RCV11
; 3   FOR RCV11
; TOTAL 10 INSTRUCTIONS BETWEEN EDGE AND ENTERING DL1
; THEREFORE SUBTRACT 10/4 = 2.5 => 3 DL1 LOOPS TO COMPENSATE FOR 
;*************************************************************************

DL1
	CLRWDT                          ; [1] RESET WATCHDOG TIMER
	DECFSZ  CNT2,1                  ; [1] [2, IF SKIP]
	GOTO    DL1                     ; [2] CNT0 X 4 us

SAMPLE1
	BTFSS   RFIN              ; [2] INPUT HIGH?  FIRST SAMPLE
	GOTO    RMT01                   ; [0] NO--ERROR

	MOVF    CNT0,W                  ; [1] CALIBRATION COUNTER
	MOVWF   CNT2                    ; [1] (NOMINALLY 75 FOR 300 us PULSE)
	DECF    CNT2,1			; [1] SUBTRACT 2 FROM FINAL CALIB COUNTER TO COMPENATE FOR THIS
	GOTO	$+1			; [2]
	NOP				; [1]
					; TOTAL = 8 => 1 LOOP COUNTER
DL2
	CLRWDT                          ; [1] RESET WATCHDOG TIMER
	GOTO	$+1			; [2] WASTE TIME
	GOTO	$+1			; [2] WASTE TIME
	DECFSZ  CNT2,1			; [1]
	GOTO    DL2                     ; [2] CNT0 X 8 us [ CNT0 x Te ]

SAMPLE2
	BCF     FLAGS,BITIN             ; [1]   CLEAR BIT POSITION
	BTFSS   RFIN              ; [1.5] LEAVE 0 IF LINE HIGH
	BSF     FLAGS,BITIN             ; [0.5] MAKE 1 IF LINE LOW
					; SUB TOTAL = 3 CYCLES

	CALL    ROT_SHIFT               ; [11]+[2] CSR SHIFT + CALL
	BCF	CSR7,7			; [1]
	BTFSC   FLAGS,BITIN		; [1.5]
	BSF     CSR7,7			; [0.5]
					; SUB TOTAL = 16 CYCLES


	MOVF    CNT0,W                  ; [1] CALIBRATION COUNTER
	MOVWF   CNT2                    ; [1] (NOMINALLY 75 FOR 300 us PULSE)
	MOVLW	3			; [1] SEE CALCULATION BELOW
	SUBWF	CNT2,1			; [1]
	NOP				; [1]
					; SUB TOTAL = 5 CYCLE
					; TOTAL = 24 => 24/8 = 3 LOOP COUNTERS
					 
;*************************************************************************
; TOTAL = 24 INSTRUCTIONS
; SUBTRACT 24/8 = 3 TO COMPESATE FOR UPDATEING CSR AND OTHER PROCESSING 
; AFTER DATA SAMPLE IS TAKEN.
;*************************************************************************

DL3
	GOTO	$+1			; [2] WASTE TIME
	GOTO	$+1			; [2] WASTE TIME
	CLRWDT                          ; [1] RESET WATCHDOG TIMER
	DECFSZ  CNT2,1                  ; [1]
	GOTO    DL3                     ; [2] CNT0 X 8 us [ CNT0 X Te ]

SAMPLE3
	BTFSC   RFIN              ; [2] INPUT LOW?  THIRD SAMPLE
	GOTO    RMT0                    ; [0] NO--RECEIVE ERROR

	CALL    TST_RTCC                ; [11] CHECK RTCC

	DECFSZ  CNT1,1                  ; [1] LAST BIT?
	GOTO    RCV8                    ; [2] ... NO, GET NEXT BIT
	GOTO	RMT1		     	; TOTAL = 14 CYCLES


RMT_0
RMT0	
RMT01	BSF	STATUS,C		; INVALID TRANSMISSION
	RETLW	1			; RETURN

RMT1
    BANK1
    BCF TRISIO,5   ;VIRA SAIDA
    BANK0	
    BCF	LED		; VALID TRANSMISSION FORMAT, LED ON
	MOVLW	0FH			; FORCE OPEN BUTTON CODES TO ZERO
	ANDWF	SER_0,1
	CLRC				; VALID SERIAL NUMBER => VALID TX
 	RETLW   .0                    	; RETURN 


;------------------------------------------------------------------------------
;
; FUNCTION     	: M_LOOP ()	      			
;
; DESCRIPTION  	: MAIN PROGRAM ROUTINE
;
;------------------------------------------------------------------------------

M_LOOP


   	MOVFW SITUAÇÃO
    XORLW 0X01
    BTFSC STATUS,Z          ;SE IGUAL A 1
	GOTO T6K
    MOVFW SITUAÇÃO
    XORLW 0X03
    BTFSS STATUS,Z          ;SE IGUAL A 1
	GOTO    T7K

    BTFSC  S1
    GOTO   T7K
    BCF    M1
    BCF    M2
    GOTO   INCSIT
T6K
    BTFSC S2
    GOTO  T7K
    BCF    M1
    BCF    M2

INCSIT
	INCF   SITUAÇÃO,F    ;EVITA UM APERTO A MAIS QUANDO MOTOR PARA COM FIM DE CURSO
    ;ANDLW  0X03
    ;MOVWF  SITUAÇÃO
T7K    	
	BANK1
    BSF TRISIO,5    ;VIRA ENTRADA
    BANK0
	BTFSS	LRN		;TESTA BOTÃO 'LEARN' 
	GOTO	LEARN		 	; TEST & HANDLE LEARN BUTTON APERTADO
	CALL	TST_RTCC		; UPDATE TIMER 
	CALL	TST_TIMER		; HANDLE TIMER - UPDATE OUTPUTS
	CALL	RECEIVE			; RECEIVE TRANSMISSION 
	BC	M_LOOP			; CHECK IF TRANSMISSION VALID




M_SEARCH
	CLRF	TXNUM			; TEST FIRST POSITION
; ******* COMPARE LOWER WORD OF SERIAL NUMBER ********
M_SERIAL
	CALL	TX_LOOKUP		; GET TX BASE ADDRESS
	
	INCF  ADDRESS,F		; SOMA 2
	INCF  ADDRESS,F 

	CALL	EEREAD			; READ LOWER 16-BITS OF SER# FROM EEPROM
  		    
	MOVFW	TMP1			; COMPARE RX AND EEPROM VALUES
	XORWF	SER_2,W
	BNZ	M_NEXT			; IF NOT EQUAL CHECK NEXT
	MOVFW	TMP2			; COMPARE RX AND EEPROM VALUES
	XORWF	SER_3,W
	BNZ	M_NEXT			; IF NOT EQUAL CHECK NEXT
	
; ******* COMPARE UPPER WORD OF SERIAL NUMBER ********
M_SERIAL2
	INCF	ADDRESS,F		; POINT TO NEXT ENTRY 
	CALL	EEREAD			; READ UPPER 16-BITS OF SER# FROM EEPROM

	MOVFW	TMP1			; COMPARE RX AND EEPROM VALUES
	XORWF	SER_0,W
	BNZ	M_NEXT			; IF NOT EQUAL CHECK NEXT

	MOVFW	TMP2			; COMPARE RX AND EEPROM VALUES
	XORWF	SER_1,W
	BNZ	M_NEXT			; IF NOT EQUAL CHECK NEXT

	BTFSS	FLAGS,LRNF		; LEARN MODE
	GOTO	M_HOP			; FOUND TRANSMITTER - DECRYPT

	BSF	FLAGS,RELEARN		; SET RELEARN FLAG
	GOTO	LEARN_F			; FOUND TRANSMITTER - LEARN
		
; **** SEARCH NEXT POSITION FOR SERIAL NUMBER *****
M_NEXT	INCF	TXNUM,F			; POINT TO NEXT TRANSMITTER POSITION
	MOVLW	MAX_USERS		; TEST FOR LAST POSITION
	SUBWF	TXNUM,W			
	BTFSS	STATUS,C		; NOT FOUND IN MAP
	GOTO	M_SERIAL		; TRY NEXT POSITION
M_NF
	BTFSS	FLAGS,LRNF		; LEARN MODE
	GOTO	M_LOOP			; NO... INVALID SERIAL NUMBER 
	GOTO	LEARN_NF		; NEW TRANSMITTER - USE POINTER FOR LEARN

; ********** DECRYPT HOPCODE *********************
M_HOP	
	CALL	DECRYPT			; DECRYPT HOPCODE 

; ********* TEST DICRIMINATION VALUE *************
M_DIS	MOVFW	SER_3			; SERIAL NUBER LSB MUST BE EQUAL
	XORWF	DISC,W			; TO DISCRIMINATION VALUE
	BNZ	M_LOOP

; *************** CHECK COUNTERS VALID ************
	BCF	FLAGS,SEC_CNT		; CHECK FIRST COUNTER
M_CNT	CALL	TX_LOOKUP		; POINT LOWER 16 BIT COUNTER
	BTFSC	FLAGS,SEC_CNT		; IF SECOND COUNTER IS USED
	INCF	ADDRESS,F		; INCREMENT ADDRESS
	CALL	EEREAD			; READ LOWER 16 BIT COUNTER FROM EEPROM

; ************ CHECK COUNTER WINDOWS ***********
M_SUB
	MOVFW	TMP2			; 16 BIT COUNTER SUBSTRACTION
	SUBWF	CNTR_LW,W
	MOVWF	TMP2			
	SKPC				; SKIP IF NO BORROW
	INCF	TMP1,F			; ... ELSE INCR HI BYTE
	MOVFW	TMP1
	SUBWF	CNTR_HI,W
	MOVWF	TMP1

	BCF	TMP1,0			; MAKE ACCEPTED WINDOW 512


 

M_CHECK0
	MOVFW	TMP1			; TEST IF IN WINDOW ( UPPER BYTE )
	BTFSC	STATUS,Z
	GOTO	M_CHECK2		; GO AND CHECK LOWER BYTE

	BTFSC	FLAGS,SEC_CNT		; IF SECOND COUNTER
	GOTO	M_LOOP			; ERROR - GOTO MAIN LOOP		

	BSF	FLAGS,SEC_CNT		; SET FLAG FOR SECOND COUNTER CHECK
	GOTO	M_CNT			; AND CHECK IT

M_CHECK2
	MOVFW	TMP2			; CHECK LOWER BYTE
	BZ	M_TZERO			; IF REPEAT - RESET TIMEOUT COUNTER








;***************************************************************
; ESCRITA NA EEPROM DOS CONTADORES 

; ************ UPDATE EEPROM COUNTER ***********
M_UPDATE
	CALL	TX_LOOKUP		; GET CURRENT TX BASE ADDRESS
	CALL	LOAD_CNT_VALS		; LOAD COUNTER VALUES
	CALL	EEWRITE			; UPDATE FIRST COUNTER
	INCF	ADDRESS,F
	CALL	LOAD_CNT_VALS		; LOAD COUNTER VALUES
	CALL	EEWRITE			; UPDATE SECOND COUNTER


  
; ******** UPDATE OUTPUT WITH CURRENT BUTTON CODE ********                                                   

M_OUTPUT 
	MOVLW	0F0H			; MASK ONLY BUTTON CODES
	ANDWF	FUNC,1
	SWAPF	FUNC,1			; GET BUTTON CODE FROM FUNC BYTE
	
;	BTFSC	FUNC,0			; CHANGE BUTTON TO S-OUTPUT FORMAT
;	BSF	FUNC,4			; [ S2 S1 S0 S3 ]
;	CLRC				
;	RRF	FUNC,W	
	MOVFW	FUNC


	
M_OUTPUT1
	CLRWDT
;	MOVWF	GPIO			; UPDATE PORT WITH FUNCTION CODE (GPIO,1)                               XXXXXXXXXXXXXXXXXXXXXXXXX
	BTFSC   FUNC,0
    GOTO    LIGJ
	BTFSC	FUNC,1
	GOTO    LIGJ
	BTFSC	FUNC,2
	GOTO    LIGJ
	BTFSS	FUNC,3
	GOTO M_END              ;FALHA
LIGJ
    INCF SITUAÇÃO,W
    ANDLW 0X03				;LIMITA CONTAGEM A 0 - 3
    MOVWF SITUAÇÃO
    XORLW 0X01
    BTFSC STATUS,Z          ;SE IGUAL A 1
	GOTO VAL1
    MOVFW SITUAÇÃO
    XORLW 0X03
    BTFSC STATUS,Z          ;SE IGUAL A 1
	GOTO VAL3
	BCF		M1              ;DESLIGA TODAS AS SAIDAS
    BCF     M2
	GOTO	M8			; WAIT FOR NEXT TRANMISSION
;	GOTO   RESET		;PREVINE TRAVAMENTOS

VAL1
   	BCF		M2              ;LIGA M1
    BSF     M1
    GOTO   M8
VAL3
   	BCF		M1              ;LIGA M2
    BSF     M2
    


M8
M_TZERO 
    CLRF	CNT_HI			; RESET RTCC CLOCK
	CLRF	CNT_LW	
	CLRF   CNT_HIX
    CLRF   CNT_LWX		

M_END	
	BSF		LED
	GOTO	M_LOOP			; WAIT FOR NEXT TRANMISSION

;-----------------------------------------------------------------

;------------------------------------------------
INTERVALO
	CLRF    CNT_LW
	CLRF    CNT_HI
X5
	CLRWDT
	BTFSS	RTCC,7
	GOTO    X5
	BCF	RTCC,7			; CLEAR MSB OF RTCC
	INCF	CNT_LW,F		; INCREASE 16 COUNTER
	SKPNZ				; INCREASE UPPER BYTE IF ZERO ( OVERFLOW )
	INCF	CNT_HI,F
	BTFSS	CNT_LW,2
	GOTO 	X5

	RETURN
;------------------------------------------------------------------------------
;
; FUNCTION     	: LEARN ()	      			
;
; DESCRIPTION  	: LEARN ROUTINE
;
;------------------------------------------------------------------------------

LEARN
	BSF		FLRN		;FLAG DE LEARN ATIVADO
	CLRF	CNT_LW			; RESET TIMER
	CLRF	CNT_HI
	BANK1
    BSF TRISIO,5        ;ENTRADA
    BANK0
	
LEARN1	;BCF		LED		; LED ON  (O PROPRIO BOTÃO LIGARA)
	CALL	TST_RTCC		; UPDATE TIMER
	BTFSC	LRN		; TEST FOR BUTTON RELEASE		
	GOTO	LEARN2			; ENTER LEARN MODE
	BTFSS	CNT_HI,0		; TEST FOR ERASE ALL
	GOTO	LEARN1			; LOOP BACK

; ******* EEPROM ERASE ALL ******************

	BSF	LED    ;FORÇA APAGAMENTO DO LED MESMO COM INTERRUPTOR LIGADO
ERASE_ALL
    BANK1
    BCF TRISIO,5    ;VIRA SAIDA
    CALL TEMPOAP
    BANK1
    BSF TRISIO,5    ;VIRA ENTRADA
    BANK0
	CLRWDT				; CLEAR WATCHDOG TIMER
	BTFSS	LRN		; WAIT FOR BUTTON RELEASE
	GOTO	ERASE_ALL		; LOOP BACK

  	CALL      APAGAEEPROM
	GOTO	RESET			; START OVER
TEMPOAP
   MOVLW  0XFF
   MOVWF  AUX8
   DECFSZ AUX8,F
   GOTO  $-1
   RETURN
	
LEARN2
	;BSF	LED		; CLEAR LED   DESNECESSARIO: APAGA PELO PROPRIO BOTÃO
	BSF	FLAGS,LRNF		; SET LEARN FLAG

LEARN3
	CALL	TST_RTCC		; UPDATE TIMER
	CALL	TST_TIMER		; CHECK FOR LEARN TIMEOUT
	CALL	RECEIVE			; RECEIVE TRANSMISSION 
	BC	LEARN3			; CHECK IF TRANSMISSION VALID
 	GOTO	M_SEARCH		; CHECK IF SERIAL NUMBER IS IN MAP

LEARN_NF

; *** IF SERIAL NOT IN MAP READ SELFLEARN POINTER ***

	MOVLW	LRNPTR			; POINT TO LEARN POINTER
	MOVWF	ADDRESS
	CALL	EEREAD			; READ LEARN POINTER FROM EEPROM

	MOVF	TMP2,W			; CHECK LOWER BYTE
	MOVLW	0H			; LOAD 0 DEFAULT
	BTFSC	STATUS,Z		; IF LOWER != 0 LEARN ON 0
	MOVF	TMP1,W			; ELSE LEARN ON TMP1 VALUE
	MOVWF	TXNUM			; LOAD TXNUM



LEARN_F
	CALL	TX_LOOKUP
	INCF ADDRESS,F		;SOMA 2
	INCF ADDRESS,F 
	MOVFW	SER_2			; GET LOWER 16 BIT OF SERIAL NUMBER
	MOVWF	TMP1
	MOVFW	SER_3
	MOVWF	TMP2
	CALL	EEWRITE			; ... AND WRITE TO EEPROM
	INCF    ADDRESS,F		;TESTE  SOMA 2	
	MOVFW	SER_0			; GET UPPER 16 BIT OF SERIAL NUMBER
	MOVWF	TMP1
	MOVFW	SER_1
	MOVWF	TMP2
	CALL	EEWRITE			; ... AND WRITE TO EEPROM

; *** DECRYPT HOP CODE ***

LEARN_DEC
	CALL	DECRYPT			; DECRYPTION ROUTINE

; *** CHECK DISCRIMINATION VALUE ***

LEARN_CHK
	MOVFW	SER_3			; CHECK LOWER BYTE OF SERIAL NUMBER
	XORWF	DISC,W			; AGAINST DISCRIMINATION VALUE
	BZ	LEARN_UP		; UPDATE LEARN POINTER
	GOTO	CANCEL_LEARN		; ERROR CANCEL LEARN MODE

; ********* UPDATE LEARN POINTER **********
LEARN_UP
	CALL	TX_LOOKUP		; GET CURRENT TX BASE ADDRESS
	CALL	LOAD_CNT_VALS
	CALL	EEWRITE			; WRITE LSB WORD OF COUNTER TO EEPROM

	BTFSC	FLAGS,RELEARN		; IF RELEARN
	GOTO	BYPASS_POINTER_WRITE	; DONT UPDATE POINTER

	INCF	TXNUM,F			; INCREMENT LEARN POINTER	       
	MOVLW	MAX_USERS     		; ALLOW 0 .. MAX_USERS - 1
	SUBWF	TXNUM,W			
	MOVLW	0H			; IF MAX WRAP TO 0
	BTFSS	STATUS,C
	MOVF	TXNUM,W			; ELSE USE TXNUM
	MOVWF	TMP1			; FOR WRITE OPERATION

	CLRF	TMP2			; CLEAR LOWER BYTE
	
	MOVLW	LRNPTR			; POINT TO LEARN POINTER
	MOVWF	ADDRESS
	CALL	EEWRITE			; UPDATE LEARN POINTER IN EEPROM

BYPASS_POINTER_WRITE

	BCF	LED		; LED ON TO INDICATE VALID LEARN
    BANK1
    BCF TRISIO,5  ;SAIDA
    BANK0
	CLRF	CNT_LW			; CLEAR COUNTER LOW BYTE

SUCCESS
	CALL	TST_RTCC		; INDICATE SUCCESSFUL LEARN
	BTFSS	CNT_LW,4		; LED ON FOR 0.5 SEC
	GOTO	SUCCESS			; LOOP BACK

CANCEL_LEARN
	BCF	FLAGS,LRNF		; CLEAR LEARN FLAG
	BCF	FLAGS,RELEARN		; CLEAR RELEARN FLAG
	BSF		LED			;APAGA LED
    BANK1
    BSF TRISIO,5  ;ENTRADA
    BANK0
	BCF		FLRN			;DESLIGA FLAG MODO APRENDIZADO
	GOTO	M_LOOP			; RETURN TO MAIN LOOP - LED OFF


;------------------------------------------------
FILTRO
; FILTRO PARA EVITAR DISPAROS ESPURIOS NA PORTA
		MOVLW	0XFF
		MOVWF	FILTRO1
		MOVLW	TF2
		MOVWF	FILTRO2

		DECFSZ	FILTRO1,F
		GOTO	$-1
		DECFSZ	FILTRO2,F
		GOTO	$-3
		RETURN

	END