;********************************************************************
;    Filename:	operador.asm             			     
;    Date: 08/05/2006                              			      
;    File Version: 1.0                              			         
;                                                               			    
;    Author: Daniel Massia Walls                			  
;    Company:                                             			   
;                                                                    
;**********************************************************************
;                                                                     
;    Files required:  P16F690.inc                    
;                                                                     
;**********************************************************************
;   En este programa iniciamos la decodificacion de seņales en X-10.
;  Vamos a interpretar ordenes de encendido y apagado para las unidades
;  1 a la 4 asi como ordenes de todo encendido y todo apagado. Se operara
;  sobre las salidas RC0 a RC3, respectivamente unidades 1 a la 4, y que 
;  corresponden a los leds de la placa de prototipo. Se usa la interrupcion RA2/INT
;  para el paso por cero y la del TIMER0 para la espera de los 0,5 ms.
;**********************************************************************

		list		p=16f690		; directiva para definir procesador
		#include		<P16F690.inc>	; archivo de definicion especifica de registros
	
		__CONFIG    _CP_OFF & _PWRTE_ON & _WDT_OFF &  _HS_OSC & _CPD_OFF & _FCMEN_OFF & _IESO_ON & _MCLRE_OFF & _BOD_OFF
		errorlevel  		-302          	  	; suprime mensaje "register not in bank0, check page bits" al ensamblar

;**********************************************************************
;            DEFINIMOS EXPRESIONES Y VARIABLES
;**********************************************************************

;					Definicion de expresiones del programa

		#define		XIN		PORTA,1		; bit DETECCION del puerto A
		#define		PASOCERO		PORTA,2		; bit PASOCERO del puerto A
		#define		PULSADOR		PORTA,3		; bit PULSADOR del puerto A
		#define		LED1		PORTC,0		; bit LED1 del puerto C
		#define		LED2		PORTC,1		; bit LED2 del puerto C
		#define		LED3		PORTC,2		; bit LED3 del puerto C
		#define		LED4		PORTC,3		; bit LED4 del puerto C

		#define		BitRx		FlagsControl,0		; bit BitRx de variable FlagsControl
		#define		BitTx		FlagsControl,1		; bit BitTx de variable FlagsControl
		#define		FlagFuncionRx	FlagsControl,2		; bit FlagFuncionRx de variable FlagsControl
		#define		FlagFuncionTx	FlagsControl,3		; bit FlagFuncionTx de variable FlagsControl
		#define		FlagX10Rx		FlagsControl,4		; bit FlagX10Rx de variable FlagsControl
		#define		FlagX10Tx		FlagsControl,5		; bit FlagX10Tx de variable FlagsControl
		#define		FlagSegundaTx	FlagsControl,6		; bit FlagSegundaTx de variable FlagsControl
		#define		FlagEspera		FlagsControl,7		; bit FlagEspera de variable FlagsControl

;					Definicion de expresiones de X10

; FUNCIONES

		#define		AllUnitsOff		b'01010101'		; 'All units off' 			b'0000'
		#define		AllLightsOn		b'01010110'		; 'All lights on'			b'0001'	
		#define		On		b'01011001'		; 'On'			b'0010'	
		#define 		Off		b'01011010'		; 'Off'			b'0011'	
		#define 		Dim		b'01100101'		; 'Dim'			b'0100'	
		#define 		Bright		b'01100110'		; 'Bright'			b'0101'		
		#define		AllLightsOff		b'01101001'		; 'All lights off'			b'0110'
		#define		ExtendedCode	b'01101010'		; 'Extended Code'		b'0111'
		#define		HailRequest		b'10010101'		; 'Hail Request'		b'1000'	
		#define		HailAcknowledge	b'10010110'		; 'Hail Acknowledge'		b'1001'
		#define		PresetDim		b'10011001'		; 'Pre-set Dim'(actually, 101x)	b'1010'	
		#define		ExtendedData		b'10100101'		; 'Extended Data (Analog)'		b'1100'
		#define		StatusOn		b'10100110'		; 'Status = ON'			b'1101'
		#define		StatusOff		b'10101001'		; 'Status = OFF'		b'1110'	
		#define 		StatusRequest	b'10101010'		; 'Status request'		b'1111'
		
