    SUBTITL "REMOTE CONTROL"
;+-------------------------------------------------------------------------+
;¦    Программа пульта дистанционного управления на PIC12C509              ¦
;+-------------------------------------------------------------------------+
;
        INCLUDE         <P12C509.inc>
;
;    Назначение выводов
;
#define         KEY1    GPIO,0
#define         KEY2    GPIO,1
#define         KEY3    GPIO,3
#define         KEY4    GPIO,2
#define         LED     GPIO,4
#define         TX      GPIO,5

TRIS_GPIO       EQU     B'00011111'
INIT_GPIO       EQU     B'00000000'




OLD_GPIO        EQU     07H ;
NOW_GPIO        EQU     08H ;

STATE_GPIO      EQU     09H
#define         FTX            STATE_GPIO,5

OLDTMR          EQU     0AH

SYS_FLAGS       EQU     0BH
#define         MODE           SYS_FLAGS,7
#define         F_PROTECT_CMD  SYS_FLAGS,6
#define         F_CH_COD       SYS_FLAGS,5
#define         F_VALID_COD    SYS_FLAGS,4
#define         F_ERR          SYS_FLAGS,3
#define         F_TIMEOUT      SYS_FLAGS,2
#define         F_LONG_PRESS   SYS_FLAGS,1


TIMER_KEY       EQU     0CH ; Таймер антидребезга

STATE_KEY       EQU     0DH ; Состояние кнопок
#define         F_KEYPRESSED   STATE_KEY,7
#define         F_DEBOUNCE     STATE_KEY,6
#define         FKEY1          STATE_KEY,0
#define         FKEY2          STATE_KEY,1
#define         FKEY4          STATE_KEY,2
#define         FKEY3          STATE_KEY,3

VAR1            EQU     0EH
CNT_ACS         EQU     0FH ; Счетчик тактов процесса доступа

TRIS_LED        EQU     10H ;
TIMER_LEDL      EQU     11H ;
TIMER_LEDH      EQU     12H ;
CNT_LED         EQU     13H ;
MODE_LED        EQU     14H ;

ACSCOD1         EQU     15H ; Код доступа
ACSCOD2         EQU     16H ;
ACSCOD1R        EQU     17H ; Копия кода доступа в инверсном виде
ACSCOD2R        EQU     18H ;
N_CIPH          EQU     19H
ACSCOD_TEMP1    EQU     1AH
ACSCOD_TEMP2    EQU     1BH
CNT_TEMP        EQU     1CH
N_CIPH_TEMP     EQU     1DH
TIMEOUTL        EQU     1EH
TIMEOUTH        EQU     1FH


MODE_TX         EQU     30H ; Режим передачи
VAR2            EQU     30H
CNT_TX          EQU     31H ; Счетчик тактов режима передачи
TIME_TX         EQU     32H ; Таймер повтора посылки
CNT_BATCH       EQU     33H ; Счетчик посылок

SYNC1           EQU     34H ; Сихронизатор
SYNC2           EQU     35H ;

SYNC1R          EQU     38H ; Копия синхронизатора в инверсном виде
SYNC2R          EQU     39H ;
N_CIPH_R        EQU     3AH ; Копия количества цифр в коде в инверсном виде

;
;     Подготовленный код для передачи
;
TXCOD1          EQU     38H
TXCOD2          EQU     39H
TXCOD3          EQU     3AH
TXCOD4          EQU     3BH
TXCOD5          EQU     3CH
TXCOD6          EQU     3DH
TXCOD7          EQU     3EH
TXCOD8          EQU     3FH
;
;
;
;
;
;
;
;
;
        ORG     0000
BEGIN:
        MOVWF   OSCCAL
        CLRF    FSR
        MOVLW   TRIS_GPIO     ; Назначение направления портов
        MOVWF   TRIS_LED
        TRIS    GPIO            ;
        CLRF    STATE_GPIO
        MOVF    STATE_GPIO,W    ; Начальная установка сигналов
        MOVWF   GPIO            ;

        MOVLW   B'01000111'
;                 ¦¦¦¦¦¦¦¦
;                 ¦¦¦¦¦¦¦+- PS0    предварительный делитель для WDT или T0
;                 ¦¦¦¦¦¦+-- PS1     ( 256 )
;                 ¦¦¦¦¦+--- PS2
;                 ¦¦¦¦+---- PSA    1 - предварительный делитель для WDT иначе для T0
;                 ¦¦¦+----- T0SE   1 - внешнее тактирование по спаду иначе по нарастанию
;                 ¦¦+------ T0CS   1 - тактирование по внешнему входу иначе по частоте Fosc/4
;                 ¦+------- GPPU   0 - разрешение режима PULL-UP на выв GP0,GP1
;                 +-------- GPWU   0 - разрешение режима WAKE-UP на выв GP0,GP1,GP3
        OPTION
        BCF     STATUS,PA0
        GOTO    CHECK_INTEGRITY
