;**********************************************************************
;                                                                     *
;    Filename:	    CheatBox.asm                                      *
;    Date:          24/01/2008                                        *
;    File Version:  0.1                                               *
;                                                                     *
;    Author:        Rubén Arranz                                      *
;    Company:       Electronics Design                                *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files required:                                                  *
;                    16F648A.lkr                                      *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:                                                           *
;                                                                     *
;                                                                     *
;                                                                     *
;                                                                     *
;**********************************************************************

	list      p=16F648A           ; list directive to define processor
	#include <p16F648A.inc>       ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file

	__CONFIG   _CP_OFF & _DATA_CP_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _WDT_ON & _PWRTE_ON & _HS_OSC 

;Variables Tenemos disponibles desde 0x20 hasta 0x7F en el Banco 0
;Mirar Datasheet para los otros bancos de memoria.

BITTECLADO	equ		0x20	;Bits faltantes por leer del Teclado
PBSTATUS	equ		0x21	;Estado del Puerto B
XOR_PB		equ		0x22	;Variable que nos dirá que puertos sufrieron cambios
TDATA		equ		0x23	;Variable para almacenar el dato recibido
TPARIDAD	equ		0x24	;Variable intermedia de control de paridad
TSTATUS		equ		0x25	;FLAGS para indicarnos el estado de lectura/escritura del Teclado
SENDATA		equ		0x26	;Variable para almacenar el dato a enviar al Teclado
BITDATA		equ		0x27	;Bits faltantes por enviar
SSTATUS		equ		0x28	;Status del Envío de datos
CSTATUS		equ		0x29	;Status del Envío de datos
CGEN		equ		0x2A	;Variable de proposito general asociada al Host
KOMBO_ACT	equ		0x2B	;Variable para saber Cual Kombo está Activo
KOMBO_ADR	equ		0x2C	;Direccion de inicio del Kombo Activo en la EEPROM
KOMBO_TYPE	equ		0x2D	;Tipo de Kombo que nos toca procesar
KOMBO_LONG	equ		0x2E	;Longitud total del Kombo
KOMBO_NUM	equ		0x2F	;Nº de tecla del Kombo que toca procesar
KOMBO1_K	equ		0x30	;Variable donde tendremos la tecla que activa el K1
KOMBO1_T	equ		0x31	;Variable donde tendremos el Tipo de Kombo que es el K1
KOMBO1_C	equ		0x32	;Variable donde tendremos la cantidad de Teclas que Componen el K1
K_ENABLED	equ		0x33	;Variable que Activa y Desactiva la ejecución de Kombos
CDATA		equ		0x34	;Variable para almacenar el dato a enviar
CTIME		equ		0x35	;Variable Para Almacenar el tiempo entre teclas del Kombo
TRANS_GEN	equ		0x36	;Variable de uso General usada en la transmisión al Host
VAR_GEN1	equ		0x37	;Variable de uso totalmente General
CPARIDAD	equ		0x38	;Variable intermedia de control de paridad
BYTETRANS	equ		0x39	;Guardamos aquí el Byte Original transmitido
KOMBO2_K	equ		0x3A	;Variable donde tendremos la tecla que activa el K1
KOMBO2_T	equ		0x3B	;Variable donde tendremos el Tipo de Kombo que es el K1
KOMBO2_C	equ		0x3C	;Variable donde tendremos la cantidad de Teclas que Componen el K1
KOMBO3_K	equ		0x3D	;Variable donde tendremos la tecla que activa el K1
KOMBO3_T	equ		0x3E	;Variable donde tendremos el Tipo de Kombo que es el K1
KOMBO3_C	equ		0x3F	;Variable donde tendremos la cantidad de Teclas que Componen el K1
KOMBO_TIME	equ		0x40	;Variable para el Timmer del Kombo
KOMBO_FLAG	equ		0x41	;Variable de apoyo a los kombos activos


;*** Constantes
CCK			equ		H'0007'	;Clock Hacia el computador
CDT			equ		H'0006'	;Linea de Datos desde y Hacia el Computador
TCK			equ		H'0005'	;Clock del Teclado
TDT			equ		H'0004'	;Linea de Datos desde y Hacia el Teclado
;*** Los siguientes son los Flags de TSTATUS
T_PAR		equ		H'0000'	;Indica el estado de la paridad del teclado
T_WAIT		equ		H'0001'	;Indica un estado de espera mientras dura el estado bajo del clock
T_CKHI		equ		H'0002'	;Este FLAG nos dirá quién puso en BAJO el Clock del Computador
T_EXT		equ		H'0003'	;En Este Flag Avisaremos si es un Caracter Extendido
T_REL		equ		H'0004'	;En ESte Flag Almacenaremos la Información de que la tecla esta siendo soltada
T_DAT		equ		H'0005'	;Dato Disponible, con este FLAG avisaremos que se completó la lectura del Dato
T_OK		equ		H'0006' ;Dato Disponible, con este FLAG avisaremos que el clock subio y podemos procesar el dato
;*** Los siguientes son los Flags de SSTATUS
S_PAR		equ		H'0000'	;Indica si se ha enviado el bit de paridad o no
S_STOP		equ		H'0001'	;Indica si se ha enviado el bit de stop o no
;*** Los siguientes son los Flags de CSTATUS
C_PAR		equ		H'0000'	;Indica el estado de la paridad del teclado
C_WAIT		equ		H'0001'	;Indica un estado de espera mientras dura el estado bajo del clock
C_EN		equ		H'0002'	;Indica si el host está inhibido de recibir datos o no
C_CKHI		equ		H'0003'	;Este FLAG nos dirá quién puso en BAJO el Clock del Teclado
C_DTHI		equ		H'0004'	;Este FLAG nos dirá quién puso en BAJO la Linea de Datos del Teclado
C_CMD		equ		H'0005'	;En este Flag Indicaremos que el Lo último que sucedió fue un envío desde el Host
C_ABORT		equ		H'0006'	;En este Flag Indicaremos un aborto de transmisión de parte del Host
C_TIM		equ		H'0007'	;Este Flag nos ayudará con el Timming al enviar datos al host
;*** Los siguientes son los Flags de KOMBO_FLAG
K1			equ		H'0000'
K2			equ		H'0001'
K3			equ		H'0002'
K4			equ		H'0003'
K5			equ		H'0004'
;*** Las Siguientes Constante son las direcciones de Inicio en la EEPROM de los Kombos
K1_ADR		equ		0x00
K2_ADR		equ		0x20
K3_ADR		equ		0x40
K4_ADR		equ		0x60
K5_ADR		equ		0x80
;*** Las siguiente constante es el Scan Code de la tecla que Activa y Desactiva el Modo "Kombo" (F10)
K_K			equ		0x09



;**********************************************************************
RESET_VECTOR	CODE	0x000			;Vector de Reset del Procesador
;		btfss	STATUS,4				;Despues de un inicio normal este bit esta en 1
;		goto							;Ocurrio un desborde de Watch Dog
		goto	Rst

