;разьем платы:
;1- +12V, 2- GND
;3- INP1,GP3	no_use	;3к MCLR на +5V
;4- IO2, GP0	(OUT) HCS Vdd line
;5- IO3, GP1	(IN/OUT) Data (PWM) for Programming HCS
;6- IO4, GP2	(OUT)	Clock (S2) for Programming HCS
;7- IO5, GP4	(OUT) Program/failure led indicator (активный "1")
;8- IO6, GP5	(IN) Programming Key (подтяжка на плюс)

;===========================================================================
; MICROCHIP KEELOQ HCS200 - HCS300 - HCS301 STANDALONE PROGRAMMER
;===========================================================================

; THIS STANDALONE PROGRAMMER APPLY THE NORMAL LEARN SCHEME TO GENERATE THE
; ENCRYPTION KEY STARTING FROM THE MANUFACTURER CODE AND THE SERIAL NUMBER.
; THE SERIAL NUMBER IS INCREMENTED EVERY TIME A HCS PROGRAMMING HAPPEN
; AND IS STORED IN THE INTERNAL DATA EEPROM OF THE PIC16F84A
;
; THE HCS MANUFACTURER CODE AND THE CONFIGURATION WORD CAN BE CHANGED
; IN THE SECTION BELOW NAMED "MODIFYABLE PROGRAMMING DEFINE"

	LIST	P=PIC12F675
	INCLUDE P12F675.INC
	__FUSES _CP_ON & _BODEN_ON & _MCLRE_OFF & _PWRTE_ON & _WDT_ON & _INTRC_OSC_NOCLKOUT & H'1FFF'
	__idlocs 0X0000	;""

;**********************************************************
;Карта eeprom:
		org	0x2100
ManufCode		equ	$-0x2100					;мануфактурный код: 0123456789ABCDEF
			de	0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01

SerialNumber		equ	$-0x2100					;серийный номер, инкрементируется при каждой записи чипа
			de	0x01, 0x00, 0x00, 0x00
;**********************************************************

;========================================================================================
; MACROS

#DEFINE BANK0   bcf     STATUS,RP0
#DEFINE BANK1   bsf     STATUS,RP0

;========================================================================================

;========================================================================================

; GENERAL PURPOSE RAM REGISTERS

 CBLOCK	0X20

; Word clocked into HCS
                WRD_HI,	WRD_LO
; Words to be programmed into HCS (HCS MEMORY MAPPING)
                WORD0:2, WORD1:2, WORD2:2, WORD3:2
                WORD4:2, WORD5:2, WORD6:2, WORD7:2
                WORD8:2, WORD9:2, WORD10:2, WORD11:2
; Other Variable for programming HCS
                TXNUM                                   ; Number of bit clocked
                TMP_CNT                                 ; Temporary Counter
                 COUNT_HI, COUNT_LO                      ; Counter for Timing

; Generated Encryption KEY
                KEY7, KEY6, KEY5, KEY4
                KEY3, KEY2, KEY1, KEY0
; Circular Buffer used in decryption routine
                CSR4, CSR5, CSR6, CSR7
                CSR0, CSR1, CSR2, CSR3
; Counter used in decryption routine
                CNT0, CNT1
; Mask register used in decryption routine
                MASK
; Temporary Register
                TMP0, TMP1, TMP2, TMP3                  ; Temp register

 ENDC

;***********************************************************************
;неиспольз. порты - выходы в ноль.
;SET_GPx состояние выхода при инициализации
;CONF_GPx =1 вход, =0 выход
;
#DEFINE	HCSVDD			GPIO,0	;(OUT) HCS Vdd line
#define	BitHCSVDD	1<<0
CONF_GP0	EQU		0<<0	;
SET_GP0		EQU		0<<0	;
;
#DEFINE	DATA			GPIO,1	;(IN/OUT) Data (PWM) for Programming HCS
#define	BitDATA		1<<1
CONF_GP1	EQU		0<<1	;
SET_GP1		EQU		0<<1	;
;
#DEFINE	CLK	 		GPIO,2	;(OUT)	Clock (S2) for Programming HCS
#define	BitCLK		1<<2
CONF_GP2	EQU		0<<2	;
SET_GP2		EQU		0<<2	;
;
#DEFINE	GP3_NoUse		GPIO,3	;mclr
CONF_GP3	EQU		0<<3
SET_GP3		EQU		0<<3
;
#DEFINE	LED			GPIO,4	;(OUT) Program/failure led indicator (активный "1")
CONF_GP4	EQU		0<<4
SET_GP4		EQU		0<<4
;
#DEFINE	PROG			GPIO,5	;(IN) Programming Key (подтяжка на плюс)
CONF_GP5	EQU		1<<5	;
SET_GP5		EQU		0<<5	;
;***********************************************************************