; CODIGOS DE CASA

		#define		HouseA		00h
		#define		HouseB		01h
		#define		HouseC		02h
		#define		HouseD		03h
		#define		HouseE		04h		
		#define		HouseF		05h
		#define		HouseG		06h
		#define		HouseH		07h
		#define		HouseI		08h
		#define		HouseJ		09h
		#define		HouseK		0Ah
		#define		HouseL		0Bh
		#define		HouseM		0Ch
		#define		HouseN		0Dh
		#define		HouseO		0Eh	
		#define		HouseP		0Fh

;CODIGOS DE UNIDAD

		#define		Unit1		00h
		#define		Unit2		01h
		#define		Unit3		02h
		#define		Unit4		03h
		#define		Unit5		04h
		#define		Unit6		05h
		#define		Unit7		06h
		#define		Unit8		07h
		#define		Unit9		08h
		#define		Unit10		09h
		#define		Unit11		0Ah
		#define		Unit12		0Bh
		#define		Unit13		0Ch
		#define		Unit14		0Dh
		#define		Unit15		0Eh	
		#define		Unit16		0Fh

;	Variables del programa

		cblock		020h

RxDato0			; variables que componen el buffer
RxDato1			; de entrada
RxDato2			;
RxDato3			;



RxCasa1			; variables que contienen los codigos de
RxCasa2			; casa y unidad o funcion de las dos ultimas
RxCodigo1			; tramas recibidas
RxCodigo2	

RxCasa			; variable con el codigo de casa recibido y convertido
RxUnidad			; variable con RxCodigo2 cuando este es Unidad y convertido
RxFuncion			; variable con RxCodigo2 cuando este es Funcion

Casa			; variable que contiene el codigo de casa del dispositivo

ValorDecodX10		; valor para convertir a X10
ValorX10			; valor convertido a codigo en X10

FlagsControl			; registro de flags de control
	
		endc

		cblock		070h

_WREG			; variables para preservar el
_STATUS			; registro W, STATUS, PCLATH
_PCLATH			; y FSR durante la ejecucion de
_FSR			; la rutina de interrupcion. Se ubican
			; en area de memoria desbancada

		endc


;**********************************************************************
;	                RESET
;**********************************************************************

		ORG		0x000		; vector de reset del procesador
START						; inicio del codigo

  		goto		PROG		; salta la rutina de interrupcion


;**********************************************************************
;                          RUTINA INTERRUPCION
;**********************************************************************

		ORG		0x004		; vector de interrupcion del procesador
ISR						; inicio rutina de interrupcion

		movwf		_WREG		; carga W en _WREG
		movf		STATUS,0		; carga STATUS en W
		clrf		STATUS		; selecciona el banco 0
		movwf		_STATUS		; carga W en _STATUS
		movf		PCLATH,0		; carga PCLATH en W
		movwf		_PCLATH		; carga W en _PCLATH
		movf		FSR,0		; carga FSR en W
		movwf		_FSR		; carga W en _FSR

		banksel		INTCON		; salta a banco de registro INTCON 
		btfss		INTCON,INTF		; interrupcion por pin RA2/INT?
		goto		FinInt		; no, ve a FinInt
		banksel		OPTION_REG		; si, salta a banco de registro OPTION_REG
		bcf		OPTION_REG,T0CS	; habilitalo como timer
EsperaTmr0
		btfss		INTCON,T0IF		; se ha habilitado el flag?
		goto		EsperaTmr0		; no, vuelve
		banksel		FlagsControl		; salta a banco variable FlagsControl
		bcf		BitRx		; si, apaga BitRx
		btfsc		XIN		; como esta XIN?
		bsf		BitRx		; alto, setea BitRx

		call		X10Rx		; llama a subrutina X10Rx
	
		call		Transicion		; llama a subrutina Transicion

		call		IniTmr0		; configuramos de nuevo el timer0