VECT_INT		CODE	0x004			;Vector de Interrupción del Procesador
		goto	Inicio

MAIN			CODE	0x005			;Sector de Inicio del Block de Programa
Rst
		movlw	0x07
		movwf	CMCON					;Desactivamos los comparadores del Puerto A
		clrf	PORTA					;Ponemos las salidas del Puerto A en 0
		movlw 	b'11110100'				;RB2(TX)=1 others are 0 
        movwf 	PORTB
		bsf		STATUS,RP0				;Me cambio al Banco de memoria 1
		clrf 	TRISA					;Todo el puert A como salidas
		movlw	b'11110010'				;RB7-RB4 y RB1(RX)=entradas, Los otros salidas
		movwf	TRISB
;---------------------------------------------------------------------------------
;	Configuración USART Transmisor
		movlw	0x0A					;0x81= 9600 bps - Clock 20Mhz (115.200 bps = 0x0A)
		movwf	SPBRG
		bsf		TXSTA,BRGH				;Si BRGH = 1 Entonces: Baud Rate = F_Osc / (16 * (SPBRG + 1))
		bcf		TXSTA,SYNC				;Comunicación Asincrónica
		bsf		TXSTA,TXEN				;Habilita el Pin RB2 como TX
		bcf		STATUS,RP0				;Vuelvo al Banco 0
		bsf		RCSTA,SPEN				;SPEN = 1 habilita el puerto serie
;---------------------------------------------------------------------------------
        movlw	0x86					;Direcciono TRISB en Forma Indirecta, para no tener...
		movwf	FSR						;... Que cambiar de Banco a Cada Rato.

;---------------------------------------------------------------------------------
;*** Obtengo la Tecla de Activación del Kombo 1
		movlw	K1_ADR
		movwf	CGEN
		bsf		STATUS,RP0				;Me cambio al Banco de memoria 1
		;-------------------------------------------------------------------------
		;Aprovecho que estamos en el banco 1 para hacer esto
		bcf		OPTION_REG,NOT_RBPU		;Activo las resistencia Pull-Up del Port B
		;-------------------------------------------------------------------------
		movwf	EEADR
		bsf		EECON1,RD
		movfw	EEDATA
		bcf		STATUS,RP0	;Banco 0
		movwf	KOMBO1_K	;Guardo el Dato en la variable correspondiente
		incf	CGEN,F
		movfw	CGEN
		bsf		STATUS,RP0	;Banco 1
		movwf	EEADR
		bsf		EECON1,RD
		movfw	EEDATA
		bcf		STATUS,RP0	;Banco 0
		movwf	KOMBO1_T	;Guardo el Dato en la variable correspondiente
		incf	CGEN,W
		bsf		STATUS,RP0	;Banco 1
		movwf	EEADR
		bsf		EECON1,RD
		movfw	EEDATA
		bcf		STATUS,RP0	;Banco 0
		movwf	KOMBO1_C	;Guardo el Dato en la variable correspondiente
;---------------------------------------------------------------------------------
;*** Obtengo la Tecla de Activación del Kombo 2
		movlw	K2_ADR
		movwf	CGEN
		bsf		STATUS,RP0				;Me cambio al Banco de memoria 1
		movwf	EEADR
		bsf		EECON1,RD
		movfw	EEDATA
		bcf		STATUS,RP0	;Banco 0
		movwf	KOMBO2_K	;Guardo el Dato en la variable correspondiente
		incf	CGEN,F
		movfw	CGEN
		bsf		STATUS,RP0	;Banco 1
		movwf	EEADR
		bsf		EECON1,RD
		movfw	EEDATA
		bcf		STATUS,RP0	;Banco 0
		movwf	KOMBO2_T	;Guardo el Dato en la variable correspondiente
		incf	CGEN,W
		bsf		STATUS,RP0	;Banco 1
		movwf	EEADR
		bsf		EECON1,RD
		movfw	EEDATA
		bcf		STATUS,RP0	;Banco 0
		movwf	KOMBO2_C	;Guardo el Dato en la variable correspondiente
;---------------------------------------------------------------------------------
;*** Obtengo la Tecla de Activación del Kombo 3
		movlw	K3_ADR
		movwf	CGEN
		bsf		STATUS,RP0				;Me cambio al Banco de memoria 1
		movwf	EEADR
		bsf		EECON1,RD
		movfw	EEDATA
		bcf		STATUS,RP0	;Banco 0
		movwf	KOMBO3_K	;Guardo el Dato en la variable correspondiente
		incf	CGEN,F
		movfw	CGEN
		bsf		STATUS,RP0	;Banco 1
		movwf	EEADR
		bsf		EECON1,RD
		movfw	EEDATA
		bcf		STATUS,RP0	;Banco 0
		movwf	KOMBO3_T	;Guardo el Dato en la variable correspondiente
		incf	CGEN,W
		bsf		STATUS,RP0	;Banco 1
		movwf	EEADR
		bsf		EECON1,RD
		movfw	EEDATA
		bcf		STATUS,RP0	;Banco 0
		movwf	KOMBO3_C	;Guardo el Dato en la variable correspondiente
;---------------------------------------------------------------------------------
;Preparo el Timer
		bcf		T1CON,TMR1CS			;Para Usar como entrada Fosc/4
		bcf		T1CON,4					;LSB del Preescaler
		bsf		T1CON,5					;MSB del Preescaler
;---------------------------------------------------------------------------------
		clrf	K_ENABLED				;Limpio la variable de activación general de Kombos
		clrf	KOMBO_ACT				;Limpio la variable de Kombo Activo Individual
		movfw	PORTB
		movwf	PBSTATUS				;Cargo el estado del Puerto en PBSTATUS
		movlw	0x0B
		movwf	BITTECLADO				;Dejo el contador del teclado listo para recibir Datos

;*** Rutina principal
Inicio
;*********************************************************************************************
;*** Esta parte de la rutina se debió agregar para que el dispositivo detecte una contención
;*** Se necesita volver a leer el estado del Puerto B porque la contención NO genera una
;*** nueva interrupción, pero si cambios en el puerto, que pueden ser detectados volviendo
;*** a ejecutar la interrupción.
;*** Despues de Probarlo descubrimos que da resultado.-
;*********************************************************************************************
		btfsc	TSTATUS,T_OK	;Me fijo si se completó la lectura de un Dato
		call	KomboTest		;De haber un dato disponible ejecutamos la rutina testea Kombos
		call	SendKombo
		movfw	PORTB			;leeo el puerto B
		xorwf	PBSTATUS,W		;Lo comparo con con el anterior estado del puerto
		movwf	XOR_PB			;Ahora en XOR_PB tengo en 1 los Pines que cambiaron
		btfsc	XOR_PB,TCK		;Verifico si hubo un cambio en el clock del teclado
		call	Cambio_TCK		;Hubo Cambio, ejecuto la rutina correspondiente
		btfsc	XOR_PB,TDT		;Verifico si hubo un cambio en el dato del teclado
		call	Cambio_TDT		;Hubo Cambio, ejecuto la rutina correspondiente
		btfsc	XOR_PB,CCK		;Verifico si hubo un cambio en el clock del host
		call	Cambio_CCK		;Hubo Cambio, ejecuto la rutina correspondiente
		btfsc	XOR_PB,CDT		;Verifico si hubo un cambio en el dato del host
		call	Cambio_CDT		;Hubo Cambio, ejecuto la rutina correspondiente
		clrwdt
		goto	Inicio