;========================================================================================
; **************  DECRYPTION REGISTER RE-MAPPINGS *******************
; NOTE : INDIRECT ADDRESSING USED, DO NOT CHANGE REGISTER ASSIGNMENT 
; ******************************************************************
; 32 BIT HOPCODE BUFFER

#DEFINE HOP1    CSR0		
#DEFINE HOP2    CSR1
#DEFINE HOP3    CSR2
#DEFINE HOP4    CSR3

; 28 BIT SERIAL NUMBER

SER_3   EQU     CSR7                    ; LSB
SER_2   EQU     CSR6
SER_1   EQU     CSR5
SER_0   EQU     CSR4                    ; MSB

;========================================================================================
; MODIFYABLE PROGRAMMING DEFINE
;========================================================================================

#DEFINE KEY_METHOD 1            ; MUST BE 1 IF NORMAL KEY GENERATION METHOD TO BE USED
                                ; MUST BE 0 IF SIMPLE KEY GENERATION METHOD TO BE USED
                                ; (ENCRYPTION KEY= MANUFACTURER KEY)

#DEFINE HCS30X  1               ; MUST BE 1 IF PROGRAMMING HCS300-301,
                                ; MUST BE 0 IF PROGRAMMING HCS200

#DEFINE SYNC_COUNT    0X0000          ; SYNCRONOUS COUNTER

#DEFINE SEED_0  0x0000          ; 2 WORD SEED VALUE
#DEFINE SEED_1  0x0000  
#DEFINE ENV_KEY 0x0000          ; ENVELOPE KEY                  ( NOT USED FOR HCS200)

#DEFINE AUTOFF  1               ; AUTO SHUT OFF TIMER           ( NOT USED FOR HCS200)

#DEFINE DISC70  0x00            ; DISCRIMINATION BIT7-BIT0
#DEFINE DISC8   0               ; DISCRIMINATION BIT8
#DEFINE DISC9   0               ; DISCRIMINATION BIT9
#DEFINE OVR0    0               ; OVERFLOW BIT0                 (DISC10 for HCS200)
#DEFINE OVR1    0               ; OVERFLOW BIT1                 (DISC11 for HCS200)
#DEFINE VLOW    1               ; LOW VOLTAGE TRIP POINT SELECT BIT (1=High voltage)
#DEFINE BSL0    0               ; BAUD RATE SELECT BIT0
#DEFINE BSL1    0               ; BAUD RATE SELECT BIT1         (RESERVED for HCS200)
#DEFINE EENC    0               ; ENVELOPE ENCRYPTION SELECT    (RESERVED for HCS200)

#DEFINE DISEQSN	0               ; IF DISEQSN=1 SET DISCRIMINANT EQUAL TO SERNUM BIT10-0
                                ; IF DISEQSN=0 SET DISCRIMINANT AS DEFINED ABOVE

;========================================================================================
; OTHER EQUATE
;========================================================================================

#DEFINE NUM_WRD .12             ; NUMBER OF WORD TO PROGRAM INTO HCS
#DEFINE RES     0X0000          ; RESERVED WORD

#DEFINE CONF_HI ((EENC<<7)|(BSL1<<6)|(BSL1<<5)|(VLOW<<4)|(OVR1<<3)|(OVR0<<2)|(DISC9<<1)|DISC8)