FinInt						; acaba interrupcion
		banksel		INTCON		; salta a banco de registro INTCON
		bcf		INTCON,INTF		; apaga flag por INT
		bcf		INTCON,T0IF		; apaga flag por TIMER0
		bcf		INTCON,RABIF	; apaga flag de interrupciones por cambio

		clrf		STATUS		; selecciona el banco 0
		movf		_FSR,0		; carga _FSR en W
		movwf		FSR		; carga W en FSR
		movf		_PCLATH,0		; carga _PCLATH en W
		movwf		PCLATH		; carga W en PCLATH
		movf		_STATUS,0		; carga _STATUS en W
		movwf		STATUS		; carga W en STATUS
		swapf		_WREG,1		; cambia los dos nibbles de _WREG y guarda en _WREG
		swapf		_WREG,0		; cambia los dos nibbles de _WREG y guarda en W

	retfie					; retorna ISR, reactiva GIE

;**********************************************************************
;     	  		   PROGRAMA PPAL
;**********************************************************************

PROG						; etiqueta programa principal

;			Configuracion de puertos

		banksel		PORTA		; salta a banco registro PORTA
		clrf		PORTA		; inicializamos PORTA
		clrf		PORTB		; inicializamos PORTB
		clrf		PORTC		; inicializamos PORTC
		banksel		TRISA		; salta a banco registro TRISA
		movlw		0Eh		; RA1, RA2 y RA3 entradas, resto salidas 
		movwf		TRISA		; cargamos ´00001110´ en TRISA
		clrf		TRISB		; todo el puerto B salidas	
		clrf		TRISC		; todo el puerto C salidas
		banksel		ANSEL		; salta a banco registro ANSEL
		clrf		ANSEL		; Todas I/O digitales

;			Inicializacion de variables

		banksel		RxDato0		; salta a banco variable RxDato0
		clrf		RxDato0		; inicializacion variable RxDato0
		clrf		RxDato1		; inicializacion variable RxDato0
		clrf		RxDato2		; inicializacion variable RxDato0
		clrf		RxDato3		; inicializacion variable RxDato0
		clrf		RxCasa1		; inicializacion variable RxCasa1
		clrf		RxCasa2		; inicializacion variable RxCasa2
		clrf		RxCodigo1		; inicializacion variable RxCodigo1
		clrf		RxCodigo2		; inicializacion variable RxCodigo2
		clrf		Casa		; inicializacion variable Casa
		clrf		ValorDecodX10	; inicializacion variable ValorDecodX10
		clrf		ValorX10		; inicializacion variable ValorX10
		clrf		FlagsControl		; inicializacion variable FlagsControl
		clrf		TMR0		; inicializacion registro TMR0

;			Inicializacion de interrupciones TMR0 e INT

		call		IniTmr0		; llama a subrutina IniTmr0
		banksel		OPTION_REG		; salta a banco de registro OPTION_REG
		bsf		OPTION_REG,INTEDG	; habilita flanco subida en entrada INT
		banksel		INTCON		; salta a banco de registro INTCON
		movlw		b'10010000'		 ; cargamos en acumulador ´10010000´
		movwf		INTCON		; cargamos en INTCON

;			Gestion de recepcion X10

Principal
		call 		Pulsador		; llama a subrutina Pulsador
		banksel		FlagsControl		; salta a banco de variabla FlagsControl
		btfsc		FlagX10Rx		; como esta FlagX10Rx?
		call		ControlLED		; alto, se ha recibido trama, llama a ControlLED
		goto		Principal		; bajo, vuelve a Principal, inicio bucle

;**********************************************************************
;          SUBRUTINAS DE SERVICIO A INTERRUPCION
;**********************************************************************

; 				Subrutina IniTmr0

IniTmr0	
		banksel		OPTION_REG		; salta a banco de registro OPTION_REG
		bsf		OPTION_REG,NOT_RABPU	; sin resistencias pull-up
		bsf		OPTION_REG,T0CS	; deshabilitamos el timer
		bcf		OPTION_REG,T0SE	; incremento timer0 por bajo-alto
		bcf		OPTION_REG,PSA	; prescaler se asigna a TMR0
		bsf		OPTION_REG,PS2	; prescaler de 1/32
		bcf		OPTION_REG,PS1	;
		bcf		OPTION_REG,PS0	;
		banksel		TMR0		; salta a banco registro TMR0
		movlw		0E2h		; lleva al acumulador 0E2h
		movwf		TMR0		; cargalo en TMR0

		return