Cambio_TCK
		btfss	PORTB,TCK		;Verifico si el pin esta en Alto
		goto	TCK_Bajo		;No lo está, ejecuto la parte correspondiente al estado bajo
		bsf		PORTB,CCK		;Paso el nuevo estado...
		bsf		INDF,CCK		;... al clock del host
		bsf		PBSTATUS,TCK	;Seteo el nuevo STATUS...
		bsf		PBSTATUS,CCK	;... del Puerto B
		btfsc	TSTATUS,T_DAT	;Verificamos si se terminó de leer un Dato
		bsf		TSTATUS,T_OK	;De ser así, al pasar por la subida de clock, estamos listos
		return
TCK_Bajo
		bcf		INDF,CCK		;Paso el nuevo estado...
		bcf		PORTB,CCK		;... al clock del host
		bcf		PBSTATUS,TCK	;Seteo el nuevo STATUS...
		bcf		PBSTATUS,CCK	;... del Puerto B
		bcf		TSTATUS,T_DAT	;Una Bajada del clock de Teclado indica que estamos leyendo un dato
		call	ExtraeDato		;Llamamos a la rutina Para extraer el dato enviado
		decfsz	BITTECLADO,F	;Luego de cada bajada de reloj, decrementamos el contador
		return					;Si no se completaron las 11 bajadas de reloj continuamos
		movlw	0x0B			;Se completaron, dejo listo todo para...
		movwf	BITTECLADO		;... leer el próximo dato
		bcf		TSTATUS,T_PAR	;Para la nueva lectura, limpiamos el Flag de Paridad...
		bcf		TPARIDAD,0		;... Seteamos la variable intermedia de control de paridad....
		return
Cambio_TDT
		btfss	PORTB,TDT		;Verifico si el pin esta en Alto
		goto	TDT_Bajo		;No lo está, ejecuto la parte correspondiente al estado bajo
		bsf		PORTB,CDT		;Paso el nuevo estado...
		bsf		INDF,CDT		;... al data del host
		bsf		PBSTATUS,TDT	;Seteo el nuevo STATUS...
		bsf		PBSTATUS,CDT	;... del Puerto B
		return
TDT_Bajo
		bcf		INDF,CDT		;Paso el nuevo estado...
		bcf		PORTB,CDT		;... al data del host
		bcf		PBSTATUS,TDT	;Seteo el nuevo STATUS...
		bcf		PBSTATUS,CDT	;... del Puerto B
		return
Cambio_CCK
		btfss	PORTB,CCK		;Verifico si el pin esta en Alto
		goto	CCK_Bajo		;No lo está, ejecuto la parte correspondiente al estado bajo
		bsf		PORTB,TCK		;Paso el nuevo estado...
		bsf		INDF,TCK		;... al clock del teclado
		bsf		PBSTATUS,CCK	;Seteo el nuevo STATUS...
		bsf		PBSTATUS,TCK	;... del Puerto B
		return
CCK_Bajo
		bcf		INDF,TCK		;Paso el nuevo estado...
		bcf		PORTB,TCK		;... al clock del teclado
		bcf		PBSTATUS,CCK	;Seteo el nuevo STATUS...
		bcf		PBSTATUS,TCK	;... del Puerto B
		return
Cambio_CDT
		btfss	PORTB,CDT		;Verifico si el pin esta en Alto
		goto	CDT_Bajo		;No lo está, ejecuto la parte correspondiente al estado bajo
		bsf		PORTB,TDT		;Paso el nuevo estado...
		bsf		INDF,TDT		;... al data del teclado
		bsf		PBSTATUS,CDT	;Seteo el nuevo STATUS...
		bsf		PBSTATUS,TDT	;... del Puerto B
		return
CDT_Bajo
		bcf		INDF,TDT		;Paso el nuevo estado...
		bcf		PORTB,TDT		;... al data del teclado
		bcf		PBSTATUS,CDT	;Seteo el nuevo STATUS...
		bcf		PBSTATUS,TDT	;... del Puerto B
		return

;*** Esta es una de las rutinas más importantes ya que con ella obtenemos el dato del teclado
ExtraeDato
		movlw	0x0B			;Buscamos saber si este es el primer bit
		xorwf	BITTECLADO,W	;Un XOR de BITTECLADO con 0x0B nos dirá si este es el Bit de Start
		btfsc	STATUS,Z		;Si despues del XOR el bit Z del STATUS quedó en "0"
		return					;No me interesa que este mal el bit de Start
		movlw	0x02			;Probamos ahora si es el bit Nº 10, el de paridad
		xorwf	BITTECLADO,W	;Un XOR de BITTECLADO con 0x02 nos dirá si este es el Bit de Paridad
		btfsc	STATUS,Z		;Si despues del XOR el bit Z del STATUS quedó en "0"
		goto	VerifParidad	;Es el 10º bit, vamos a chequear si la paridad coincide
		movlw	0x01			;Intentemos finalmente con el bit de Stop
		xorwf	BITTECLADO,W	;Un XOR de BITTECLADO con 0x01 nos dirá si este es el Bit de Stop
		btfsc	STATUS,Z		;Si despues del XOR el bit Z del STATUS quedó en "0"
		goto	TipoTecla		;Es el 11º bit, aprovecho de Determinar que tipo de Tecla se Presionó
;*** Si todo lo anterior falló, es un bit de datos común y silvestre, y vamos a extraer su información
;*** Utilizaremos el acarreo para "empujar" el bit de dato en la variable TDATA y formar el byte completo
		bcf		STATUS,C		;Asumimos que el Dato es Cero limpiando el bit de acarreo...
		btfsc	PORTB,TDT		;Verificamos si el dato enviado es un cero...
		bsf		STATUS,C		;...si no lo es ponemos un 1 en el acarreo
		btfsc	STATUS,C		;Antes de cargar el valor verificamos si modifica el bit de paridad...
		comf	TPARIDAD,F		;...si el dato es un "1" el bit de paridad se ve afectado.
		rrf		TDATA,F			;Finalmente el cero o uno es ingresado al dato
;*** algo interesante, es que el bit es ingresado como MSB, pero en los sucesivos ingresos de datos
;*** se irá desplazando hasta convertirse en LSB
		return					;Volvemos a la rutina que nos llamó