; ****** HCS TIME PROGRAMMING EQUATE ********
#DEFINE Tps     .4              ; PROGRAM MODE SETUP TIME 4mS   (3,5mS min, 4,5 max)
#DEFINE Tph1    .4              ; HOLD TIME 1             4mS   (3,5mS min)
#DEFINE Tph2    .19             ; HOLD TIME 2             62uS  (50uS min)
#DEFINE Tpbw    .3              ; BULK WRITE TIME         3mS   (2,2mS min)
#DEFINE Tclkh   .10             ; CLOCK HIGH TIME         35uS  (25uS min)
#DEFINE Tclkl   .10             ; CLOCK LOW TIME          35uS  (25uS min)
#DEFINE Twc     .40             ; PROGRAM CYCLE TIME      40mS  (36mS min)


; NOTE: FOR mS TIME DELAY USE WAIT_WMSEC SUBROUTINE ( W * 1mSec )
;       FOR uS TIME DELAY USE WAIT_uS SUBROUTINE ( 5 + Txxx*3 uS )


;========================================================================================
;========================================================================================

;========================================================================================
; FUNCTION     : RESET ()	      			
; DESCRIPTION  : PROGRAM RESET ROUTINE
;========================================================================================

        ORG     0x00
RESET_VECTOR
        goto    START

;========================================================================================
; FUNCTION     : ISR_VECTOR ()	      			
; DESCRIPTION  : INTERRUPT SERVICE ROUTINE VECTOR
;========================================================================================

        ORG     0x04
ISR_VECTOR
                retfie

;========================================================================================







;========================================================================================
; FUNCTION     	: WAIT_uS ()	      			
; DESCRIPTION  	: WAIT 5+W*3 MICROSECOND SUBROUTINE
;========================================================================================

WAIT_uS         movwf	COUNT_LO
WAIT_uS_A       decfsz	COUNT_LO, F
		goto	WAIT_uS_A
		return

;========================================================================================
; FUNCTION     	: DEBOUNCE - WAIT_16MSEC - WAIT_WMSEC ()	      			
; DESCRIPTION  	: WAIT 16mSec or W mSec SUBROUTINE 
;========================================================================================

DEBOUNCE
WAIT_16MSEC     movlw	.16
WAIT_WMSEC      movwf	COUNT_HI
WAITSET         movlw	.250
		movwf	COUNT_LO
WAITLOOP        clrwdt
		decfsz	COUNT_LO,F
		goto	WAITLOOP
		decfsz	COUNT_HI,F
		goto	WAITSET
		return

;========================================================================================
; FUNCTION     	: BUTTON RELEASE ()	      			
; DESCRIPTION  	: WAIT FOR BUTTON RELEASE 
;========================================================================================

BUTTON_RELEASE  clrwdt
		btfss	PROG
		goto	BUTTON_RELEASE
		call	DEBOUNCE
		return

;========================================================================================
; FUNCTION     	: READ_SN ()	      			
; DESCRIPTION  	: READ LAST SERIAL NUMBER STORED IN THE EEPROM DATA,
;		  AND INCREMENT IT INTO NEW SER_x
;========================================================================================

READ_SN
	movlw	SerialNumber
	call	MovEeadrW
	call	RdEepr_IncEeadr
        movwf	SER_3
	call	RdEepr_IncEeadr
        movwf	SER_2
	call	RdEepr_IncEeadr
        movwf	SER_1
	call	RdEepr_IncEeadr
        movwf	SER_0
READ_SN_X       return

;========================================================================================
; FUNCTION     	: WRITE_SN ()	      			
; DESCRIPTION  	: SAVE INTO EEPROM DATA THE LAST PROGRAMMED SERIAL
;               : NUMBER
;========================================================================================
;WRITE_SN

 errorlevel	-302	;Turn off banking message
			;known tested (good) code
MovEeadrW
	BSF	STATUS,RP0
	MOVWF	EEADR
	BCF	STATUS,RP0
	RETURN

WrEepr_IncEeadr
	BSF	STATUS,RP0
	MOVWF	EEDATA
	BSF	EECON1,WREN ;разрешить запись

	movlw	55H
	movwf	EECON2
	movlw	0AAH
	movwf	EECON2
	bsf	EECON1,WR