END_CHECK_INTEGRITY:
        CLRF    MODE_TX
        BCF     FSR,5
        CLRF    STATE_KEY
        CLRF    TIMER_KEY
        CLRF    MODE_LED
        CLRF    OLD_GPIO
        COMF    OLD_GPIO
        BTFSC   STATUS,GPWUF
        GOTO    MAINCIKL
        CLRF    CNT_ACS
        CLRF    SYS_FLAGS
        GOTO    MAINCIKL

TABL_BIT:
        ANDLW   B'00000111'
        ADDWF   PCL, F
        DT      B'10000000'
        DT      B'01000000'
        DT      B'00100000'
        DT      B'00010000'
        DT      B'00001000'
        DT      B'00000100'
        DT      B'00000010'
        DT      B'00000001'
MODE1_MAP:
        ANDLW   B'00000111'
        ADDWF   PCL, F
;        верх 1
;             2
;             3
;        низ  4
;                    4 231
        DT      B'11101111'
        DT      B'11101101'
        DT      B'11111001'
        DT      B'11111010'
        DT      B'11111110'
        DT      B'11111111'
        DT      B'11111111'
        DT      B'11111111'
MODE2_MAP:
        ANDLW   B'00000111'
        ADDWF   PCL, F
;                    4 231
        DT      B'11101111'
        DT      B'11111101'
        DT      B'11111011'
        DT      B'11111110'
        DT      B'11111011'
        DT      B'11111101'
        DT      B'11101111'
        DT      B'11111111'
MODE4_MAP:
        ANDLW   B'00000011'
        ADDWF   PCL, F
;                    4 231
        DT      B'11111110'
        DT      B'11111011'
        DT      B'11111101'
        DT      B'11101111'
;+--------------------------------------------------------------------------+
;¦      Процедура перехода в SLEEP                                          ¦
;+--------------------------------------------------------------------------+
TO_SLEEP:
        BSF     FSR,5
        MOVF    MODE_TX
        BCF     FSR,5
        BTFSS   STATUS,Z
        RETURN
TO_SLEEP1:
        BTFSC   F_TIMEOUT
        RETURN
        MOVF    STATE_KEY,W
        XORLW   B'00001111'
        BTFSS   STATUS,Z
        RETURN
        BSF     FSR,5
        CLRF    MODE_TX
        COMF    SYNC1,W         ; Сохранить копию синхронизатора
        MOVWF   SYNC1R          ;
        COMF    SYNC2,W         ;
        MOVWF   SYNC2R          ;

        BCF     FSR,5           ; Сохранить копию количества цифр
        COMF    N_CIPH,W        ;   в инверсном виде
        BSF     FSR,5           ;
        MOVWF   N_CIPH_R        ;

        MOVLW   B'11111111'     ; Все выводы на вход
        TRIS    GPIO            ;
        MOVF    GPIO
        SLEEP

MAINCIKL:
;+--------------------------------------------------------------------------+
;¦      Цикл с периодом 256 мкс                                             ¦
;+--------------------------------------------------------------------------+
;
;     Опрос клавиатуры
;     Поддержка работы индикатора
;     Поддержка выдачи кода
;
        MOVF    TMR0,W
        SUBWF   OLDTMR,F
        MOVWF   OLDTMR
        BTFSC   STATUS,Z
        GOTO    MAINCIKL


        MOVF    STATE_GPIO,W    ; Установить сигналы на выводах
        MOVWF   GPIO            ;


        BTFSC   MODE
        GOTO    DO_LED
        BSF     MODE            ;
        MOVLW   TRIS_GPIO       ; Назначить направление портов на вход
        TRIS    GPIO            ;
;
;********************* Опрос клавиатуры *************************************
;
;    Обработка нажатия производиться при изменении состояния кнопок
;
        MOVF    TIMER_KEY,F       ; Кнопки не проверяются пока включен таймер
        BTFSS   STATUS,Z          ;  антидребезга
        GOTO    DO_TIMER_KEY      ;

        MOVF    GPIO,W
        MOVWF   NOW_GPIO
        XORWF   OLD_GPIO,W
        ANDLW   B'00001111'
        BTFSC   STATUS,Z
        GOTO    NOT_CHANGE_KEY
;
;       Состояние изменилось
;       Инициализироват таймер антидребезга
;
        MOVLW   .50             ; Длительность периода антидребезга 25 мс
        MOVWF   TIMER_KEY       ;
        BSF     F_DEBOUNCE
        GOTO    DO_TIMER_KEY