;*** Esta nueva rutina de verificación de paridad es mas compacta y no se ve afectada por cambios...
;*** ... en los Pines del clock de teclado.
VerifParidad
		bsf		TSTATUS,T_PAR	;Asumimos que la paridad esta con error...
		btfss	PORTB,TDT		;Nos fijamos si la Paridad que indica el Teclado es 1
		goto	ParidadCero		;No, es cero, vamos a esa parte de la rutina
		btfsc	TPARIDAD,0		;Si la paridad calculada es 0 saltamos sin limpiar el bit de paridad
		bcf		TSTATUS,T_PAR	;Si es 1 es igual a la calculada por nosotros y limpiamos el bit
		return					;Volvemos a la rutina que nos llamó
ParidadCero
		btfss	PORTB,TDT		;Si la paridad calculada es 1 saltamos sin limpiar el bit de paridad
		bcf		TSTATUS,T_PAR	;Si es 0 es igual a la calculada por nosotros y limpiamos el bit
		return

;*** Lo Primero que debo averiguar, es si se trata de una tecla Especial, de una tecla soltada
;*** O de una tecla definitiva.
;*** De Tratarse de alguna de las dos primeras opciones, solo modificaremos unos FLAGS
TipoTecla
		movlw	0xE0			;Intentamos Comparar el Dato con el Comando "0xE0"...
		xorwf	TDATA,W			;... Que indicaría una tecla Extendida
		btfss	STATUS,Z		;Un uno en el Status indicaría que lo es
		goto	Test_Release	;No es el caso, probemos si soltaron una tecla
		bsf		TSTATUS,T_EXT	;Ok, es una tecla extendida, solo cambiamos el FLAG
		clrf	TDATA			;Y dejamos el Dato en 0
		return
Test_Release
		movlw	0xF0			;comparamos con "0xF0"...
		xorwf	TDATA,W			;...Para probar si se esta soltando una tecla
		btfss	STATUS,Z		;Un uno en el Status indicaría que se está soltando una tecla
		goto	Procesar_Data	;Un cero me indica que no es el caso
		bsf		TSTATUS,T_REL	;Activamos el FLAG de tecla soltada
		return
Procesar_Data
		movlw	0x00			;Preparo W con un cero, que será modificado o no según la próxima instrucción
		btfsc	TSTATUS,T_REL	;Veamos Ahora si se envió un comando de Tecla Soltada en el envío anterior
		movlw	0x80			;De ser así le vamos a sumar "0x80" al dato
		addwf	TDATA,W			;Convirtiéndo el Scan Code doble en uno simple
		movwf	TDATA
;---------------------------------------------------------------------------------
		movwf	TXREG			;Transmito los cambios por el Puerto Serie
;---------------------------------------------------------------------------------
		bcf		TSTATUS,T_EXT	;Limpiamos el Flag de Tecla Extendida
		bcf		TSTATUS,T_REL	;Limpiamos el Flag de Tecla Soltada
		bsf		TSTATUS,T_DAT	;Avisamos que se completó la lectura del dato
		return
		

;---------------------------------------------------------------------------------
; Una transmisión del CheatBox al Teclado sería así:
;Poner en 0 el Clock, esperar 35us poner en 0 el Data, Esperar 125us y soltar el clock
;    ____                                _____
; CK     \                              /
;         \____________________________/

;        |<--35us-->|<------125us------>|
;    ______________
; DT               \
;                   \_________________________

;Con esto avisamos que vamos a enviar algo, luego de esto, pasado cerca de 1ms, el teclado
;comienza a generar pulsos de clock y debemos enviar los datos luego de cada bajada de clock
;           _____      __      __      __      __      __      __      __      __      __      __      __      ______
;          /     \    /  \    /  \    /  \    /  \    /  \    /  \    /  \    /  \    /  \    /  \    /  \    /  
; CK  ____/<-1ms->\__/    \__/    \__/    \__/    \__/    \__/    \__/    \__/    \__/    \__/    \__/    \__/
;
;  Host -->|<-------------- Teclado
;                    ______  ______  ______  ______  ______  ______  ______  ______  ______  _______ ______        __
; DT \              /  D0  \/  D1  \/  D2  \/  D3  \/  D4  \/  D5  \/  D6  \/  D7  \/  D8  \/ PAR   / STOP \ ACK. /
;     \____________/_______/\______/\______/\______/\______/\______/\______/\______/\______/\______/        \____/
;																					         Host ------>|<-- Teclado
; Para Finalizar, despues del bit de Stop, el teclado da un pulso más de relok y contesta con un ACK
Envio_a_Teclado
		movwf	SENDATA			;Guardo el dato a transmitir en la variable correspondiente
		bcf		INDF,TCK		;Pongo el clock...
		bcf		PORTB,TCK		;... del teclado en 0
		bcf		PBSTATUS,TCK	;Anoto el Status del Puerto B
		movlw	0xD3			;Cargo el valor necesario para esperar 35 us
		call	Wait_XXus		;Llamo a la rutina de demora
		bcf		INDF,TDT		;Pongo el Data...
		bcf		PORTB,TDT		;... del teclado en 0
		bcf		PBSTATUS,TDT	;Anoto el Status del Puerto B
		movlw	0x61			;Cargo el valor necesario para esperar 125 us
		call	Wait_XXus		;Llamo a la rutina de demora
		bsf		INDF,TCK		;Pongo el clock...
		bsf		PORTB,TCK		;... del teclado en 1
		bsf		PBSTATUS,TCK	;Anoto el Status del Puerto B
		clrf	TPARIDAD		;Seteamos la variable intermedia de control de paridad....
		bsf		SSTATUS,S_PAR	;Seteo el Flag para idicar que no se ha enviado el bit de Paridad
		bsf		SSTATUS,S_STOP	;Seteo el Flag para idicar que no se ha enviado el bit de Stop
;De ahora en más, debo esperar a que el teclado envíe los pulsos de clock y...
;... el dispositivo debe contestar con los bits del dato a transmitir
		movlw	0x08			;Cantidad de bits a enviar
		movwf	BITDATA
EspClock_H
		btfsc	PORTB,TCK		;Espero que el clock baje
		goto	EspClock_H		;Me mantengo en el bucle
		btfss	SENDATA,0		;Verifico el valor del bit 0 de SENDATA
		goto	Envio_0			;Es 0, voy a la parte correspondiente
		bsf		INDF,TDT		;Pongo el Data...
		bsf		PORTB,TDT		;... del teclado en 1
		bsf		PBSTATUS,TDT	;Anoto el Status del Puerto B
		comf	TPARIDAD,F		;...si el dato es un "1" el bit de paridad se ve afectado.
		goto	ParityStop
Envio_0
		bcf		INDF,TDT		;Pongo el Data...
		bcf		PORTB,TDT		;... del teclado en 0
		bcf		PBSTATUS,TDT	;Anoto el Status del Puerto B