;
wrp1_1	CLRWDT
	BTFSC	EECON1,WR	; ожидание
	GOTO	wrp1_1		;конца записи
	BCF	EECON1,WREN ;запретить запись

VERIFY_WRITE
		movf	EEDATA, W
		bsf	EECON1, RD		; do a read
		clrwdt
		btfsc	EECON1, RD		; Read done ?
		goto	$-2

		xorwf	EEDATA, W
		BNZ	EE_ERR			; EEPROM WRITE ERROR

	INCF	EEADR,F		;продвинуть указатель адреса
	BCF	STATUS,RP0
	RETURN

RdEepr_IncEeadr		    ;EEADR-адрес
	BSF	STATUS,RP0
	BSF	EECON1,RD
	MOVF	EEDATA,W
	INCF	EEADR,F		;продвинуть указатель адреса
	BCF	STATUS,RP0
	RETURN

 errorlevel	+302	;Enable banking message
			;untested code
;========================================================================================
; FUNCTION     	: MEM_MAP ()	      			
; DESCRIPTION  	: PREPARE THE WORDS TO BE PROGRAMMED INTO HCS
;========================================================================================

MAP_SET         movlw	WORD0
		movwf	FSR
WORD_0                                          ; ENCRYPTION KEY (4 WORD)
WORD_0_LO       movf	KEY0,W
		movwf	INDF
		incf	FSR, F
WORD_0_HI       movf	KEY1,W
		movwf	INDF
		incf	FSR, F
WORD_1
WORD_1_LO       movf	KEY2,W
		movwf	INDF
		incf	FSR, F
WORD_1_HI       movf	KEY3,W
		movwf	INDF
		incf	FSR, F
WORD_2
WORD_2_LO       movf	KEY4,W
		movwf	INDF
		incf	FSR, F
WORD_2_HI       movf	KEY5,W
		movwf	INDF
		incf	FSR, F
WORD_3
WORD_3_LO       movf	KEY6,W
		movwf	INDF
		incf	FSR, F
WORD_3_HI       movf	KEY7,W
		movwf	INDF
		incf	FSR, F
WORD_4                                          ; SYNC_COUNT COUNTER (1 WORD)
WORD_4_LO       movlw	LOW(SYNC_COUNT)
		movwf	INDF
		incf	FSR, F
WORD_4_HI       movlw	HIGH(SYNC_COUNT)
		movwf	INDF
		incf	FSR, F
WORD_5                                          ; RESERVED (1 WORD)
WORD_5_LO       movlw	LOW(RES)
		movwf	INDF
		incf	FSR, F
WORD_5_HI       movlw	HIGH(RES)
		movwf	INDF
		incf	FSR, F
WORD_6                                          ; SERIAL NUMBER (2 WORD)
WORD_6_LO       movf	SER_3, W                ; LSByte
		movwf	INDF
		incf	FSR, F
WORD_6_HI       movf	SER_2, W
		movwf	INDF
		incf	FSR, F
WORD_7
WORD_7_LO       movf	SER_1, W
		movwf	INDF
		incf	FSR, F
WORD_7_HI       movf	SER_0, W                ; MSByte
		andlw	B'00001111'
		iorlw	(AUTOFF<<7)             ; SET THE AUTO SHUT-OFF TIMER
		movwf	INDF			
		incf	FSR, F
WORD_8                                          ; SEED VALUE ( 2 WORD)
WORD_8_LO       movlw	LOW(SEED_0)
		movwf	INDF
		incf	FSR, F
WORD_8_HI       movlw	HIGH(SEED_0)
		movwf	INDF
		incf	FSR, F
WORD_9
WORD_9_LO       movlw	LOW(SEED_1)
		movwf	INDF
		incf	FSR, F
WORD_9_HI       movlw	HIGH(SEED_1)
		movwf	INDF
		incf	FSR, F
WORD_10                                         ; ENVELOPE KEY (1 WORD)
                                                ; (RESERVED FOR HCS200 SET TO 0x0000)
WORD_10_LO      movlw	(LOW(ENV_KEY) * HCS30X)
		movwf	INDF
		incf	FSR, F