NOT_CHANGE_KEY:
        BTFSS   F_DEBOUNCE
        GOTO    END_CHECK_KEY
        ; Сдесь проверяется, чтобы отпускание клавиши при нажатой другой
        ;  не вызывало события F_KEYPRESSED
        MOVF    NOW_GPIO,W
        ANDLW   B'00001111'

        MOVWF   STATE_KEY
        BSF     F_KEYPRESSED
        GOTO    END_CHECK_KEY

DO_TIMER_KEY:
        DECF    TIMER_KEY
END_CHECK_KEY:
        MOVF    NOW_GPIO,W
        MOVWF   OLD_GPIO
;
;****************** Обработка команд с клавиатуры ***************************
;
        BTFSS   F_KEYPRESSED
        GOTO    END_DO_CMD
        BCF     F_KEYPRESSED
        BTFSS   FKEY1
        GOTO    SEND_CMD1
        BTFSS   FKEY2
        GOTO    SEND_CMD2
        BTFSS   FKEY3
        GOTO    SEND_CMD3
        BTFSS   FKEY4
        GOTO    SEND_CMD4
        CALL    TO_SLEEP       ;       Процедура при отпускании кнопки
END_DO_CMD:
        GOTO    DO_TX_COD
;
;****************** Поддержка работы индикатора *****************************
;
DO_LED:
        BCF     MODE
;
;       Зажечь необходимые сегменты
;
        MOVF    TRIS_LED,W     ; Определить направление выводов
        TRIS    GPIO            ;


        MOVLW   .1              ; Изменять состояние индикации
        SUBWF   TIMER_LEDL      ;  при истечении заданного времени
        BTFSS   STATUS,C        ;
        SUBWF   TIMER_LEDH      ;
        BTFSC   STATUS,C        ;
        GOTO    END_DO_LED      ;


        MOVF    MODE_LED,W
        ADDWF   PCL, F
        GOTO    MODE_LED0
        GOTO    MODE_LED1
        GOTO    MODE_LED2
        GOTO    MODE_LED3
        GOTO    MODE_LED4

MODE_LED0:
        MOVLW   TRIS_GPIO
        MOVWF   TRIS_LED
        GOTO    END_DO_LED

;
;       Движение вверх одного сегмента
;
MODE_LED1:
        MOVLW   LOW .100
        MOVWF   TIMER_LEDL
        MOVLW   HIGH .100
        MOVWF   TIMER_LEDH

        MOVF    CNT_LED,W
        CALL    MODE1_MAP
        GOTO    SET_TRIS_LED
;
;       Движение вверх всех сегментов
;
MODE_LED2:
        MOVLW   LOW .100
        MOVWF   TIMER_LEDL
        MOVLW   HIGH .100
        MOVWF   TIMER_LEDH
        MOVF    CNT_LED,W
        CALL    MODE2_MAP
        GOTO    SET_TRIS_LED
;
;       Мигание
;
MODE_LED3:
        MOVLW   B'00011111'
        XORWF   CNT_LED

        MOVLW   LOW .150
        MOVWF   TIMER_LEDL
        MOVLW   HIGH .150
        MOVWF   TIMER_LEDH
        GOTO    SET_TRIS_LED1
;
;       Движение вниз одного сегмента
;
MODE_LED4:
        MOVLW   LOW .150
        MOVWF   TIMER_LEDL
        MOVLW   HIGH .150
        MOVWF   TIMER_LEDH
        MOVF    CNT_LED,W
        CALL    MODE4_MAP
        GOTO    SET_TRIS_LED

SET_TRIS_LED:
        INCF    CNT_LED
SET_TRIS_LED1:
        IORLW   B'11100000'
        ANDLW   TRIS_GPIO
        MOVWF   TRIS_LED

END_DO_LED:


DO_TX_COD:
;
;********************* Поддержка выдачи кода ********************************
;
;
;       Формат передачи команды
;
;   преамбула          пауза     кодовая посылка
;  512 us 12 раз      8*256 us   64 импульса с периодом 3*256 us
; +--+  +--+  +-...-+         +-++-++-++-++-++-...-+                        +
; ¦  ¦  ¦  ¦  ¦     ¦         ¦ ¦¦ ¦¦ ¦¦ ¦¦ ¦¦     ¦                        ¦
;    +--+  +--+     +--...----+ ++ ++ ++ ++ ++     +----------...-----------+
;                                                     пауза между посылками
;                                                       50*256 us
        BSF     FSR,5
        MOVF    MODE_TX,W
        ANDLW   B'00001111'
        ADDWF   PCL, F
        GOTO    MODE_TX0
        GOTO    MODE_TX1
        GOTO    MODE_TX2
        GOTO    MODE_TX3
        GOTO    MODE_TX4
