$include (8051.mcu)
$include (macroses.mcu)

; ВЫВОДЫ
COL_HDD           EQU  P3_4     ; выводы анодов светодиодов
COL_NET           EQU  P3_7
COL_RESERVE       EQU  P3_5

IN_HDD            EQU  P3_0     ; источники сигналов активности
IN_NET            EQU  P3_2
IN_RESERVE        EQU  P3_1
OUT_NET_START     EQU  P3_3     ; при запуске надо секунду удерживать тут высокий уровень

; КОНСТАНТЫ
STACK             EQU  056h               ; местоположение стека
TIMER_HI          EQU  HIGH(NOT(1000-1))  ; константы иннициализации таймера опроса состояния датчиков
TIMER_LO          EQU  LOW(NOT(1000-1))

; ПЕРЕМЕННЫЕ
VAL_HDD           EQU  10       ; показания индикаторов (0..8)
VAL_NET           EQU  11
VAL_RESERVE       EQU  12

COUNT_HDD         EQU  14       ; счетчики обращений (сначала младший байт, затем - старший)
COUNT_HDD_HI      EQU  15
COUNT_NET         EQU  16
COUNT_NET_HI      EQU  17
COUNT_RESERVE     EQU  18
COUNT_RESERVE_HI  EQU  19

STATE_HDD         EQU  20       ; текущее состояние (FF-активен, 0-пассивен)
STATE_NET         EQU  21
STATE_RESERVE     EQU  22

STATE_COUNT_HDD       EQU  23       ; счетчик нахождения в текущем состоянии
STATE_COUNT_HDD_HI    EQU  24
STATE_COUNT_NET       EQU  25
STATE_COUNT_RESERVE   EQU  26






CSEG AT 0

; ТОЧКА ВХОДА В ПРОГРАММУ
	ljmp start

ORG    0Bh
; ВЕКТОР ПРЕРЫВАНИЯ ТАЙМЕРА T/C0
    ljmp    interrupt_handler_tc0

; НАЧАЛО ПРОГРАММЫ
ORG    30h



; код первичной иннициализации
start:

   mov     SP, #STACK
   mov     DPTR, #d_levels

   ; обнуляем переменные
   mov     VAL_HDD, #0
   mov     VAL_NET, #0
   mov     VAL_RESERVE, #0

   mov     COUNT_HDD, #0
   mov     COUNT_HDD_HI, #0
   mov     COUNT_NET, #0
   mov     COUNT_NET_HI, #0
   mov     COUNT_RESERVE, #0
   mov     COUNT_RESERVE_HI, #0
   
   mov     STATE_HDD, #0
   mov     STATE_NET, #0
   mov     STATE_RESERVE, #0

   mov     STATE_COUNT_HDD, #0
   mov     STATE_COUNT_HDD_HI, #0
   mov     STATE_COUNT_NET, #0
   mov     STATE_COUNT_RESERVE, #0

   ; для корректной работы сетевой карты надо в течении секунды-двух удерживать высокий уровень
   ; на выоводе OUT_NET_START. затем для наблюдения за сетевой активностью этот вывод надо сбросить в 0
   mov     B,  #7
l0:
   push    B
   mov     B, #0FFh
l1:
   push    B
   mov     B, #0FFh
l2:
   djnz    B, l2
   pop     B
   djnz    B, l1
   pop     B
   djnz    B, l0
   
   clr     OUT_NET_START

   ; иннициализируем таймер
   mov     TL0, #TIMER_LO
   mov     TH0, #TIMER_HI
   setb    EA                          ; глобально разрешаем прерывания
   setb    ET0                         ; разрешение прерывания от Т/С0
   setb    TR0                         ; старт Т/С0

   

; главный цикл программы
main:
   ; индикация загрузки HDD
   mov     A, VAL_HDD
   movc    A, @A + DPTR
   mov     P1, A
   clr     COL_HDD
   call   calc_hdd_level
   setb    COL_HDD
   
   ; индикация загрузки NET
   mov     A, VAL_NET
   movc    A, @A + DPTR
   mov     P1, A
   clr     COL_NET
   call    calc_net_level
   setb    COL_NET

IFDEF ENABLE_RESERVE
   ; индикация загрузки RESERVE
   mov     A, VAL_RESERVE
   movc    A, @A + DPTR
   mov     P1, A
   clr     COL_RESERVE
   call    calc_reserve_level
   setb    COL_RESERVE
ENDIF
   jmp     main
   
   
   
; -------------------------------------------------------------------------------------------------
; подпрограмма вычисления уровня загрузки HDD
calc_hdd_level:
   ; если HDD долго непрерывно активен (горит светодиод при старте ПК), то устанавливаем
   ; уровень в 0 и сбрасываем счетчик
   mov     A, STATE_HDD
   jz      calc_hdd_level_go
   CMPJBW  STATE_COUNT_HDD, 800, calc_hdd_level_go
   ; светодиод HDD горит непрерывно, значит, дело не в активности
   mov     VAL_HDD, #0
   mov     COUNT_HDD, #0
   ret