WORD_10_HI      movlw	(HIGH(ENV_KEY) * HCS30X)
		movwf	INDF
		incf	FSR, F
;!!!
        if      DISEQSN==1
WORD_11_LO      movf	SER_3, W                ; CONFIGURATION WORD
		movwf	INDF                    ; LOWER BYTE=LOWEST BYTE OF SERIAL NUMBER
		incf	FSR, F
WORD_11_HI      movf	SER_2, W
		ANDLW	B'00000011'             ; MASK BIT OF SER. NUM.
		IORLW	CONF_HI                 ; MASK OTHER BIT OF CONFIG WORD
		movwf	INDF
		incf	FSR, F
        else
WORD_11_LO      movlw	DISC70	                ; Discrimination bits (10 BIT)
		movwf	INDF                    ;
		incf	FSR, F			;
WORD_11_HI      movlw	CONF_HI			;
		movwf	INDF
		incf	FSR, F
        endif

		return

;========================================================================================
; FUNCTION     	: PREPARE_WRD ()	      			
; DESCRIPTION  	: PUT IN WRD_LO & WRD_HI THE WORD TO BE CLOCKED OUT (PWM)
;========================================================================================

PREPARE_WRD     movf	INDF, W
		movwf	WRD_LO
		incf	FSR, F
		movf	INDF, W
		movwf	WRD_HI
		incf	FSR, F		
		return

;========================================================================================
; FUNCTION     	: DECRYPT ()	      			
; DESCRIPTION  	: DECRYPTS 32 BIT [HOP1:HOP4] USING [CSR0:CSR7]
;========================================================================================

DECRYPT
	        movlw   .11 +.1			; 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

        	addwf   PCL,F			; ADD THE INDEX TO THE PROGRAM COUNTER
						;  [ MUST BE IN LOWER HALF OF PAGE ]
TABLE
	        movlw   0x2E			; BITS 4:3 WERE 00
	        goto    TABLE_END		; END OF LOOKUP

        	movlw   0x74			; BITS 4:3 WERE 01
        	goto    TABLE_END		; END OF LOOKUP

        	movlw   0x5C			; BITS 4:3 WERE 10
        	goto    TABLE_END		; END OF LOOKUP

        	movlw   0x3A			; BITS 4:3 WERE 11
                                 
TABLE_END
        	andwf   MASK,F			; ISOLATE THE CORRECT BIT
        	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 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     	: CALC_KEY ()	      			
; DESCRIPTION  	: GENERATE 32 BITS ENCRYPTION KEY USING THE MANUFACTURER CODE STORED IN ROM
;========================================================================================

CALC_KEY	iorwf	SER_0,W			; PATCH 28 BIT SERIAL NUMBER
		movwf	CSR3			; ... AND COPY TO DECRYPT BUFFER
		movf	SER_1,W
		movwf	CSR2
		movf	SER_2,W
		movwf	CSR1
		movf	SER_3,W
		movwf	CSR0
CALC_KEY2	call	DECRYPT 		; DECRYPT 32 BIT USING MASTER KEY
		return

;========================================================================================
; FUNCTION     	: NORMAL_KEY_GEN ()	      			
; DESCRIPTION  	: GENERATE THE 64 BITS ENCRYPTION KEY USING THE MANUFACTURER CODE STORED IN ROM
;========================================================================================
NORMAL_KEY_GEN
		call	SIMPLE_KEY_GEN
;---------------
NORMAL_KEY_GEN_PATCH1				; DERIVE LOWER 32 BITS OF DECRYPTION KEY FROM SN
		movlw	0x20			; PATCH REQUIRED FOR HCS NORMAL ENCODER
		call	CALC_KEY
		movf	CSR3,W			; TEMPORARY STORE LOWER 32 BITS
		movwf	TMP3
		movfw	CSR2
		movwf	TMP2
		movfw	CSR1
		movwf	TMP1
		movfw	CSR0			
		movwf	TMP0