MODE_TX0:
        BCF     FTX
        GOTO    END_DO_TX_COD
;
;       Передача преамбулы
;
MODE_TX1:
        BSF     FTX
        BTFSS   CNT_TX,0
        BCF     FTX

        DECFSZ  CNT_TX
        GOTO    END_DO_TX_COD
        MOVLW   .8            ; Количество тактов в цикле передачи заголовка
        MOVWF   CNT_TX        ;
        INCF    MODE_TX
        GOTO    END_DO_TX_COD
;
;       Передача заголовка
;
MODE_TX2:
        BCF     FTX
        DECFSZ  CNT_TX
        GOTO    END_DO_TX_COD
        INCF    MODE_TX
        GOTO    END_DO_TX_COD
;
;       Передача кода
;
MODE_TX3:
        SWAPF   MODE_TX,W     ; Определить фазу передачи бита
        ANDLW   B'00000011'
        ADDWF   PCL, F
        GOTO    MODE_TX30
        GOTO    MODE_TX31
        GOTO    MODE_TX32
MODE_TX30:
        BSF     FTX           ; Передача начала бита
        MOVLW   B'00010000'   ;
        ADDWF   MODE_TX       ;
        GOTO    END_DO_TX_COD ;
MODE_TX31:
        MOVF    CNT_TX,W
        ANDLW   B'00111000'
        MOVWF   VAR1
        RRF     VAR1
        RRF     VAR1
        RRF     VAR1
        MOVLW   TXCOD1
        ADDWF   VAR1,W
        MOVWF   FSR
        MOVF    CNT_TX,W
        CALL    TABL_BIT
        ANDWF   INDF,W
        BSF     FTX
        BTFSC   STATUS,Z
        BCF     FTX
        MOVLW   B'00010000'   ;
        ADDWF   MODE_TX       ;
        GOTO    END_DO_TX_COD
MODE_TX32:
        BCF     FTX           ; Передача конца бита
        MOVLW   B'00001111'   ;
        ANDWF   MODE_TX       ;
        INCF    CNT_TX
        MOVLW   .64
        SUBWF   CNT_TX,W
        BTFSS   STATUS,C
        GOTO    END_DO_TX_COD
        MOVLW   .50           ; Количество тактов в цикле паузы
        MOVWF   CNT_TX        ;
        INCF    MODE_TX
        GOTO    END_DO_TX_COD
;
;       Пауза между передачами кода
;
MODE_TX4:
        BCF     FTX
        DECFSZ  CNT_TX
        GOTO    END_DO_TX_COD
        MOVLW   .24           ; Количество тактов в цикле передачи преамбулы
        MOVWF   CNT_TX        ;
        MOVLW   1             ; Режим передачи преамбулы
        MOVWF   MODE_TX

        INCF    CNT_BATCH     ; Увеличить счетчик переданных посылок
        MOVLW   .10           ; Минимальное количество посылок 10
        SUBWF   CNT_BATCH,W
        BTFSS   STATUS,C
        GOTO    END_DO_TX_COD
        ; После передачи 10 посылок можно проверить условие для перехода
        ; в SLEEP режим
        CALL    TO_SLEEP1
        BSF     FSR,5
        MOVLW   .47           ; После 2.5 секунд
        SUBWF   CNT_BATCH,W
        BTFSS   STATUS,C
        GOTO    END_DO_TX_COD
        BSF     F_LONG_PRESS
        BCF     FSR,5
        GOTO    SEND_LONG_PRESS_CMD

END_DO_TX_COD:
        BCF     FSR,5


DO_TIMEOUT:
        MOVLW   .1              ;
        SUBWF   TIMEOUTL        ;
        BTFSS   STATUS,C        ;
        SUBWF   TIMEOUTH        ;
        BTFSC   STATUS,C        ;
        GOTO    END_DO_TIMEOUT  ;
        BCF     F_TIMEOUT
        CALL    TO_SLEEP
END_DO_TIMEOUT:
        GOTO    MAINCIKL
;+--------------------------------------------------------------------------+
;¦      Конец цикла     256 мкс                                             ¦
;+--------------------------------------------------------------------------+

;
;     Процедура смены парол
;
;     1. Ввод старого кода
;        +---+   +---+
;     2. ¦ A ¦ + ¦ B ¦  одновременно
;        +---+   +---+
;     3. Новый код
;        +---+
;     4. ¦ 2 ¦
;        +---+
;     5. Новый код
;
;+--------------------------------------------------------------------------+
;¦      Процедура при нажатии кнопки 1 функция  [A]                         ¦
;+--------------------------------------------------------------------------+
SEND_CMD1:
        BTFSS   FKEY2
        GOTO    WAIT_RELEASE