ParityStop
		rrf		SENDATA,f		;Roto a la derecha los bits, para poder leer el siguiente bit
		decfsz	BITDATA,f		;un bit menos para enviar
		goto	EspClock_L		;No hemos llegado al último bit, continuamos
;Al llegar a este punto, hemos transmitido el Byte Completo
		btfss	SSTATUS,S_PAR	;Verificamos si se ha transmitido el Bit de Paridad
		goto	BitStop			;Ya se transmitió, continuamos
		clrf	SENDATA			;Borramos completamente SENDATA
		btfsc	TPARIDAD,0		;Verificamos si el bit de paridad es 0
		bsf		SENDATA,0		;No lo es, preparamos el envío de un 1
		bcf		SSTATUS,S_PAR	;Limpiamos el flag de paridad, para anunciar que ya enviamos este bit
		incf	BITDATA,F		;Preparamos BITDATA para poder enviar un bit más
		goto	EspClock_L		;Continuamos
BitStop
		btfss	SSTATUS,S_STOP	;Verificamos si se ha transmitido el Bit de STOP
		goto	FinEnvio		;Ya se transmitió, vamos al final
		bsf		SENDATA,0		;El bit de STOP es siempre 1
		bcf		SSTATUS,S_STOP	;Limpiamos el flag de STOP, para anunciar que ya enviamos este bit
		incf	BITDATA,F		;Preparamos BITDATA para poder enviar un bit más
		clrf	TPARIDAD		;Limpiamos la variable de control de paridad
EspClock_L
		btfss	PORTB,TCK		;Testeamos el clock...
		goto	EspClock_L		;Mientras este bajo, nos mantenemos en el loop
		goto	EspClock_H		;Subió, continuamos
FinEnvio
		movlw	0x02
		movwf	BITDATA
EspCK_L
		btfss	PORTB,TCK		;Testeamos el clock...
		goto	EspCK_L			;Mientras este bajo, nos mantenemos en el loop
EspCK_H
		btfsc	PORTB,TCK		;Testeamos el clock...
		goto	EspCK_H			;Mientras este alto, nos mantenemos en el loop
		decfsz	BITDATA,F
		goto	EspDT_H
		goto	EspCK_L
EspDT_H
		btfss	PORTB,TCK		;Testeamos el data...
		goto	EspDT_H			;Mientras este bajo, nos mantenemos en el loop
		movwf	PORTB
		movwf	PBSTATUS
		return
;---------------------------------------------------------------------------------

;Aqui hemos de utilizar tiempos para el envío de datos al host.
;Con un oscilador externo de 20 MHz y usando el timer TMR1 como contador, tendríamos
;una tabla de tiempos así:
;   1us, TMR1 = 0x01 (0xFF)
;  10us, TMR1 = 0x0C (0xF3)
;  15us, TMR1 = 0x13 (0xEC)
;  20us, TMR1 = 0x19 (0xE6)
;  25us, TMR1 = 0x1F (0xE0)
;  30us, TMR1 = 0x25 (0xDA)
;  35us, TMR1 = 0x2C (0xD3)
;  50us, TMR1 = 0x3F (0xC0)
;  75us, TMR1 = 0x5F (0xA0)
; 100us, TMR1 = 0x7F (0x80)
; 125us, TMR1 = 0x9E (0x61)
; 150us, TMR1 = 0xBE (0x41)

Wait_XXus
		clrf	TMR1H			;Limpiamos el Timer
		movwf	TMR1L			;Anotamos el Tiempo que nos enviaron
		bsf		T1CON,TMR1ON	;Encendemos el Timer
Wait_us
		clrwdt
		btfss	TMR1H,0			;Testeamos cuando se enciende el primer bit del Contador Alto
		goto	Wait_us			;Esperamos que se cumpla el tiempo
		bcf		T1CON,TMR1ON	;Apagamos el Timer
		return					;Volvemos desde donde nos llamaron
		


;-----------------------------  RUTINA PARA ENVIAR LOS KOMBOS  -----------------------------------
;Como primera medida, debemos determinar cuando estan dadas las condiciones para enviar Los Kombos activos.
; 1º- Luego de un comando enviado por el host.
;		Si el host envió un comando al teclado, espera el conocido ACK, Si el comando fue un "Resend"
;		El teclado tendrá que reenviar el último byte y si el comando fue un "Echo" el teclado responde
;		con un "Echo", sea cual fuere la situación, el host espera una respuesta del teclado
;		por ello usamos un FLAG "C_CMD" que encendemos cada vez que tengamos un envío del host al teclado
;		y apagamos cuando el envío sea del teclado al host.
;2º- Cuando estamos en medio de un envío de datos desde el teclado al host
;		Esto se puede averiguar fácilmente, chequeando que la variable BITTECLADO sea igual a "0"
;3º- Cuando el envío de Kombos este activo
;		Esto lo logramos testeando K_ENABLED
;4º- Tengamos un Kombo activo
;		Esto lo logramos testeando KOMBO_ACT
;5º- Que se halla superado el tiempo de espera entre tecla y tecla
;		Esto lo logramos saber chequeando las variable del Timer (TMR1H y TMR1L)
;Si las condiciones están dadas, debo:
;		Inhibir al teclado del envío de teclas
;		Hacer un envío completo de todos los Byte que implican esta tecla (Ejemplo E0, F0, 45)
;		y volver al menú principal para verificar nuevas teclas
;		Testear si el host intenta enviar un comando, en cuyo caso debo llamar a la rutina adecuada
KomboTest
		bcf		TSTATUS,T_DAT	;Limpio este Flag, para indicar que fue procesado el Dato
		bcf		TSTATUS,T_OK	;Limpio este Flag, para indicar que fue procesado el Dato
		movfw	TDATA
		xorlw	K_K				;Comparo TDATA con 0x09 (Tecla F10) para activar o desactivar los kombos
		btfsc	STATUS,Z
		comf	K_ENABLED,F		;Si es la tecla indicada, se activan o desactivan los combos
;Es el turno de verificar si se activó uno de los Kombos en particular y deberemos pasar cierta
;Información del Kombo activado a las variables generales, estas son:
;KOMBO_ACT		Variable para saber Cual Kombo está Activo, se usa como Flag siendo el LSB el Kombo 1
;KOMBO_ADR		Direccion de inicio del Kombo Activo en la EEPROM
;KOMBO_TYPE		Tipo de Kombo que nos toca procesar
;KOMBO_LONG		Longitud total del Kombo
;KOMBO_NUM		Nº de tecla del Kombo que toca procesar
;KOMBO1_K	equ		0x30	;Variable donde tendremos la tecla que activa el K1
;KOMBO1_T	equ		0x31	;Variable donde tendremos el Tipo de Kombo que es el K1
;KOMBO1_C	equ		0x32	;Variable donde tendremos la cantidad de Teclas que Componen el K1

		movfw	TDATA			;Cargo el dato leido del teclado en W
		xorwf	KOMBO1_K,W		;Lo Comparo con ta tecla del K1
		btfss	STATUS,Z		;Si conciden hago cambios en K1
		goto	TestK2			;No coinciden, probamos con el K2