;				Subrutina X10Rx

X10Rx						; subrutina X10Rx
		banksel		RxDato0		; salta a banco de variable RxDato0
		bcf		STATUS,C		; apaga el bit CARRY
		btfsc		BitRx		; como esta el bit BitRx?
		bsf		STATUS,C		; alto, setea el bit CARRY
		rlf		RxDato0,1		; bajo, rota a la izquierda RxDato0
		rlf		RxDato1,1		; rota a la izquierda RxDato1
		rlf		RxDato2,1		; rota a la izquierda RxDato2
		rlf		RxDato3,1		; rota a la izquierda RxDato3

		movf		RxDato3,0		; carga en W RxDato3
		andlw		b'00001111'		; haz AND de W con literal ´00001111´
		xorlw		b'00001110'		; haz XOR de W con literal ´00001110´
		btfss		STATUS,Z		; como esta el bit Z?
		goto		FinX10Rx		; bajo, ve a FinX10Rx

		movf		RxCasa1,0		; alto, carga en W RxCasa1
		movwf		RxCasa2		; carga W en RxCasa2
		movf		RxCodigo1,0		; carga en W RxCodigo1
		movwf		RxCodigo2		; carga W en RxCodigo2
	
		movf		RxDato2,0		; carga en W RxDato2		; 
		movwf		RxCasa1		; carga W en RxCasa1
		movf		RxDato1,0		; carga en W RxDato1
		movwf		RxCodigo1		; carga W en RxCodigo1

		movf		RxCasa1,0		; carga en W RxCasa1
		xorwf		RxCasa2,0		; haz XOR de W con RxCasa2, guarda en W
		btfss		STATUS,Z		; como esta el bit Z?
		goto		FinX10Rx		; bajo, ve a FinX10Rx

		movf		RxCodigo1,0		; alto, carga en W RxCodigo1	
		xorwf		RxCodigo2,0		; haz XOR de W con RxCodigo2, guarda en W
		btfss		STATUS,Z		; como esta el bit Z?
		goto		FinX10Rx		; bajo, ve a FinX10Rx

		movf		RxDato0,0		; carga en W RxDato0
		andlw		b'11000000'		; haz AND de W con literal ´11000000´
		xorlw		b'01000000'		; haz XOR de W con literal ´01000000´
		btfsc		STATUS,Z		; como esta el bit Z?
		goto		RecibidoUnidad	; alto, ve a RecibidoUnidad
	
		movf		RxDato0,0		; carga en W RxDato0
		andlw		b'11000000'		; haz AND de W con literal ´11000000´
		xorlw		b'10000000'		; haz XOR de W con literal ´10000000´
		btfsc		STATUS,Z		; como esta el bit Z?
		goto		RecibidoFuncion	; alto, ve a RecibidoFuncion
	
		goto		FinX10Rx		; bajo, ve a FinX10Rx

RecibidoUnidad					; etiqueta RecibidoUnidad
		bcf		FlagFuncionRx	; apaga FlagFuncionRx
		bsf		FlagX10Rx		; setea FlagX10Rx
		goto		FinX10Rx		; ve a FinX10Rx

RecibidoFuncion					; etiqueta RecibidoFuncion
		bsf		FlagFuncionRx	; setea FlagFuncionRx
		bsf		FlagX10Rx		; setea FlagX10Rx
		goto		FinX10Rx		; ve a FinX10Rx
	
FinX10Rx						; etiqueta FinX10Rx
		return				; final de la subrutina

;				Subrutina Transicion

Transicion						; subrutina Transicion
		banksel		OPTION_REG		; selecciona el banco de OPTION_REG
		btfss		OPTION_REG,INTEDG	; esta alto INTEDG, se ha activado por flanco de subida?
		goto		Bajada		; no, por bajada. Ve a bajada
		bcf		OPTION_REG,INTEDG	;  si, por flanco de subida. Ponlo de bajada
		goto		FinTransicion		; ve a FinTransicion