;---------------
NORMAL_KEY_GEN_PATCH2				; PATCH REQUIRED FOR HCS NORMAL ENCODER
		movlw	0x60
		call	CALC_KEY
		movfw	CSR3			; STORE UPPER 32 BITS OF DERIVED KEY 
		movwf	KEY7			; .... IN 64 BIT KEY BUFFER
		movfw	CSR2
		movwf	KEY6
		movfw	CSR1
		movwf	KEY5
		movfw	CSR0			 
		movwf	KEY4			
;---------------
NORMAL_KEY_GEN_REC
		movfw	TMP3			; RECOVER LOWER 32 BITS OF DERIVED KEY
		movwf	KEY3			; ... AND STORE IN 64 BIT KEY BUFFER
		movfw	TMP2
		movwf	KEY2
		movfw	TMP1
		movwf	KEY1
		movfw	TMP0
		movwf	KEY0
		return

;========================================================================================

;========================================================================================
; FUNCTION     	: GET KEY or SIMPLE_KEY_GEN ()	      			
; DESCRIPTION  	: ENCRYPTION KEY =  MANUFACTURER CODE STORED IN ROM
;========================================================================================
SIMPLE_KEY_GEN
	movlw	ManufCode			; COPY THE MANUFACTURER CODE INTO
	call	MovEeadrW			; ENCRYPTION KEY (BYTE)
	call	RdEepr_IncEeadr
	movwf	KEY0
	call	RdEepr_IncEeadr
	movwf	KEY1
	call	RdEepr_IncEeadr
	movwf	KEY2
	call	RdEepr_IncEeadr
	movwf	KEY3
	call	RdEepr_IncEeadr
	movwf	KEY4
	call	RdEepr_IncEeadr
	movwf	KEY5
	call	RdEepr_IncEeadr
	movwf	KEY6
	call	RdEepr_IncEeadr
	movwf	KEY7

	return
;========================================================================================

;========================================================================================
START		clrf	STATUS
		CLRF	PCLATH
		clrf	INTCON                  ; INTERRUPT DISABLED
		MOVLW	1<<CM2 | 1<<CM1 | 1<<CM0	;выкл. компаратор
		MOVWF	CMCON				;
		MOVLW	SET_GP0 | SET_GP1 | SET_GP2 | SET_GP3 | SET_GP4	| SET_GP5		;начальное значение выходов
		MOVWF	GPIO									;

		BSF	STATUS,RP0
		CALL	3FFh	;загрузить калибровочную константу RC генератора (не использую LOAD_OSCCAL, чтоб HEX файл не залезал в 3FFh)
		MOVWF	T1CON	;OSCCAL
;Tad=4mks.(Fosc/16), ANS... все как цифровые каналы
		MOVLW	1<<ADCS2 | 0<<ADCS1 | 1<<ADCS0 | 0<<ANS3 | 0<<ANS2 | 0<<ANS1 | 0<<ANS0	;
		MOVWF	ADCON0									;ANSEL
		CLRWDT
		MOVLW	1<<PS0 | 1<<PS1 | 1<<PS2 | 0<<PSA | 0<<T0SE | 0<<T0CS | 1<<NOT_GPPU
		MOVWF	OPTION_REG ^ 0X80 ;Prescaler=1:256 перед TMR0, таймер по перепаду 0/1, резисторы выключены

		MOVLW	CONF_GP0 | CONF_GP1 | CONF_GP2 | CONF_GP3 | CONF_GP4 | CONF_GP5		;конфигурация входов/выходов
		MOVWF	GPIO									;
		BCF	STATUS,RP0
		clrf	TMR0


CLEAR_RAM       movlw	0X20
		movwf	FSR
CLEAR_RAM_LOOP  clrf	INDF
		incf	FSR,F
		movlw	0x50
		xorwf	FSR,W
		skpz
		goto	CLEAR_RAM_LOOP

		bsf	LED			; LED ON PWUP
		movlw	.250			; WAIT 250Msec with LED ON
		call	WAIT_WMSEC
		bcf	LED			; LED OFF
		goto	M_LOOP

;========================================================================================
; FUNCTION     	: M_LOOP ()	      			
; DESCRIPTION  	: MAIN PROGRAM ROUTINE
;========================================================================================

M_LOOP          clrwdt				; WAIT FOR PROGRAMMING BUTTON PRESS
		btfsc	PROG
		goto	M_LOOP
		call	DEBOUNCE