K1_Change
		btfss	KOMBO_ACT,K1	;Me fijo si actualmente el K1 está activo...
		goto	K1_Enable		;...no lo está, vamos a activarlo
		;clrf	KOMBO_ACT		;Lo estaba, entonces lo desactivo
		return					;Volvemos a la rutina que nos llamó
K1_Enable
		clrf	KOMBO_ACT		;Limpiamos cualquier combo activo
		bsf		KOMBO_ACT,K1	;Seteamos como activo el K1
		movfw	KOMBO1_C		;Paso la longitud del Kombo a...
		movwf	KOMBO_LONG		;... KOMBO_LONG
		clrf	KOMBO_NUM		;Limpio la Variable KOMBO_NUM para empezar por la primera tecla del Kombo
		movfw	KOMBO1_T		;Paso el tipo de Kombo...
		movwf	KOMBO_TYPE		;A la variable que le corresponde
		movlw	K1_ADR			;Cargo la Dirección en la EEPROM del K1...
		movwf	KOMBO_ADR		;... en la variable correspondiente
		return					;Volvemos a la rutina que nos llamó
TestK2
		movfw	TDATA			;Cargo el dato leido del teclado en W
		xorwf	KOMBO2_K,W		;Lo Comparo con ta tecla del K2
		btfss	STATUS,Z		;Si conciden hago cambios en K2
		goto	TestK3			;No coinciden, probamos con el K3
K2_Change
		btfss	KOMBO_ACT,K2		;Me fijo si actualmente el K2 está activo...
		goto	K2_Enable		;...no lo está, vamos a activarlo
		;clrf	KOMBO_ACT		;Lo estaba, entonces lo desactivo
		return					;Volvemos a la rutina que nos llamó
K2_Enable
		clrf	KOMBO_ACT		;Limpiamos cualquier combo activo
		bsf		KOMBO_ACT,K2	;Seteamos como activo el K2
		movfw	KOMBO2_C		;Paso la longitud del Kombo a...
		movwf	KOMBO_LONG		;... KOMBO_LONG
		clrf	KOMBO_NUM		;Limpio la Variable KOMBO_NUM para empezar por la primera tecla del Kombo
		movfw	KOMBO2_T		;Paso el tipo de Kombo...
		movwf	KOMBO_TYPE		;A la variable que le corresponde
		movlw	K2_ADR			;Cargo la Dirección en la EEPROM del K2...
		movwf	KOMBO_ADR		;... en la variable correspondiente
		return					;Volvemos a la rutina que nos llamó
TestK3
		movfw	TDATA			;Cargo el dato leido del teclado en W
		xorwf	KOMBO3_K,W		;Lo Comparo con ta tecla del K3
		btfss	STATUS,Z		;Si conciden hago cambios en K3
		return					;*** SI HEMOS DE USAR MAS KOMBOS, AQUI DEBE HABER UN: goto	TestK4
K3_Change
		btfss	KOMBO_ACT,K3		;Me fijo si actualmente el K3 está activo...
		goto	K3_Enable		;...no lo está, vamos a activarlo
		;clrf	KOMBO_ACT		;Lo estaba, entonces lo desactivo
		return					;Volvemos a la rutina que nos llamó
K3_Enable
		clrf	KOMBO_ACT		;Limpiamos cualquier combo activo
		bsf		KOMBO_ACT,K3	;Seteamos como activo el K3
		movfw	KOMBO3_C		;Paso la longitud del Kombo a...
		movwf	KOMBO_LONG		;... KOMBO_LONG
		clrf	KOMBO_NUM		;Limpio la Variable KOMBO_NUM para empezar por la primera tecla del Kombo
		movfw	KOMBO3_T		;Paso el tipo de Kombo...
		movwf	KOMBO_TYPE		;A la variable que le corresponde
		movlw	K3_ADR			;Cargo la Dirección en la EEPROM del K3...
		movwf	KOMBO_ADR		;... en la variable correspondiente
		return					;Volvemos a la rutina que nos llamó
		
		
SendKombo		
;		btfsc	CSTATUS,C_CMD	;Verificamos que la última acción no haya sido una comunicación desde el host
;		return					;Eso era, no podemos enviar Kombos
		movlw	0x0B			;Testeamos ahora...
		xorwf	BITTECLADO,W	;...que no estemos en medio...
		btfss	STATUS,Z		;...de una transmisión desde el teclado al host
		return					;Lamentablemente eso es, No es el momento
		btfss	K_ENABLED,0		;Luego probamos si los Kombos en General estan activos
		return					;No lo estan, "pa la casa"
		movfw	KOMBO_ACT		;Es el turno de testear...
		andlw	0xFF		
		btfsc	STATUS,Z		;...que haya alguno activo
		return					;No hay ninguno... "pa la casa"
;Solo queda testear que se haya cumplido el tiempo entre Tecla y Tecla del Kombo
;Si el Timer esta apagado, no se estaban enviando Kombos, o a cambiado el Kombo activo
;Lo que me da via libre para empezar con este.
		btfss	T1CON,TMR1ON	;Verificamos que el timer este apagado
		goto	Luz_Verde
		
;TMR1H,7 se activará cuando hayan sucedido 256*128 = 32.768 instrucciones
;Eso sucederá cuando se hayan ejecutado 32768*4 = 131.072 ciclos de reloj
;A una frecuencia de 20 MHz, eso ocurriría en aproximadamente 6,5 ms
;Para tener mejor control usaremos el preescaler 1:4 con lo que obtendríamos 26 ms
;Para ver si alcanzamos la cuota de 26ms bastará con chequear el MSB de TMR1H, cuando se encienda estamos
		btfss	TMR1H,7			;Chequeamos el Contador del Timer
		return					;Todavía no..."pa la casa"
		bcf		T1CON,TMR1ON	;Apagamos el contador
		decfsz	KOMBO_TIME,F
		goto	LimpiarTimer
		
;Tenemos luz verde, hagámoslo...
Luz_Verde
		bcf		INDF,TCK		;Convertimos el puerto en Salida... (62)
		bcf		PORTB,TCK		;... y ponemos un 0 para inhibir el envío de datos desde el teclado
		movfw	KOMBO_LONG		;Cargo la longitud total del Kombo en W
		xorwf	KOMBO_NUM,W		;Lo comparo con la cantidad de Teclas procesadas hasta el momento
		btfsc	STATUS,Z		;Si son distintas continuo procesando teclas
		goto	MataKombo		;Si son iguales desactivo el Kombo
		movfw	KOMBO_ADR		;Cargo la dirección en EEPROM del Kombo a procesar en W
		addlw	0x03			;Luego le sumo 3 a W y ya tengo la 1º posición de la EEPROM de los datos
		addwf	KOMBO_NUM,W		;Finalmente le sumo el Nº de byte que nos toca procesar
		movwf	CGEN			;Guardo el Valor en una variable General