calc_hdd_level_go:
   mov     A, STATE_HDD
   jnz     calc_hdd_level_go_go
   ; если диск долго пассивен, вручную уменьшаем его счетчик
   mov     A, STATE_COUNT_HDD_HI
   jz      calc_hdd_level_go_go
   ; диск достаточно долго пассивен
   DECW    COUNT_HDD

calc_hdd_level_go_go:
   CALCLEV VAL_HDD, COUNT_HDD,   5, 25, 50, 100, 500, 1000, 2000, 5000
   ret



; -------------------------------------------------------------------------------------------------
; подпрограмма вычисления уровня загрузки NET
calc_net_level:
   ; если долгое время нет сетевой активности, то вручную уменьшаем счетчик NET
   mov     A, STATE_NET
   jnz     calc_net_level_go
   ; сеть сейчас пассивна
   mov     A, STATE_COUNT_NET
   inc     A
   jnz     calc_net_level_go
   ; сеть пассивна и счетчик пассивности на максимуме
   SUBW    COUNT_NET, 10

calc_net_level_go:
   CALCLEV VAL_NET, COUNT_NET,   50, 100, 200, 400, 800, 2000, 3000, 4000
   ret


; -------------------------------------------------------------------------------------------------
; подпрограмма вычисления уровня загрузки RESERVE
IFDEF ENABLE_RESERVE
calc_reserve_level:
   CALCLEV VAL_RESERVE, COUNT_RESERVE,   5, 25, 50, 100, 200, 400, 800, 2000
   ret
ENDIF



; -------------------------------------------------------------------------------------------------
; ОБРАБОТЧИК ПРЕРЫВАНИЯ ТАЙМЕРА
interrupt_handler_tc0:

   ; сохраняем все используемые регистры
   push    B
   mov     B, A


   ; опрашиваем датчики
   ;  HDD
   mov     R1, STATE_HDD            ; сохраняем предыдущее состояние
   jb      IN_HDD, int_inc_hdd
   DECW    COUNT_HDD                ; --
   mov     STATE_HDD, #0
   jmp     int_state_hdd
int_inc_hdd:
   INCW    COUNT_HDD                ; ++
   mov     STATE_HDD, #0FFh

   ; вычисляем счетчик текущего состояния
int_state_hdd:
   mov     A, R1
   xrl     A, STATE_HDD             ; если состояние не изменилось, в A будет 0
   jnz     int_hdd_changed
   ; увеличиваем счетчик удержания состояния
   INCW    STATE_COUNT_HDD
   jmp     int_verify_hdd_done
int_hdd_changed:
   mov     STATE_COUNT_HDD, #0
   mov     STATE_COUNT_HDD_HI, #0
int_verify_hdd_done:




   ;  NET
   mov     R1, STATE_NET
   jb      IN_NET, int_inc_net
   DECW    COUNT_NET                ; --
   mov     STATE_NET, #0
   jmp     int_state_net
int_inc_net:
   INCW    COUNT_NET                ; ++
   mov     STATE_NET, #0FFh
   
   ; вычисляем счетчик текущего состояния
int_state_net:
   mov     A, R1
   xrl     A, STATE_NET             ; если состояние не изменилось, в A будет 0
   jnz     int_net_changed
   ; увеличиваем счетчик удержания состояния
   inc     STATE_COUNT_NET
   mov     A, STATE_COUNT_NET
   jnz     int_verify_net_done
   dec     STATE_COUNT_NET
   jmp     int_verify_net_done
int_net_changed:
   mov     STATE_COUNT_NET, #0
int_verify_net_done:

   
int_verify_reserve:
IFDEF ENABLE_RESERVE
   ;  RESERVE
   jb      IN_RESERVE, int_inc_reserve
   DECW    COUNT_RESERVE            ; --
   jmp     int_reinit_timer
int_inc_reserveЖ
   INCW    COUNT_RESERVE            ; ++
ENDIF


   ; перезагружаем таймер и возвращаемся
int_reinit_timer:
   mov     TL0, #TIMER_LO
   mov     TH0, #TIMER_HI

   ; восстанавливаем сохраненные регистры
   mov     A, B
   pop     B

   reti


; -------------------------------------------------------------------------------------------------
; ОБЛАСТЬ ДАННЫХ
; уровни индикатора
d_levels:
   db     11111111B          ; 0
   db     01111111B          ; 1
   db     00111111B          ; 2
   db     00011111B          ; 3
   db     00001111B          ; 4
   db     00000111B          ; 5
   db     00000011B          ; 6
   db     00000001B          ; 7
   db     00000000B          ; 8


END ; КОНЕЦ ПРОГРАММЫ