SCM11:
        BTFSC   F_CH_COD
        GOTO    CHANGE_COD
        BTFSC   F_VALID_COD
        GOTO    VALID_COD
        MOVF    CNT_ACS
        BTFSC   STATUS,Z     ; Если ввод кода только начинаетс
        BCF     F_ERR        ;  то сбросить флаг ошибки
        ; Вычислить адрес соответствующего бита в коде доступа
        MOVLW   ACSCOD1
        BTFSC   CNT_ACS,3
        MOVLW   ACSCOD2
        MOVWF   FSR
        MOVF    CNT_ACS,W
        CALL    TABL_BIT     ; Получить маску соответствующего бита
        ANDWF   INDF,W



        BTFSC   FKEY1
        GOTO    SCM12
        BTFSC   STATUS,Z     ; Если бит нулевой то выставить флаг ошибки
        BSF     F_ERR        ; поскльку [A] соответствует 1
        GOTO    SCM13
SCM12:
        BTFSS   STATUS,Z     ; Если бит ненулевой то выставить флаг ошибки
        BSF     F_ERR        ; поскльку [B] соответствует 0
SCM13:
        INCF    CNT_ACS
        MOVF    N_CIPH,W
        SUBWF   CNT_ACS,W
        BTFSS   STATUS,Z
        GOTO    END_DO_CMD   ;
        CLRF    CNT_ACS
        BTFSC   F_ERR
        GOTO    INDC_ERR
        BSF     F_PROTECT_CMD
        ; Таймаут для индикации корректного ввода
INDC_OK:
        MOVLW   4
        MOVWF   MODE_LED
        CLRF    CNT_LED
SET_TIMEOUT:
        MOVLW   HIGH .3906
        MOVWF   TIMEOUTH
        MOVLW   LOW  .3906
        MOVWF   TIMEOUTL
        BSF     F_TIMEOUT
        CLRF    TIMER_LEDL
        CLRF    TIMER_LEDH
        GOTO    END_DO_CMD
INDC_ERR:
        MOVLW   3
        MOVWF   MODE_LED
        CLRF    CNT_LED
        GOTO    SET_TIMEOUT

CHANGE_COD:
        MOVLW   ACSCOD_TEMP1
        BTFSC   CNT_ACS,3
        MOVLW   ACSCOD_TEMP2
        MOVWF   FSR
        MOVF    CNT_ACS,W
        CALL    TABL_BIT     ; Получить маску соответствующего бита

        INCF    CNT_ACS
        BTFSC   FKEY1
        GOTO    CHC1
        IORWF   INDF
        GOTO    CHC2
CHC1:
        XORLW   B'11111111'
        ANDWF   INDF
CHC2:
        GOTO    END_DO_CMD

VALID_COD:
        MOVF    CNT_ACS
        BTFSC   STATUS,Z     ; Если ввод кода только начинаетс
        BCF     F_ERR        ;  то сбросить флаг ошибки
        ; Вычислить адрес соответствующего бита в коде доступа
        MOVLW   ACSCOD_TEMP1
        BTFSC   CNT_ACS,3
        MOVLW   ACSCOD_TEMP2
        MOVWF   FSR
        MOVF    CNT_ACS,W
        CALL    TABL_BIT     ; Получить маску соответствующего бита
        ANDWF   INDF,W

        BTFSC   FKEY1
        GOTO    VAC12
        BTFSC   STATUS,Z     ; Если бит нулевой то выставить флаг ошибки
        BSF     F_ERR        ; поскльку [A] соответствует 1
        GOTO    VAC13
VAC12:
        BTFSS   STATUS,Z     ; Если бит ненулевой то выставить флаг ошибки
        BSF     F_ERR        ; поскльку [B] соответствует 0
VAC13:
        INCF    CNT_ACS
        MOVF    N_CIPH_TEMP,W
        SUBWF   CNT_ACS,W
        BTFSS   STATUS,Z
        GOTO    END_DO_CMD   ;
        CLRF    CNT_ACS
        BTFSC   F_ERR
        GOTO    INDC_ERR
        BTFSS   F_PROTECT_CMD      ; Если доступ был разрешен то сменить код
        GOTO    INDC_OK
        MOVF    ACSCOD_TEMP1,W
        MOVWF   ACSCOD1
        COMF    ACSCOD1,W
        MOVWF   ACSCOD1R
        MOVF    ACSCOD_TEMP2,W
        MOVWF   ACSCOD2
        COMF    ACSCOD2,W
        MOVWF   ACSCOD2R
        MOVF    N_CIPH_TEMP,W
        MOVWF   N_CIPH
        GOTO    INDC_OK