;--------------------------------------------------------------------------------------------------------
;***Con este trozo de código cargaremos CDATA y CTIME
		bsf		STATUS,RP0		;Todo este pedazo, es para leer un dato desde la EEPROM
		movwf	EEADR
		bsf		EECON1,RD
		movfw	EEDATA
		bcf		STATUS,RP0		;Vuelvo al viejo y querido Banco de memoria 0
		movwf	CDATA			;Guardo el Dato de la EEPROM en la variable de datos
		incf	CGEN,W			;Pasamos a la siguiente dirección de memoria
		bsf		STATUS,RP0		;Todo este pedazo, es para leer un dato desde la EEPROM
		movwf	EEADR
		bsf		EECON1,RD
		movfw	EEDATA
		bcf		STATUS,RP0		;Vuelvo al viejo y querido Banco de memoria 0
		movwf	CTIME			;Guardo el Dato de la EEPROM en la variable de Tiempo
;--------------------------------------------------------------------------------------------------------
;Debemos obtener el/los Byte/s a transmitir
		movlw	0xE0
		btfsc	CDATA,7			;Averiguamos si es una tecla extendida
		call	TransmiteData	;Si lo es, transmitimos el byte 0xE0 (100)
		btfsc	CSTATUS,C_ABORT ;Averiguamos si en la transmisión hubo un aborto
		goto	Abort_Trans
		movlw	0xF0
		btfsc	CTIME,7			;Averiguamos si es una liberación de tecla
		call	TransmiteData	;Si lo es, transmitimos el byte 0xF0
		btfsc	CSTATUS,C_ABORT ;Averiguamos si en la transmisión hubo un aborto
		goto	Abort_Trans
		bcf		CDATA,7			;Finalmente, preparamos el dato
		movfw	CDATA			;Lo cargamos en W
		call	TransmiteData	;y lo transmitimos al host
		btfsc	CSTATUS,C_ABORT ;Averiguamos si se aborto la transmisión
		goto	Abort_Trans		;El Incremento se hace luego del testeo de abort, para asegurarnos de enviar el Kombo Completo
		bsf		INDF,TCK		;Liberamos al Teclado...
		bsf		PORTB,TCK		;... Para que pueda transmitir
		incf	KOMBO_NUM,F		;Dejo todo listo...
		incf	KOMBO_NUM,F		;...Para la próxima lectura
		movfw	CTIME			;Cargo CTIME
		movwf	KOMBO_TIME		;... y guardo el valor en la Variable de tiempo
		bcf		KOMBO_TIME,7	;Limpio el MSB para que solo cuenten los LSM
		movfw	PORTB			;Registro en el PBSTATUS
		movwf	PBSTATUS		;El actual estado del puerto
;--------------------------------------------------------------------------------------------------------
;Con esta parte del código, debemos setear el timer para lograr el tiempo requerido entre tecla y tecla
;Para ello debemos usar CTIME cuyos 7 LSB tienen el tiempo un valor de 38 (0x26) equivalen a 1 Seg.
;--------------------------------------------------------------------------------------------------------
LimpiarTimer
		clrf	TMR1H			;Limpiamos el timer
		clrf	TMR1L			;
		bsf		T1CON,TMR1ON	;Encendemos el Timer para enviar las Teclas separadas el tiempo dispuesto
		return					;Regresamos ahora a la rutina principal
Abort_Trans
		bcf		CSTATUS,C_ABORT
		return
MataKombo
		clrf	KOMBO_ACT
		clrf	KOMBO_NUM
		clrf	TMR1H			;Limpiamos el timer
		clrf	TMR1L			;
		bsf		INDF,TCK		;Liberamos al Teclado...
		bsf		PORTB,TCK		;... Para que pueda transmitir
		return

TransmiteData
;Una transmisión de teclado se comporta así
;    ________________     ___     ___     ___     ___     ___     ___     ___     ___     ___     ___     _____
;                    |   |   |   |   |   |   |   |   |   |   |   |   |   | H |   |   | L |   |   |   |   |
; CK                 |___|   |___|   |___|   |___|   |___|   |___|   |___|   |___|   |___|   |___|   |___|
;    <-----50us----->|
;                                                                     -->|30u|<-- -->|30u|<--
;          |<--10us->|          -->| |<--             -->| |<--
; El dato debe estar listo al       ^                     ^     El dato debe permanecer al menos
; menos 10us antes del flanco de ___|                     |___  10us depues del flanco de bajada
; bajada del Reloj                                              del Reloj
;    ______                 _______ _______ _______ _______ _______ _______ _______ _______ _______ ___________
; DT       |      START    |  D0   |  D1   |  D2   |  D3   |  D4   |  D5   |  D6   |  D7   | PAR.  |  STOP 
;          |_______________|_______|_______|_______|_______|_______|_______|_______|_______|_______|
;

		movwf	TRANS_GEN		;Guardamos el dato a transmitir en la variable general
		movwf	BYTETRANS		;Y en otra variable que no será modificada para enviarla vía puerto serie
		movlw	0xC0			;Debemos esperar 50 us
		call	Wait_XXus		;Lo hacemos
;Habiendo esperado los 50us que marca la ley, verifico si el clock y data del host, manifiestan intenciones
; de transmitir
Wait_Trans_CK
		btfss	PORTB,CCK		;Si el Clock esta a nivel bajo, el host me inhibe de transmitir...
		goto	Wait_Trans_CK	;...y debo esperar
		btfss	PORTB,CDT		;Si el el host bajo la linea de datos, es un RTS, intenta transmitir...
		goto	Abortar			;...y debo abortar
;La Transmisión en si se desarrolla de la siguiente manera:
;El Clock cambia de estado cada 30us
;El dato debe estar puesto unos 10us antes de la bajada del clock
;Y permanecer despues de la subida otros 10us
;Con esta mecánica debemos transmitir 1 bit de inicio, 8 bits de datos
;1 bit de paridad y 1 de stop... Empecemos
;Transmitimos primero el bit de START que es 0
		bcf		CSTATUS,C_DTHI	;Usaremos este Flag para enviar los datos, enviamos el bit de Start que es 0
		call	TransmiteBit
		btfss	PORTB,CCK		;Testeamos si hay Contención
		goto	Abortar			;La hay, tenemos que abortar
;El Bit Start esta enviado, ahora debo buscar cada bit del byte de datos y procesarlo
		movlw	0x08			;vamos transmitir 8 bits
		movwf	VAR_GEN1		;Usaremos esta variable como contador
		clrf	CPARIDAD		;Limpiamos la variable de Paridad Intermedia
		comf	CPARIDAD,F