Bajada
		bsf		OPTION_REG,INTEDG	; Ponlo por flanco de subida

FinTransicion						; etiqueta FinTransmision
	return					; final de la subrutina



;**********************************************************************
;               	SUBRUTINAS DE LA APLICACION
;**********************************************************************

;				Subrutina Pulsador

Pulsador
		banksel		Casa		; salta a banco de variable Casa
		btfss		PULSADOR		; como esta el PULSADOR?
		goto		CasaB		; bajo, vete a HouseB
		movlw		HouseA		; alto, HouseA, carga en W HouseA
		movwf		Casa		; carga W en variable Casa	
		goto		FinPulsador		; ve a FinPulsador
CasaB
		movlw		HouseB		; carga en W HouseB
		movwf		Casa		; carga W en variable Casa
FinPulsador
		return				; retorna de Pulsador

;				Subrutina ControlLED

ControlLED
		movf		RxCasa2,0		; carga RxCasa2 en W
		call		Decodificador		; llama a subrutina Decodificador
		movwf		RxCasa		; carga W (Decodificador) en variable RxCasa

		btfss		FlagFuncionRx	; como esta FlagFuncionRx?
		goto		UnidadRecibido	; bajo, ve a UnidadRecibido
		movf		RxCodigo2,0		; alto, se ha recibido Funcion
		movwf		RxFuncion		; cargala en RxFuncion
		goto		ApagaFlag		; vete a ApagaFlag
	
UnidadRecibido
		movf		RxCodigo2,0		; carga RxCodigo2 en W
		call		Decodificador		; llama a subrutina Decodificador
		movwf		RxUnidad		; carga W (Decodificador) en variable RxUnidad

ApagaFlag
		bcf		FlagX10Rx		; apaga bit FlagX10Rx
	
		movf		RxCasa,0		; cargamos RxCasa en W
		xorwf		Casa,0		; son iguales RxCasa y Casa?
		btfss		STATUS,Z
		goto		FinControlLED		; no, ve a FinControlLED
		btfss		FlagFuncionRx	; se ha recibido una Funcion?
		goto		FinControlLED		; no, ve a FinControlLED
		
AllUnitsOff?
		movf		RxFuncion,0		; se ha recibido AllUnitsOff?
		xorlw		AllUnitsOff
		btfss		STATUS,Z
		goto		AllLightsOn?		; no, ve a AllLightsOn?
		goto		ApagaLEDs

AllLightsOn?	
		movf		RxFuncion,0		; se ha recibido AllLightsOn?
		xorlw		AllLightsOn
		btfss		STATUS,Z
		goto		AllLightsOff?		; no, ve a AllLightsOff?
		goto		EnciendeLEDs

AllLightsOff?	
		movf		RxFuncion,0		; se ha recibido AllLightsOff?
		xorlw		AllLightsOff
		btfss		STATUS,Z
		goto		On?		; no, ve a On?
		goto		ApagaLEDs

On?	
		movf		RxFuncion,0		; se ha recibido On?
		xorlw		On
		btfss		STATUS,Z
		goto		Off?		; no, ve a Off?
		goto		EnciendeLED

Off?		
		movf		RxFuncion,0		; se ha recibido Off?
		xorlw		Off
		btfss		STATUS,Z
		goto		FinControlLED		; no, ve a FinControlLED
		goto		ApagaLED

FinControlLED
		return				; retorna de ControlLED

;				Subrutina Decodificador

Decodificador
		movwf		ValorX10		; carga W en varible ValorX10
		clrf		ValorDecodX10	; pon a 0 variable ValorDecodX10
BucleDecod
		call		TablaCod		; llama a TablaCod
		xorwf		ValorX10,0		; son iguales ValorX10 y W?
		btfsc		STATUS,Z		
		goto		FinDecod		; si, ve a FinDecod con el valor en ValorDecodX10
		incf		ValorDecodX10,1	; no, incrementa ValorDecodX10
		movlw		10h		; carga 16 decimal en registro W
		xorwf		ValorDecodX10,0	; es ValorDecodX10 ya el maximo?
		btfss		STATUS,Z
		goto		BucleDecod		; no, repite BucleDecod
		movlw		0FFh		; si, lleva 0FFh al registro W
		movwf		ValorDecodX10	; carga W en ValorDecodX10