;+--------------------------------------------------------------------------+
;¦      Процедура при нажатии кнопки 2  функция  [B]                        ¦
;+--------------------------------------------------------------------------+
SEND_CMD2:
        GOTO    SCM11

;+--------------------------------------------------------------------------+
;¦      Процедура при нажатии кнопки 3  функция  [1]                        ¦
;+--------------------------------------------------------------------------+
SEND_CMD3:
        MOVLW   1
        MOVWF   MODE_LED
        CLRF    CNT_LED
        GOTO    SCM4

;+--------------------------------------------------------------------------+
;¦      Процедура при нажатии кнопки 4  функция  [2]                        ¦
;+--------------------------------------------------------------------------+
SEND_CMD4:
        BTFSC   F_CH_COD
        GOTO    CHANGE_COD_END
        BTFSC   F_VALID_COD
        GOTO    BREAK_ACS
        MOVF    CNT_ACS
        BTFSS   STATUS,Z
        GOTO    BREAK_ACS

        MOVLW   2
        MOVWF   MODE_LED
        CLRF    CNT_LED
SCM4:
        BCF     F_LONG_PRESS
SEND_LONG_PRESS_CMD:
        CLRF    TIMER_LEDL
        CLRF    TIMER_LEDH
        BSF     STATUS,PA0
        CALL    ENCRIPT_CMD
        BCF     STATUS,PA0
        BSF     FSR,5
        MOVLW   .24           ; Количество тактов в цикле передачи преамбулы
        MOVWF   CNT_TX        ;
        MOVLW   1             ; Режим передачи преамбулы
        MOVWF   MODE_TX
        CLRF    CNT_BATCH
        BCF     FSR,5
        BCF     F_PROTECT_CMD     ; Снять разрешение на выдачу команд
        GOTO    END_DO_CMD
BREAK_ACS:
        CLRF    CNT_ACS
        CLRF    SYS_FLAGS
        GOTO    INDC_ERR
CHANGE_COD_END:
        MOVF    CNT_ACS,W
        MOVWF   N_CIPH_TEMP
        BSF     F_VALID_COD
        BCF     F_CH_COD
        CLRF    CNT_ACS
        GOTO    INDC_OK
;+--------------------------------------------------------------------------+
;¦      Процедура входа в режим смены кода                                  ¦
;+--------------------------------------------------------------------------+
WAIT_RELEASE:
        BCF     F_VALID_COD
        BSF     F_CH_COD
        CLRF    CNT_ACS
        ;  Ожидать отпускания всех кнопок
        ;
WAR2:
        COMF    GPIO,W
        ANDLW   B'00001111'
        BTFSS   STATUS,Z
        GOTO    WAR2
        ;  Пауза на антидребезг 20 мс
        ;
WAR3:
        MOVLW   .26
        MOVWF   TIMEOUTH
        CLRF    TIMEOUTL
WAR4:
        DECFSZ  TIMEOUTL
        GOTO    WAR4
        DECFSZ  TIMEOUTH
        GOTO    WAR4

        COMF    GPIO,W
        ANDLW   B'00001111'
        BTFSS   STATUS,Z
        GOTO    WAR3
        GOTO    INDC_OK

;+--------------------------------------------------------------------------+
;¦      Проверка целостности критических данных                             ¦
;+--------------------------------------------------------------------------+
CHECK_INTEGRITY:
        COMF    N_CIPH,W          ; Проверить сохранность величины
        BSF     FSR,5             ;  количества цифр в коде
        SUBWF   N_CIPH_R,W        ;
        BCF     FSR,5             ;
        BTFSS   STATUS,Z          ;
        GOTO    CRASH             ;

        COMF    ACSCOD1,W         ; Сверить первый байт кода доступа с его
        SUBWF   ACSCOD1R,W        ;  копией
        BTFSS   STATUS,Z          ;
        GOTO    CRASH             ;
        COMF    ACSCOD2,W         ; Сверить второй байт кода доступа
        SUBWF   ACSCOD2R,W        ;
        BTFSS   STATUS,Z          ; Если код поврежден то установить
        GOTO    CRASH             ;  предопределенный код
        MOVF    ACSCOD1
        BTFSS   STATUS,Z     ; Если код доступа содержит одни 0
        GOTO    CHI1         ;  то автоматически разрешаетс
        MOVF    ACSCOD2      ;  доступ
        BTFSS   STATUS,Z     ;
        GOTO    CHI1         ;
        BSF     F_PROTECT_CMD    ;  Доступ разрешается флагом F_PROTECT_CMD
CHI1:
        BSF     FSR,5         ; Bank 1
        COMF    SYNC1,W       ; Проверить целостность
        SUBWF   SYNC1R,W      ;  счетчика синхронизатора
        BTFSS   STATUS,Z      ;
        GOTO    CRASH         ;
        COMF    SYNC2,W       ;
        SUBWF   SYNC2R,W      ;
        BTFSS   STATUS,Z      ;
        GOTO    CRASH
        GOTO    END_CHECK_INTEGRITY