Loop_Bit
		bsf		CSTATUS,C_DTHI	;Asumimos que el bit a transmitir es un uno
		btfss	TRANS_GEN,0		;Testeamos el bit real, si es un uno, lo dejamos como está...
		bcf		CSTATUS,C_DTHI	;... Pero si es un cero lo dejamos en cero
		call	TransmiteBit	;Llamamos a la rutina de transmisión del bit
		btfsc	TRANS_GEN,0		;Verificamos si el bit afecta al bit de paridad
		comf	CPARIDAD,F		;Lo hace
		btfss	PORTB,CCK		;Testeamos si hay Contención
		goto	Abortar			;La hay, tenemos que abortar
		bcf		STATUS,C		;Limpiamos el acarreo
		rrf		TRANS_GEN,F		;rotamos los bit de la variable para sacar el siguiente
		decfsz	VAR_GEN1,F		;Decrementamos el contador de bits
		goto	Loop_Bit		;Continuamos con la trasnmisión bit a bit del dato
;Transmitimos ahora el bit de paridad
		bsf		CSTATUS,C_DTHI	;Asumimos que el bit a transmitir es un uno
		btfss	CPARIDAD,0		;Testeamos el bit real, si es un uno, lo dejamos como está...
		bcf		CSTATUS,C_DTHI	;... Pero si es un cero lo dejamos en cero
		call	TransmiteBit	;Llamamos a la rutina de transmisión del bit
		btfss	PORTB,CCK		;Testeamos si hay Contención
		goto	Abortar			;La hay, tenemos que abortar
;Si llegamos hasta aquí el Host no puede abortar la transmisión
		bsf		CSTATUS,C_DTHI	;el bit de Stop es un uno
		call	TransmiteBit	;Llamamos a la rutina de transmisión del bit
;---------------------------------------------------------------------------------
		movfw	BYTETRANS
		movwf	TXREG			;Transmito los cambios por el Puerto Serie
;---------------------------------------------------------------------------------
		return
		
TransmiteBit
		movfw	PORTB			;Seteamos el Actual estado del port
		movwf	PBSTATUS		;En el PBSTATUS
		btfss	CSTATUS,C_DTHI	;Verificamos si quiero transmitir un 1 o un 0
		goto	Trans_0
		bsf		PORTB,CDT		;Ponemos un 1.
		bsf		INDF,CDT		;Convertimos el puerto en Entrada...
		bsf		PBSTATUS,CDT	;Seteamos PBSTATUS con el nuevo valor
		goto	Sigo_Trans
Trans_0
		bcf		INDF,CDT		;Convertimos el puerto en Salida...
		bcf		PORTB,CDT		;... ponemos un 0.
		bcf		PBSTATUS,CDT	;Seteamos PBSTATUS con el nuevo valor
Sigo_Trans
		movlw	0xEC			;Esperamos 15 us
		call	Wait_XXus
		bcf		INDF,CCK		;... Bajamos el Clock, Convertimos el puerto en Salida...
		bcf		PORTB,CCK		;... ponemos un 0.
		bcf		PBSTATUS,CCK	;Seteamos PBSTATUS con el nuevo valor
		movlw	0xDA			;Esperar 30 us
		call	Wait_XXus
		bsf		PORTB,CCK		;Subimos el Clock...
		bsf		INDF,CCK		;...Convertimos el puerto en Entrada
		bsf		STATUS,CCK		;Seteamos PBSTATUS con el nuevo valor
		movlw	0xEC			;Esperamos 15 us
		call	Wait_XXus
		return

Abortar
		bsf		CSTATUS,C_ABORT	;Seteo el FLAG de aborto de Transmisión
		bsf		PORTB,CCK		;Subimos el Clock...
		bsf		INDF,CCK		;...Convertimos el puerto en Entrada
		bsf		STATUS,CCK		;Seteamos PBSTATUS con el nuevo valor
		bsf		PORTB,CDT		;Subimos el Data
		bsf		INDF,CDT		;Convertimos el puerto en Entrada...
		bsf		PBSTATUS,CDT	;Seteamos PBSTATUS con el nuevo valor
		return					;Regreso a la rutina que me llamó.
		
;Mierdi
;		movfw	K_ENABLED
;		movwf	TXREG			;Transmito los cambios por el Puerto Serie
;		call	LoopMierdi
;		goto	SoloPorAhora
;LoopMierdi
;		bsf		STATUS,RP0
;		btfss	TXSTA,TRMT
;		goto	LoopMierdi
;		bcf		STATUS,RP0		;Vuelvo al viejo y querido Banco de memoria 0
;		return

;Tengo un fdespelote con el KOMBO_NUM tengo que hacer algo para que tome bien las teclas

;Datos de los Kombos
;1º Byte Tecla que activa el Kombo ejemplo: 0xF5 = tecla arriba
;2º Byte Tipo de Kombo, Algunas opciones serían: Activarse al presionar y descativarse al soltar una tecla
;												 Activarse al presionar y desactivarse al volver a presionar
;												 Activarse cuando todas las teclas están soltadas
;Para lograr esto último deberíamos incluir una rutina que mantenga unas Flags que se activen con la presion
;De una tecla y se desactiven cuando son soltadas, experimentalmente compruebo que el teclado soporta máximo
;5 teclas presionadas, no genera una sexta, pero lo veo complicado.
;3º Byte Longitud del Kombo, Muestra de cuantos bytes consta el Kombo hasta un máximo de 29 Bytes
;Bytes de Datos, van en conjunto de a dos, el primero asociado a la tecla y el segundo al tiempo entre teclas
;Byte Tecla: Solo utilizamos los 7 primeros bytes para referenciar la tecla el MSB es utilizado para Indicar
;			 Una tecla extendida, ejemplo 0x75 = tecla arriba, si fuera 0xF5 indicaría la tecla extendida
;			 0xE0 y luego la tecla arriba 0x75
;Byte Tiempo: Similar al anterior los 7 primeros bits indican el tiempo entre tecla y tecla
;			  Podemos indicar desde 1 hasta 127, trataremos de darle el significado 1 = 10ms, 127 = 1,27 seg.
;			  El MSB indica que la tecla está siendo soltada, y se transmitirá el break Code 0xF0 previo a
;			  enviar la tecla correspondiente.
EE		CODE	0x2100
;Kombo 1
		DE	0x75, 0xFF, 0x06, 0x75, 0x89, 0x29, 0x03, 0x29, 0x83, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
		DE	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
;Kombo 2
		DE	0x6B, 0xFF, 0x08, 0x6B, 0x83, 0x6B, 0x03, 0x29, 0x03, 0x29, 0x83, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
		DE	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
;Kombo 3
		DE	0x74, 0xFF, 0x08, 0x74, 0x83, 0x74, 0x03, 0x29, 0x03, 0x29, 0x83, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
		DE	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF

		end						;Fin del Programa