FinDecod
		movf		ValorDecodX10,0	; carga ValorDecodX10 a W
		return				; retorna de Decodificador

;				Subrutina TablaCod

TablaCod
		movlw		HIGH TablaCod	; carga el MSB de la direccion TablaCod en W
		movwf		PCLATH		; carga W en PCLATH
		movf		ValorDecodX10,0	; carga ValorDecodX10 en W
		addwf		PCL,1		; suma W con PCL y guarda en PCL
	
				
						; CASA        UNIDAD              CODIGO X10
		retlw		b'01101001'		;   'A'		 1		b'0110'		
		retlw		b'10101001'		;   'B'		 2		b'1110'		
		retlw		b'01011001'		;   'C'		 3		b'0010'		
		retlw		b'10011001'		;   'D'		 4		b'1010'		
		retlw		b'01010110'		;   'E'		 5		b'0001'		
		retlw		b'10010110'		;   'F'		 6		b'1001'	
		retlw		b'01100110'		;   'G'		 7		b'0101'		
		retlw		b'10100110'		;   'H'		 8		b'1101'		
		retlw		b'01101010'		;   'I'		 9		b'0111'		
		retlw		b'10101010'		;   'J'		10		b'1111'		
		retlw		b'01011010'		;   'K'		11		b'0011'		
		retlw		b'10011010'		;   'L'		12		b'1011'		
 		retlw		b'01010101'		;   'M'		13		b'0000'		
		retlw		b'10010101'		;   'N'		14		b'1000'		
		retlw		b'01100101'		;   'O'		15		b'0100'		
		retlw		b'10100101'		;   'P'		16		b'1100'	

;				Subrutina ApagaLEDs

ApagaLEDs
		banksel		PORTC			; salta a banco de registro PORTC
		bcf		LED1			; apaga LED1
		bcf		LED2			; apaga LED2
		bcf		LED3			; apaga LED3
		bcf		LED4			; apaga LED4
		goto		FinControlLED

;				Subrutina EnciendeLEDs

EnciendeLEDs
		banksel		PORTC			; salta a banco de registro PORTC
		bsf		LED1			; enciende LED1
		bsf		LED2			; enciende LED2
		bsf		LED3			; enciende LED3
		bsf		LED4			; enciende LED4
		goto		FinControlLED

;				Subrutina ApagaLED

ApagaLED
		banksel		RxUnidad
		movlw		00h
		xorwf		RxUnidad,0
		btfss		STATUS,Z
		goto		ApagaLED2
		bcf		LED1
		goto		FinControlLED
ApagaLED2
		movlw		01h
		xorwf		RxUnidad,0
		btfss		STATUS,Z
		goto		ApagaLED3
		bcf		LED2
		goto		FinControlLED
ApagaLED3
		movlw		02h
		xorwf		RxUnidad,0
		btfss		STATUS,Z
		goto		ApagaLED4
		bcf		LED3
		goto		FinControlLED
ApagaLED4
		movlw		03h
		xorwf		RxUnidad,0
		btfss		STATUS,Z
		goto		FinControlLED
		bcf		LED4
		goto		FinControlLED

;				Subrutina EnciendeLED

EnciendeLED
		banksel		RxUnidad
		movlw		00h
		xorwf		RxUnidad,0
		btfss		STATUS,Z
		goto		EnciendeLED2
		bsf		LED1
		goto		FinControlLED
EnciendeLED2
		movlw		01h
		xorwf		RxUnidad,0
		btfss		STATUS,Z
		goto		EnciendeLED3
		bsf		LED2
		goto		FinControlLED
EnciendeLED3
		movlw		02h
		xorwf		RxUnidad,0
		btfss		STATUS,Z
		goto		EnciendeLED4
		bsf		LED3
		goto		FinControlLED
EnciendeLED4
		movlw		03h
		xorwf		RxUnidad,0
		btfss		STATUS,Z
		goto		FinControlLED
		bsf		LED4
		goto		FinControlLED
	


	END                     		; directive 'end of program'