CRASH:
        BCF     FSR,5
        MOVLW   B'10110011'  ; Код доступа по умолчанию
        MOVWF   ACSCOD1      ; '1011001110001111'
                             ; A-B-A-A-B-B-A-A-A-B-B-B-A-A-A-A
        XORLW   B'11111111'  ; Копии сохраняются в инверсном виде
        MOVWF   ACSCOD1R     ;
        MOVLW   B'10001111'
        MOVWF   ACSCOD2
        XORLW   B'11111111'
        MOVWF   ACSCOD2R
        MOVLW   .16
        MOVWF   N_CIPH

        BSF     FSR,5
        CLRF    SYNC1         ; Сбросить счетчик в 0 если данные счетчика
        CLRF    SYNC2         ;  повреждены
        MOVLW   B'11111111'   ;
        MOVWF   SYNC1R        ;
        MOVWF   SYNC2R        ;
        BCF     STATUS,GPWUF  ; Установить в 0 флаг указывающий
                              ; на способ сброса процессора
                              ; (Разрушительный сброс)

        GOTO    END_CHECK_INTEGRITY




        ORG     200H
;+--------------------------------------------------------------------------+
;¦      Номер прибора                                                       ¦
;+--------------------------------------------------------------------------+
DEV_NUMBER:
        ANDLW   B'00000011'
        ADDWF   PCL, F
        DT      12H
        DT      34H
        DT      56H
        DT      78H
;+--------------------------------------------------------------------------+
;¦      Процедура шифрации команды                                          ¦
;+--------------------------------------------------------------------------+
ENCRIPT_CMD:
        BSF     FSR,5
;
;
;  Состав кодовой посылки
; +-------------------------------------------+
; ¦ Переменная часть 32 ¦ Постоянная часть 32 ¦
; +-------------------------------------------+
; ********************************************************************
;  Переменная часть - зашифрованная последовательность бит
; +----------------------------------------------------+
; ¦ Функция 4 ¦ Контрольное слово 12 ¦ Синхронизатор 16¦
; +----------------------------------------------------+
;  Контрольное слово - последнии 12 бит серийного номера
;
;  Постоянная часть
; +-------------------------------+
; ¦ Серийный номер 28 ¦ Функция 4 ¦
; +-------------------------------+
;
;  Функци
; +----------------------------------------------------------------------------+
; ¦ Бит защищенной команды ¦ Бит кнопки 1¦ Бит кнопки 2 ¦ Флаг долгого нажатия ¦
; +----------------------------------------------------------------------------+
;
;
;  Получение переменной части
; +-----------------+    +------------------------------------+
; ¦  Скремблер 32   ¦ <- ¦ Незашифрованная переменная часть 32¦
; +-----------------+    +------------------------------------+
;      XOR
; +-----------------+
; ¦    Ключ  32     ¦
; +-----------------+
;   \/ \/ \/ \/ \/
; +-------------------------------------+
; ¦ Зашифрованная переменная часть 32   ¦
; +-------------------------------------+
;
;  Функция скремблера  X^32+X^21+X^1+1
;                               +---+                  +---+
;     +------------------------>¦== +----------------->¦== ¦ --+
;     ¦                      +->¦   ¦               +->¦   ¦   ¦
;     ¦                      ¦  +---+               ¦  +---+   ¦
;     ¦                      +----+                 +---+      ¦
;     ¦                           ¦                     ¦      ¦
;     ¦ +--------------------- ------   ------------------+    ¦
;     +-¦ 32¦ 31¦ 30¦ 29¦ 28¦...¦ 21¦ ... ¦ 4 ¦ 3 ¦ 2 ¦ 1 ¦<---+
;       +--------------------- ------   ------------------+
;
;
;  Шифрация производится в ячейках TXCOD1..TXCOD4
;

        ; Сформировать функцию для переменной части

        CLRF    TXCOD1
        BTFSC   F_LONG_PRESS  ; Бит долгого нажати
        BSF     TXCOD1,4  ;
        BTFSC   FKEY4     ; Бит кнопки 2
        BSF     TXCOD1,5  ;
        BTFSC   FKEY3     ; Бит кнопки 1
        BSF     TXCOD1,6  ;
        BTFSC   F_PROTECT_CMD ; Бит защищенной команды
        BSF     TXCOD1,7  ;

        ; Сформировать контрольное слово из порядкового номера

        MOVLW   0
        CALL    DEV_NUMBER
        ANDLW   B'00001111'
        IORWF   TXCOD1,F
        MOVLW   1
        CALL    DEV_NUMBER
        MOVWF   TXCOD2

        ; Записать синхронизатор
        MOVF    SYNC2,W
        MOVWF   TXCOD3
        MOVF    SYNC1,W
        MOVWF   TXCOD4

        ; Инициализировать цикл шифрации
        MOVLW   .32     ; Количество повторений цикла 32 равно длине ключа
        MOVWF   CNT_TX  ;


        ; Цикл шифрации