;----------------------------------------------------------------------------------------
; PROGRAMMING ROUTINES
;----------------------------------------------------------------------------------------
M_KEY_GEN       call	READ_SN			; READ FROM EE SN TO BE PROGRAMMED
		clrwdt

        if      KEY_METHOD==1
		call	NORMAL_KEY_GEN
        else
		call	SIMPLE_KEY_GEN
        endif

		call	MAP_SET			; PREPARE EEPROM MEMORY MAP

;---------------				; ENTER IN PROGRAMMING MODE AND BULK ERASE
M_PROGRAMMING
M_PROG_INIT     bcf	DATA			; DATA=0
		bcf	CLK			; CLK=0
		bsf	HCSVDD			; HCS POWER ON
	BANK1
		bcf	DATA
	BANK0
		call	WAIT_16MSEC

M_PROG_SETUP    bsf	CLK			; DATA=0, CLK=1
		movlw	Tps			; WAIT Program mode Setup Time (Tps)
		call	WAIT_WMSEC

		bsf	DATA			; DATA=1, CLK=1
		movlw	Tph1			; WAIT Program Hold Time 1 (Tph1)
		call	WAIT_WMSEC

		bcf	DATA			; DATA=0, CLK=1
		movlw	Tph2			; WAIT Program Hold Time 2 (Tph2)
		call	WAIT_uS

M_PROG_BULK_ER  bcf	CLK			; DATA=0, CLK=0
		movlw	Tpbw			; WAIT Program Bulk Write Time (Tpbw)
		call	WAIT_WMSEC	

;---------------				; CLOCK INTO HCS THE WORDS TO BE PROGRAMMED 
		clrf	TMP_CNT			; NUMBER OF WORD TRASMITTED
		movlw	WORD0			; SET INDIRECT PONTER TO INIT EE MAP
		movwf	FSR

M_NEW_WORD      call	PREPARE_WRD

;---------------				; OUTPUT WORD ROTATE
		clrf	TXNUM			; NUMBER OF BIT TRASMITTED FOR EACH WORD

M_TX_BIT        bsf	CLK			; CLK=1
		clrc
		rrf	WRD_HI, F		; ROTATE BIT TO OUTPUT
		rrf	WRD_LO, F		;  into CARRY FLAG
		skpnc
		goto	M_PROG_DHI
		nop
M_PROG_DLO      bcf	DATA			; DATA=0
		goto	M_PROG_BIT
M_PROG_DHI      bsf	DATA			; DATA=1

M_PROG_BIT      movlw	Tclkh
		call	WAIT_uS			; DELAY
		bcf	CLK			; CLK=0
		movlw	Tclkl
		call	WAIT_uS			; DELAY
;---------------
M_PROG_CHK_WORD incf	TXNUM, F		; INCREMENT NUMBER OF BIT TRASMITTED
		movlw	.16			; CHECK IF END OF WORD TRASMITTED (16 BITS)
		xorwf	TXNUM, W
		skpz
		goto	M_TX_BIT		; TRASMIT NEXT BIT

;---------------				; END OUTPUT WORD
M_END_WORD      bcf	DATA			; DATA=0		
		movlw	Twc			; WAIT FOR WORD Write Cycle Time (Twc)
		call	WAIT_WMSEC

;---------------
M_CECHK_PRG_END incf	TMP_CNT, F		; INCREMENT NUMBER OF WORD PROGRAMMED
		movlw	NUM_WRD			; CHECK NUMBER OF WORD TRASMITTED
		xorwf	TMP_CNT, W
		skpz
		goto	M_NEW_WORD		; PROGRAM NEW WORD

;----------------------------------------------------------------------------------------
; VERIFY ROUTINE
;----------------------------------------------------------------------------------------
M_VERIFY
	BANK1
		bsf	DATA           ; I/O TRISTATE FOR VERIFY
	BANK0
		clrwdt
		movlw	WORD0			; SET INDIRECT POINTER TO INIT EE MAP
		movwf	FSR

		clrf	TMP_CNT			; NUMBER OF WORDS RECIVED
		clrf	TXNUM			; NUMBER OF BIT RECEIVED FOR EACH WORD
