PasjaGSM.pl
  Jesteś w: Forum > Dispatchery i timery


Dispatchery i timery

Forum.PasjaGSM.pl » ...:Sprzęt:... » Nokia » DCT-3 » [DCT3] Modyfikacje HW i SW » NokiX » Programowanie » Dispatchery i timery
Poprzedni temat «» Następny temat
Autor Wiadomość
 
yak 
Starszyzna



Telefon: Kilka DCT3
Operator: Vodafone
Pomógł: 20 razy
Wiek: 37
Dołączył: 21 Gru 2004
Posty: 774
Skąd: Bochum / Niemcy
Wysłany: 2006-08-18, 17:15   Dispatchery i timery

Witam!

Kolejny artykuł, tym razem na temat timerów. Ciągle co jakiś czas dostaję pytania na temat uzyskania pewnych efektów które mozliwe są właśnie dzięki timerom. Postanowiłem więc rzucić na ten temat trochę światła.

Podstawą która trzeba znać zabierając się do tego jest system wiadomości i dispatchery. Najpierw więc krótki wstęp na ten temat. Jeśli to już znasz, przeskocz do lini "I tu wkraczają timery".

System Nokii oparty jest na wiadomościach. Podobne rozwiązania istnieją w wielu normalnych systemach, na przykład w Windowsie (proponuje przyjrzeć się obsłudze okien Windows'a bezpośrednio poprzez WinAPI).

Wiadomość inaczej można nazwać zdarzeniem lub z angielska eventem.

Każda aplikacja czy gra posiada główną funkcję zwaną dispatcherem (dawniej mówiono na to funkcje 5E0). Funkcja ta zajmuje się właśnie obsługą zdarzeń po uruchomieniu gry/aplikacji. Przykładowy dispatcher wygląda np. tak:

Kod:
unsigned dispatcher(unsigned msg)
{
   switch(msg)
   {
      case MSG_D_INIT:
         msg=MSG_R_STAY;
         break;

      case MSG_D_QUIT:
         msg=MSG_R_QUIT;
         break;
   }
   return msg;
}



System posiada wiele swoich zdarzeń które są przekazywane do dispatcher'a podczas jego działania. Większość z nich nas nie interesuje. Są jednak ważne, takie jak MSG_D_INIT (inicjalizacja dispatchera), MSG_D_QUIT (zamknięcie dispatchera) czy MSG_KEYPRESS (naciśnięcie klawisza).

Dla każdego zdarzenia system wywołuje nasz dispatcher podając jako parametr msg zdarzenie, które wystąpiło. Jeśli dane zdarzenie nas interesuje to wyłapujemy je w bloku switch(), inne po prostu zwracamy do systemu (return msg;) do dalszej obróbki.

Oprócz systemu, zdarzenia możmy generować sami. Służy do tego funkcja send_message().

Wywołanie:
Kod:
send_message(MSG_BACK);

spowoduje opuszczenie naszego dispatchera i powrót do menu (zdarzenie MSG_BACK jest generowane także po naciśnięciu klawisza "Wróć" czy C).

Jak już zapewne zauważyliście, każde zdarzenie ma swój identyfikator (np. MSG_D_INIT). Jest to nic innego jak stała liczba całkowita. System rezerwuje część tych liczb na swoje zdarzenia ale nigdy nie używa żadnych o identyfikatorze 0x1F00 i wyższych.

Możemy więc prosto stworzyć własne zdarzenie. Na przykład tak:
Kod:
#define OMSG_ZDARZENIE (0x1F00)

Taką linię umieszczamy na początku pliku źródłowego i już, mamy nasze własne zdarzenie o identyfikatorze OMSG_ZDARZENIE.

Takie zdarzenie możemy wygenerować za pomocą wspomnianej funkcji send_message(). A więc wywołanie:
Kod:
send_message(OMSG_ZDARZENIE);

spowoduje, że po chwili nasz dispatcher odbierze to zdarzenie i będziemy mogli je wyłapać w bloku switch().

W całym tym systemie zdarzeń chodzi głównie o to, aby jak najszybciej obsługiwać nadchodzące zdarzenia. W ten sposób pozostały czas procesora może być wykorzystany przez system (ma on dużo innych rzeczy do roboty w tym samym czasie).

Często jednak pisana przez nas aplikacja czy gra musi odczekać jakiś czas. Przykładowo wyświetlając animację po wyświetleniu każdej klatki musimy odczekać pewien czas zanim narysujemy następną. Skoro więc musimy wszystko obsługiwać jak najszybciej to jak zrealizować takie odczekiwanie?

I tu wkraczają timery.

Timer pozwala nam generalnie na to samo co funkcja send_message(), czyli wygenerowanie zdarzenia, ale nie natychmiast, a po zdefiniowanym czasie.

Najprostszą metodą użycia timerów jest funkcja own_timer_create(). Wywołanie:
Kod:
own_timer_create(125,TT_MESSAGE,OMSG_ZDARZENIE);

spowoduje wygenerowanie zdarzenia OMSG_ZDARZENIE po jednej sekundzie. Kolejne parametry oznaczają:
125 - Czas po jakim ma zostać wygenerowane zdarzenie, 125 oznacza jedną sekundę, najkrótszy czas to więc 1/125 sekundy, najdłuższy to 65535 (0xFFFF) a więc niecałe 9 minut. Dłuższe czasy należy symulować wykorzystując zapętlone timery.
TT_MESSAGE - Oznacza że ma zostać wygenerowane zdarzenie. Timery mają większe możliwości ale tu ich nie rozpatrujemy. Narazie zawsze podawaj tu TT_MESSAGE.
OMSG_ZDARZENIE - To właśnie zdarzenie, które ma zostać wygenerowane.

Funkcja ta na pewno jest łatwa w użyciu. Sprawia jednak jeden problem. Sprawia lekkie problemy gdy wymagana jest możliwość zatrzymania timer'a przed upływem zdefiniowanego w nim czasu.

W takim wypadku lepiej skorzystać z innej funkcji, own_timer_start(). Aby zniej skorzystać timer musimy najpierw zdefiniować w postaci stałej. Robimy to umieszczając następującą linię na początku pliku:
Kod:
static const unsigned moj_timer=OMSG_ZDARZENIE;


W ten sposób stworzyliśmy timer moj_timer, który generuje zdarzenie OMSG_ZDARZENIE. Aby uruchomić ten timer, wywołujemy:
Kod:
own_timer_start(&moj_timer,TT_MESSAGE,125);

Parametr pierwszy to nasz timer poprzedzony operatorem adresowym (&). Drugi i trzeci argument są już nam znane z funkcji own_timer_create(), tylko tu znajdują się w innej kolejności.

Timer stworzony w ten sposób możemy bardzo łatwo zatrzymać przed upływem jego czasu. W tym celu wywołujemy:
Kod:
own_timer_abort(&timer);


To wszystko na temat podstaw używania zdarzeń i timerów.

----------------------------------------------------------------------------------------------

Teraz krótkie pogłębienie tematu dla ambitnych.

Jak pewnie wiecie, zdarzenia mogą mieć parametry. Najpierw przykład dla funkcji send_message(). Wywołanie:
Kod:
send_message(OMSG_ZDARZENIE|MSG_2P,1,2);

generuje zdarzenie OMSG_ZDARZENIE z dwoma parametrami: 1 oraz 2. Parametrów może być maksymalnie 3. Są one typu unsigned int a więc są to 32bitowe liczby którymi można także zapisywać wskaźniki.

Po odebraniu takiego zdarzenia w dispatcherze, liczba parametrów dostępna jest w zmiennej globalnej msg_argc. Same parametry znaleźć można w tablicy globalnej msg_argv[] pod indeksami 0, 1 i 2.

Timery również umożliwiają generowanie zdarzeń z parametrami. Najpierw więc funkcja own_timer_create(). Wywołanie:
Kod:
own_timer_create(125,TT_MESSAGE,OMSG_ZDARZENIE|MSG_2P,1,2);

spowoduje wygenerowanie zdarzenia OMSG_ZDARZENIE z dwoma parametrami: 1 i 2, po jednej sekundzie.

W przypadku tworzenia timerów jako stałych do funkcji own_timer_start(), wygląda to następująco:
Kod:
static const unsigned[] moj_timer = { OMSG_ZDARZENIE|MSG_2P, 1, 2 };


Ponieważ jest to tablica, wywołując funkcję own_timer_start(), czy own_timer_abort() nie musimy podawać operatora adresu:
Kod:
own_timer_start(moj_timer,TT_MESSAGE,125);
own_timer_abort(moj_timer);


Teraz więcej o samych funkcjach obsługi timerów.

Funkcja own_timer_start() zwraca wskaźnik na timer stworzony w pamięci RAM. Wskaźnik ten można przechować i podać do funkcji own_timer_abort() w razie potrzeby.

W przypadku timerów generujących zawsze takie same zdarzenia (z takimi samymi parametrami lub bez nich), metoda ta jest gorsza od tworznia timerów jako stałych gdyż potrzebujemy miejsca na przechowanie wskaźnika na timer. Stworzenie zmiennej globalnej zabierze nam 4 bajty z RAMu telefonu co nie jest dobrym pomysłem.

Metoda ta może jednak okazać się lepszym wyjściem jeśli chcemy aby timer generował różne zdarzenia lub jedno, ale ze zmieniającymi się parametrami. Należy jednak starać się trzymać wskaźnik w pamięci tymczasowej, zachowującej swą zawartość tylko na czas działania aplikacji (global_buffer).

Istnieje jeszcze jedna, nie omówiona funkcja obsługi timerów. Mowa o own_timer_query(). Funkcja ta jako parametru oczekuje tylko wskaźnika na timer (tak samo jak own_timer_abort()). Funkcja zwraca czas, jaki pozostał do wygenrowania zdarzenia lub stałą TE_TIMER_NOT_FOUND jeśli podany timer nie istnieje lub już zakończył odliczanie.

Tę samą wartość zwraca także funkcja own_timer_abort().

Na koniec o innych typach timerów.

Podawana we wszystkich przykładach stała TT_MESSAGE nie jest jedyną, która można tam użyć. Jest to typ timera. TT_MESSAGE oznacza, że timer generuje zdarzenia. Oznacza to jednocześnie, że wartość podana do funkcji own_timer_start() to wskaźnik na stałą definiującą zdarzenie do wygenrowania. Timery mogą jednak wykonywać inne czynności po odliczeniu czasu. Oto inne wartości:

TT_FUNCTION - Timer to wskaźnik na funkcję. Funkcja ta zostanie wywołana po odliczeniu czasu. Funkcja nie ma oczekiwać żadnych parametrów ani zwracać żadnej wartości (void moj_timer(void) {}).
TT_TASK_MESSAGE - Timer to wskaźnik na tablicę dwóch unsigned int'ów. Pierwszy to identyfikator tasku, drugi to wiadomość dla tego tasku. Wiadomość zostanie wysłana po odliczeniu czasu. Ten typ timerów wykorzystywany jest bardzo rzadko. W przypadku funkcji own_timer_create() po typie timera podajemy bezpośrednio identyfikator tasku oraz wiadomość.
TT_MESSAGES - Podobne do TT_MESSAGE, ale timer to tablica zdarzeń (mogą mieć także parametry) zakończona zdarzeniem o identyfikatorze MSG_NOP. Po odliczeniu czasu, zostaną wygenerowane wszystkie te zdarzenia w kolejności w jakiej występują w tablicy. W przypadku funkcji own_timer_create() po typie timera podajemy bezpośrednio listę zdarzeń zakończoną zdarzeniem MSG_NOP.
TT_NOP - Timer jest nic nie oznaczającą wartością. Po odliczeniu nic się nie stanie. Ten typ timera wykorzystywany jest najczęściej z funkcją own_timer_query(). W przypadku funkcji own_timer_create() po typie timera nie podajemy już żadnych parametrów.

Przykład timera TT_FUNCTION:
Kod:
void moj_timer(void)
{
   // ta funkcja wywolana zostanie po odliczeniu czasu
}
[...]
   own_timer_start(moj_timer,TT_FUNCTION,125);

Podany przykład uruchomi funkcję moj_timer() po jednej sekundzie (125).

To tyle. Mam nadzieję że temat opisałem dość wyczerpująco i co ważniejsze, zrozumiale. Dalsze pytania proszę umieszczać w tym wątku.

Pozdrawiam
[Yak]

PS: W ramach małego ćwiczenia polecam zobaczyć jak timery można wykorzystać do symulacji powtarzania naciśnięcia klawiszy (tutaj).
_________________
NokiX Ci się podoba? Kliknij i wyraź to!
^
 
 
 
     
AdSense


druidbartek 
Expert



Telefon: DCT-3
Operator: Era
Pomógł: 39 razy
Wiek: 31
Dołączył: 13 Wrz 2005
Posty: 1006
Skąd: Wrocław
Wysłany: 2006-10-13, 21:35   

bry
mam pytanie odnosnie systemowych timerów. podczas analizoania kodu czesto natykam sie na jakis timer no ale funkcja start_timer ma tylko 2 parametry - ID oraz czas

chcialem zapytac czy jest jakas mozliwosc sprawdzenia co dany ID dokladnie wywoluje po odmierzeniu czasu.

pozdrawiam,
Bartek

[ Dodano: 2006-11-12, 03:55 ]
no tak - dump_timers.nrx i wszystko jasne :]
Ostatnio zmieniony przez druidbartek 2006-10-13, 21:56, w całości zmieniany 1 raz  
^
 
     
Wyświetl posty z ostatnich:   
Odpowiedz do tematu
Nie możesz pisać nowych tematów
Nie możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach
Nie możesz załączać plików na tym forum
Nie możesz ściągać załączników na tym forum
Dodaj temat do Ulubionych
Wersja do druku

Skocz do:  

Podobne tematy
Temat Autor Forum Odpowiedzi Wysłany
Brak nowych postów timery y37 Programowanie 6 2005-12-31, 00:28