; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: Asynchronous timer library.
;
;  Target OS: KolibriOS
;
;  Dependencies:
;
;  Notes:
;_________________________________________________________________________________________

__sys_time_slice = 10 ;[ms]


if used TimerCreate

initialize __InitTimers
begin
        mov     eax, sys_threads
        mov     ebx, 1
        mov     ecx, __TimerProc
        mov     edx, __timerstack
        int     $40

        return
endp


finalize __StopTimers
begin
        mov     [__timer_stop], 1

.loop:
        mov     eax, sys_f68
        mov     ebx, 1
        int     $40

        cmp     [__timer_stop], 0
        jne     .loop
        return
endp


end if


proc GetTime
begin
        push    ebx ecx edx

        mov     eax, sys_clock
        int     $40

        mov     edx, eax

        mov     ah, al
        and     ah, $0f ; low digit
        and     al, $f0
        and     dl, $f0
        shr     al, 1   ; *8
        shr     dl, 3   ; *2
        add     al, dl
        add     al, ah
        movzx   ebx, al
        imul    ebx, 60*60      ; hours in seconds.

        shr     edx, 8

        mov     ah, dl
        mov     al, dl

        and     ah, $0f ; low digit
        and     al, $f0
        and     dl, $f0
        shr     al, 1   ; *8
        shr     dl, 3   ; *2
        add     al, dl
        add     al, ah
        mov     eax, al
        imul    eax, $60        ; minutes in seconds

        add     ebx, eax

        shr     edx, 8

        mov     ah, dl
        mov     al, dl

        and     ah, $0f ; low digit
        and     al, $f0
        and     dl, $f0
        shr     al, 1   ; *8
        shr     dl, 3   ; *2
        add     al, dl
        add     al, ah
        mov     eax, al
        add     ebx, eax        ; seconds

; here ebx contains the time of the day in seconds...
; now, compute the current date in Unix time...

        mov     eax, sys_date
        int     $40




        mov     eax, ebx
        pop     edx ecx ebx
        return
endp




proc GetLocalTimeOffset
begin
        xor     eax, eax
        return
endp




proc Sleep, .ms
begin
        push    eax ebx ecx edx

        mov     ecx, 10
        mov     eax, [.ms]
        cdq
        div     ecx
        mov     ebx, eax

        mov     eax, sys_delay_hs
        int     $40

        pop     edx ecx ebx eax
        return
endp



uglobal
  rd 1024
  label __timerstack dword

  __timer_stop dd ?
endg



proc __TimerProc
begin

        mov     eax, sys_getsetup
        mov     ebx, 9
        int     $40
        mov     edi, eax

.main_timer_loop:
        cmp     [__timer_stop], 0
        jne     .end_thread

        mov     eax, sys_getsetup
        mov     ebx, 9
        int     $40

        cmp     edi, eax
        jne     .process_timers

        mov     eax, sys_f68
        mov     ebx, 1
        int     $40
        jmp     .main_timer_loop

.process_timers:
        mov     ebx, eax
        sub     ebx, edi
        imul    ebx, __sys_time_slice
        mov     edi, eax

        lea     eax, [__ptrFirstTimer]

.loop:
        mov     eax, [eax+TTimer.next]
.loop2:
        test    eax, eax
        jz      .main_timer_loop

        test    [eax+TTimer.flags], tmfRunning
        jz      .loop

        mov     ecx, [eax+TTimer.value]
        add     ecx, ebx
        mov     [eax+TTimer.value], ecx

        cmp     ecx, [eax+TTimer.interval]
        jl      .loop

.exploop:
        inc     [eax+TTimer.Expired]

        mov     ecx, [eax+TTimer.interval]
        sub     [eax+TTimer.value], ecx
        cmp     [eax+TTimer.value], ecx
        jge     .exploop

        cmp     [eax+TTimer.Callback], 0
        je      .end_event

        mov     ecx, [eax+TTimer.flags]
        and     ecx, $0f
        cmp     ecx, tmfDoNothing
        je      .end_event

; call the callback procedure.
.execloop:
        pushad
        stdcall [eax+TTimer.Callback], eax
        popad

        sub     [eax+TTimer.Expired], 1
        jg      .execloop

.end_event:
        test    [eax+TTimer.flags], tmfSyncDestroy
        jz      .loop

        push    eax
        mov     eax, [eax+TTimer.next]  ; after the destruction, this pointer will be lost.
        stdcall TimerDestroy ; pointer from the stack.
        jmp     .loop2

.end_thread:
        mov     [__timer_stop], 0
        mov     eax, sys_end
        int     $40
endp