;---------------
M_VER_BITIN     clrc				; RECIVE DATA BIT FROM HCS FOR VERIFY
		btfsc	DATA			; TEST and ROTATE RECEIVED BIT INTO WORD BUFFER
		setc
		rrf	WRD_HI, F
		rrf	WRD_LO, F
		incf	TXNUM, F
		movlw	.16
		xorwf	TXNUM, W		; TEST IF RECEIVED A COMPLETE WORD
		skpz
		goto	M_VER_CLKHI
;---------------
M_VERIFY_WORD   movf	WRD_LO, W		; 16th BIT RECIVED (WORD) -> VERIFY WORD
		xorwf	INDF, W
		skpz
		goto	PROG_ERR		; WORD LOW VERIFY ERROR
		incf	FSR, F
		movf	WRD_HI, W
		xorwf	INDF, W
		skpz
		goto	PROG_ERR		; WORD HIGH VERIFY ERROR
		incf	FSR, F
		incf	TMP_CNT, F
		movlw	NUM_WRD
		xorwf	TMP_CNT, W		; TEST IF RECEIVED ALL THE WORDS PROGRAMMED
		skpnz
		goto	PROG_SUCCESS		; ALL 12 WORDS VERIFIED WITH SUCCESS
		clrf	TXNUM
;---------------
M_VER_CLKHI     bsf	CLK			; CLK=1
		movlw	Tclkh			; WAIT TIME CLOCK HIGH
		call	WAIT_uS

M_VER_CLKLO     bcf	CLK			; CLK=0
		movlw	Tclkl			; WAIT TIME CLOCK LOW
		call	WAIT_uS
		goto	M_VER_BITIN

;----------------------------------------------------------------------------------------
PROG_SUCCESS				; WRITE LAST SN PROGRAMMED INTO EEPROM DATA
	movlw	1
	addwf	SER_3,f
	btfsc	STATUS,C
	addwf	SER_2,f
	btfsc	STATUS,C
	addwf	SER_1,f
	btfsc	STATUS,C
	addwf	SER_0,f

	movlw	SerialNumber
	call	MovEeadrW
	movf	SER_3,w
	call	WrEepr_IncEeadr
	movf	SER_2,w
	call	WrEepr_IncEeadr
	movf	SER_1,w
	call	WrEepr_IncEeadr
	movf	SER_0,w
	call	WrEepr_IncEeadr

		bsf	LED			; LED ON FOR 0,4SEC
		movlw	.200
		call	WAIT_WMSEC		; DELAY
		movlw	.200
		call	WAIT_WMSEC		; DELAY
		goto	PROG_END

;----------------------------------------------------------------------------------------
; HCS PROGRAMMING ERROR
; WAIT FOR BUTTON PRESS

PROG_ERR	MOVLW	0xff ^ (BitDATA | BitCLK | BitHCSVDD)
		andwf	GPIO,f

		movlw	.20			; 20 * 0,2SEC = 4SEC LED BLINKING
		movwf	TMP_CNT
PROG_ERR_LEDON  bsf	LED			; LED ON FOR 0,1SEC
		movlw	.100
		call	WAIT_WMSEC		; DELAY

PROG_ERR_LEDOFF bcf	LED			; LED OFF FOR 0,1SEC
		movlw	.100
		call	WAIT_WMSEC		; DELAY
		decfsz	TMP_CNT,F		
		goto	PROG_ERR_LEDON

PROG_ERR_X      bcf	LED
		goto	PROG_END

;----------------------------------------------------------------------------------------
PROG_END        bcf	LED
		bcf	HCSVDD
		call	BUTTON_RELEASE
		goto	M_LOOP

;----------------------------------------------------------------------------------------
;DATA EEPROM WRITE ERROR; LED ON FOREVER
EE_ERR		BCF	STATUS,RP0
		MOVLW	0xff ^ (BitDATA | BitCLK | BitHCSVDD)
		andwf	GPIO,f

		bsf	LED			; LED ON
		clrwdt
		goto	$-1


        END