SCRAMBL_CIKL:
        ;
        ; Сформировать бит обратной связи
        ;
        BSF     STATUS,C
        BTFSS   TXCOD1,7   ; Обработать бит 32
        BCF     STATUS,C

        BTFSS   STATUS,C   ; Обработать бит 21
        GOTO    ENC1
        BTFSC   TXCOD2,4
        BCF     STATUS,C
        GOTO    ENC2
ENC1:   BTFSC   TXCOD2,4
        BSF     STATUS,C
ENC2:
        BTFSS   STATUS,C   ; Обработать бит 1
        GOTO    ENC5
        BTFSC   TXCOD4,0
        BCF     STATUS,C
        GOTO    ENC6
ENC5:   BTFSC   TXCOD4,0
        BSF     STATUS,C
ENC6:
                             ; Сдвиг шифруемой цепочки
        RLF     TXCOD4
        RLF     TXCOD3
        RLF     TXCOD2
        RLF     TXCOD1

        DECFSZ  CNT_TX
        GOTO    SCRAMBL_CIKL
;
;       Сформировать ключ
;
        MOVLW   0
        CALL    DEV_NUMBER
        MOVWF   TXCOD5
        MOVLW   1
        CALL    DEV_NUMBER
        MOVWF   TXCOD6
        MOVLW   2
        CALL    DEV_NUMBER
        MOVWF   TXCOD7
        MOVLW   3
        CALL    DEV_NUMBER
        ANDLW   B'11110000'
        MOVWF   TXCOD8

        ; Инициализировать цикл формирования ключа

        MOVLW   .32     ; Количество повторений цикла 32 равно длине ключа
        MOVWF   CNT_TX  ;

KEY_CIKL:
        ;
        ; Сформировать бит обратной связи
        ;
        BSF     STATUS,C
        BTFSS   TXCOD5,7   ; Обработать бит 32
        BCF     STATUS,C

        BTFSS   STATUS,C   ; Обработать бит 21
        GOTO    KCI1
        BTFSC   TXCOD6,4
        BCF     STATUS,C
        GOTO    KCI2
KCI1:   BTFSC   TXCOD6,4
        BSF     STATUS,C
KCI2:
        BTFSS   STATUS,C   ; Обработать бит 1
        GOTO    KCI5
        BTFSC   TXCOD8,0
        BCF     STATUS,C
        GOTO    KCI6
KCI5:   BTFSC   TXCOD8,0
        BSF     STATUS,C
KCI6:
                             ; Сдвиг шифруемой цепочки
        RLF     TXCOD8
        RLF     TXCOD7
        RLF     TXCOD6
        RLF     TXCOD5

        DECFSZ  CNT_TX
        GOTO    KEY_CIKL
        ;
        ; Операция XOR шифрованной переменной части с ключом
        ;
        MOVF    TXCOD5,W
        XORWF   TXCOD1
        MOVF    TXCOD6,W
        XORWF   TXCOD2
        MOVF    TXCOD7,W
        XORWF   TXCOD3
        MOVF    TXCOD8,W
        XORWF   TXCOD4
        ;
        ; Записать порядковый номер прибора
        ;
        MOVLW   0
        CALL    DEV_NUMBER
        MOVWF   TXCOD5
        MOVLW   1
        CALL    DEV_NUMBER
        MOVWF   TXCOD6
        MOVLW   2
        CALL    DEV_NUMBER
        MOVWF   TXCOD7
        MOVLW   3
        CALL    DEV_NUMBER
        ANDLW   B'11110000'
        MOVWF   TXCOD8

        ; Сформировать функцию для постоянной части

        BTFSC   F_LONG_PRESS  ; Бит долгого нажати
        BSF     TXCOD8,0  ;
        BTFSC   FKEY4     ; Бит кнопки 2
        BSF     TXCOD8,1  ;
        BTFSC   FKEY3     ; Бит кнопки 1
        BSF     TXCOD8,2  ;
        BTFSC   F_PROTECT_CMD ; Бит защищенной команды
        BSF     TXCOD8,3  ;
;
;       Увеличить значение синхронизатора
;
        MOVLW   .1
        ADDWF   SYNC1
        BTFSC   STATUS,C
        INCF    SYNC2

        BCF     FSR,5
        RETURN

       