amiga-news ENGLISH VERSION
.
Links| Forum| Kommentare| News melden
.
Chat| Umfragen| Newsticker| Archiv
.

amiga-news.de Forum > Programmierung > Gesucht: Sekundentakt [ - Suche - Neue Beiträge - Registrieren - Login - ]

1 -2- 3 4 [ - Beitrag schreiben - ]

20.06.2006, 12:57 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von whose:
Zitat:
Original von Holger:
Zitat:
Original von whose:
Es ist natürlich auch die Frage, wie Du die Ticks auswertest. Wenn Du z.B. immer nur ein Mal GetMsg() aufrufst und nicht, bis GetMsg() NULL zurückliefert (!), dann kennst Du im Grunde schon die Ursache. Du erwischst in dem Fall halt immer nur den "zuletzt" aufgelaufenen Tick, "übersiehst" aber alle anderen, bereits aufgelaufenen Ticks.


Man kann keine Ticks übersehen. Messages hängen in einer Warteschlange und egal, ob man jedesmal WaitPort aufruft oder erst GetMsg bis NULL abholt, bleiben die nicht abgeholten in der Schlange.


Was will uns der Autor damit sagen?


Er will damit sagen, daß Bäume auch umfallen, wenn keiner hinsieht - d.h. hier: Alle Ticks landen in der Message Queu, auch wenn das Programm "nicht hinschaut".

--
http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

20.06.2006, 13:15 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Mad_Dog:
Er will damit sagen, daß Bäume auch umfallen, wenn keiner hinsieht - d.h. hier: Alle Ticks landen in der Message Queu, auch wenn das Programm "nicht hinschaut".

Richtig, und sie sind vor allem auch dann da, wenn das Programm das nächste Mal hinschaut.
Sprich, ob man vor jedem GetMsg ein WaitPort durchführt oder per erst GetMsg bis zum Erreichen von NULL iteriert, spielt keine Rolle, es sind trotzdem exakt die gleich Anzahl Messages in der Queue.

Was anderes wäre es, wenn man per Wait wartet, dann könnten tatsächlich Signale verloren gehen, aber auch weiterhin keine Messages. Das heißt, wenn ein solches Programm z.B. auf den Closebutton wartet, kann es dann ziemlich lange dauern, bis es darauf reagiert, es muß aber trotzdem alle bis zum Klick auf den Button eingetroffenen Ticks bearbeiten.
Die Frage, ob zwanzig ticks eintreffen, wenn man zwei Sekunden nach dem Programmstart auf den Closebutton klickt, läßt sich dann also genauso beantworten.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

20.06.2006, 13:20 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von whose:
Auch das ist klar. Für ein simples Beispiel, was man mit IntuiTicks machen kann, langt es allerdings.

Klar. Man könnte ja z.B. immer die Titelzeile setzen, wenn das Fenster aktiv ist...
Aber primär sollte man ticks dafür verwenden, wofür sie gedacht sind, für die Interaktion. Z.B. für autoscrolling oder kombinierte Eingabeaktionen, verzögertes feedback etc.
Zitat:
Denkbare Überschrift: "So baut man eine wirklich brauchbare WB-Uhr"...
:D

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

20.06.2006, 13:21 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Mad_Dog:
Zitat:
Original von whose:
Zitat:
Original von Holger:
Zitat:
Original von whose:
Es ist natürlich auch die Frage, wie Du die Ticks auswertest. Wenn Du z.B. immer nur ein Mal GetMsg() aufrufst und nicht, bis GetMsg() NULL zurückliefert (!), dann kennst Du im Grunde schon die Ursache. Du erwischst in dem Fall halt immer nur den "zuletzt" aufgelaufenen Tick, "übersiehst" aber alle anderen, bereits aufgelaufenen Ticks.


Man kann keine Ticks übersehen. Messages hängen in einer Warteschlange und egal, ob man jedesmal WaitPort aufruft oder erst GetMsg bis NULL abholt, bleiben die nicht abgeholten in der Schlange.


Was will uns der Autor damit sagen?


Er will damit sagen, daß Bäume auch umfallen, wenn keiner hinsieht - d.h. hier: Alle Ticks landen in der Message Queu, auch wenn das Programm "nicht hinschaut".


Hm, auf die Ticks bezogen hat sich das Thema im Grunde ja schon erledigt. Es landet exakt einer in der Message Queue, bis er beantwortet wird.

In Bezug auf die IntuiMessages stimmt das aber auch nur so lange, wie der Timeout der jeweilige Message nicht erreicht ist. Wenn mans ganz unklug anstellt, gehen da durchaus Ticks flöten (und andere Messages auch). Bei MOUSEMOVE-Events gibt es eine begrenzte Queue, da können auch Events flöten gehen, wenn man nicht schnell genug antwortet (ist mir oft genug passiert).

Es hängt also vom Sender ab, ob die Messages bis in alle Ewigkeit "an der Kasse stehen". Bei Intuition ist es für die meisten Fälle wohl so, daß die "nach Hause gehen, wenn zu viele an der Kasse stehen und ihnen die Warterei auf die Nerven geht".

Beim timer.device liegt der Fall etwas anders (bei Devices im Allgemeinen), denn da ist man selbst der Sender. Allerdings können einem auch da Events flöten gehen, wenn man schläft.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

20.06.2006, 13:31 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Holger:
Zitat:
Original von whose:
Auch das ist klar. Für ein simples Beispiel, was man mit IntuiTicks machen kann, langt es allerdings.

Klar. Man könnte ja z.B. immer die Titelzeile setzen, wenn das Fenster aktiv ist...

Wo ist der Sinn? :D

Du meinst sicherlich, die Uhrzeit in der Titelzeile anzeigen...

Zitat:
Aber primär sollte man ticks dafür verwenden, wofür sie gedacht sind, für die Interaktion. Z.B. für autoscrolling oder kombinierte Eingabeaktionen, verzögertes feedback etc.

Hmm, ich denke mal, für solche Anwendungsfälle fehlen schöne Beispiele. Hast Du da evtl. etwas auf Lager? Wenn das so weiter geht, wird Ralf mehr prima Spiele und Anwendungen in MaxonBasic basteln, Informationen kriegt er ja reichlich :D

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

20.06.2006, 13:37 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von whose:
In Bezug auf die IntuiMessages stimmt das aber auch nur so lange, wie der Timeout der jeweilige Message nicht erreicht ist. Wenn mans ganz unklug anstellt, gehen da durchaus Ticks flöten (und andere Messages auch). Bei MOUSEMOVE-Events gibt es eine begrenzte Queue, da können auch Events flöten gehen, wenn man nicht schnell genug antwortet (ist mir oft genug passiert).

Das stimmt so eben nicht ganz. Es werden keine neuen mehr erzeugt, und die letzte in der queue reflektiert den aktuellen Status solange keine weiteren Events von einem anderen Typ erzeugt werden. Trotzdem bleiben die ersten Mouse-Events, die noch nicht wußten, daß es einen Engpaß geben wird, in der Queue.

Kann man gut beobachten, wenn man in ein Malprogramm bei hoher Systemlast zeichnet. Die Abstände zwischen den registrierten Punkten werden immer größer, d.h. die ersten Events, die noch in einem sehr kleinen Abstand verschickt wurden, sind in der Queue geblieben, auch wenn der Zeitabstand für die nächsten Mouse-events zum Zeitpunkt des Abholens schon viel größer war.
Zitat:
Es hängt also vom Sender ab, ob die Messages bis in alle Ewigkeit "an der Kasse stehen". Bei Intuition ist es für die meisten Fälle wohl so, daß die "nach Hause gehen, wenn zu viele an der Kasse stehen und ihnen die Warterei auf die Nerven geht".
Nee, sie stellen sich mitunter gar nicht erst an, wenn die Schlange zu lang ist. Aber wenn sie erstmal drin sind, bleiben sie auch da.
Wäre auch viel zu aufwendig, ein vorzeitiges Verlassen bei Erhalt der Konsistenz zu implementieren. Das letzte MouseEvent in der Queue durch ein neueres ersetzen, oder einen Tick nicht verschicken, wenn noch einer in der Queue ist, das geht noch. Aber da hört es auch schon auf.

Wie will man z.B. bei folgender Sequenz etwas entfernen, ohne die inhaltliche Aussage zu verändern?

Move(x1,y1), Klick(x1,y1), Move(x2,y2), Diskinserted, KeyDown(shift), Klick(x2,y2), Move(x3,y3), KeyUp(shift), Klick(x3,y3)

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

20.06.2006, 13:41 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von whose:
Du meinst sicherlich, die Uhrzeit in der Titelzeile anzeigen...

Oder den momentan verfügbaren Speicher, CPU-Last, CPU-Temperatur, Luftfeuchtigkeit...
Zitat:
Hmm, ich denke mal, für solche Anwendungsfälle fehlen schöne Beispiele. Hast Du da evtl. etwas auf Lager? Wenn das so weiter geht, wird Ralf mehr prima Spiele und Anwendungen in MaxonBasic basteln, Informationen kriegt er ja reichlich :D

Direkt auf Lager hab ich hier keine, aber so ein bißchen Zeit dafür da ist (sobald Deutschland ausgeschieden ist, duck und weg...), läßt sich vielleicht was machen.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

20.06.2006, 13:58 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Holger:
Zitat:
Original von whose:
In Bezug auf die IntuiMessages stimmt das aber auch nur so lange, wie der Timeout der jeweilige Message nicht erreicht ist. Wenn mans ganz unklug anstellt, gehen da durchaus Ticks flöten (und andere Messages auch). Bei MOUSEMOVE-Events gibt es eine begrenzte Queue, da können auch Events flöten gehen, wenn man nicht schnell genug antwortet (ist mir oft genug passiert).

Das stimmt so eben nicht ganz. Es werden keine neuen mehr erzeugt, und die letzte in der queue reflektiert den aktuellen Status solange keine weiteren Events von einem anderen Typ erzeugt werden. Trotzdem bleiben die ersten Mouse-Events, die noch nicht wußten, daß es einen Engpaß geben wird, in der Queue.

Kann man gut beobachten, wenn man in ein Malprogramm bei hoher Systemlast zeichnet. Die Abstände zwischen den registrierten Punkten werden immer größer, d.h. die ersten Events, die noch in einem sehr kleinen Abstand verschickt wurden, sind in der Queue geblieben, auch wenn der Zeitabstand für die nächsten Mouse-events zum Zeitpunkt des Abholens schon viel größer war.


Ja, ich verstehe, was Du meintest. Und ich meinte etwas anderes, nämlich, daß Dir dadurch evtl. für Dich eigentlich wichtige Events verloren gehen. Ob sie gar nicht erst erzeugt werden oder ein Timeout haben, spielt da keine große Rolle, finde ich.

Zitat:
Zitat:
Es hängt also vom Sender ab, ob die Messages bis in alle Ewigkeit "an der Kasse stehen". Bei Intuition ist es für die meisten Fälle wohl so, daß die "nach Hause gehen, wenn zu viele an der Kasse stehen und ihnen die Warterei auf die Nerven geht".
Nee, sie stellen sich mitunter gar nicht erst an, wenn die Schlange zu lang ist. Aber wenn sie erstmal drin sind, bleiben sie auch da.
Wäre auch viel zu aufwendig, ein vorzeitiges Verlassen bei Erhalt der Konsistenz zu implementieren. Das letzte MouseEvent in der Queue durch ein neueres ersetzen, oder einen Tick nicht verschicken, wenn noch einer in der Queue ist, das geht noch. Aber da hört es auch schon auf.

Wie will man z.B. bei folgender Sequenz etwas entfernen, ohne die inhaltliche Aussage zu verändern?

Move(x1,y1), Klick(x1,y1), Move(x2,y2), Diskinserted, KeyDown(shift), Klick(x2,y2), Move(x3,y3), KeyUp(shift), Klick(x3,y3)


Ich sagte ja auch "für die meisten Fälle". MOUSEMOVE-Events haben die eigene Queue mit begrenzter Länge, einige Events bleiben in der Message Queue erhalten. Ich kann mich aber ziemlich deutlich daran erinnern, daß es einige Intuition-Events mit Timeout gibt. Ich kann mich nur nicht so besonders konkret daran erinnern, welche das im einzelnen waren ("Libraries" immer noch nicht zur Hand, da unterwegs). IDCMP_SIZEVERIFY vielleicht? IDCMP_MENUVERIFY auf alle Fälle, das weiß ich aus leidvoller Erfahrung. Um den Rest habe ich mich noch nie besonders kümmern müssen, daher bin ich mir da alles andere als sicher. Ich sollte mich mal wieder intensiv mit Intuition beschäftigen, denke ich.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

20.06.2006, 14:11 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von whose:
Ich kann mich aber ziemlich deutlich daran erinnern, daß es einige Intuition-Events mit Timeout gibt. Ich kann mich nur nicht so besonders konkret daran erinnern, welche das im einzelnen waren ("Libraries" immer noch nicht zur Hand, da unterwegs). IDCMP_SIZEVERIFY vielleicht? IDCMP_MENUVERIFY auf alle Fälle, das weiß ich aus leidvoller Erfahrung.


Ach so, klar. Da gibt's spätestens seit 2.0 einen Timeout. Allerdings bin ich mir da gar nicht sicher, ob wirklich die Events aus der Queue entfernt werden. Bei dem Timeout geht es ja primär darum, daß das System nicht ewig auf die Anwendung wartet, und das Problem besteht ja z.B. auch, wenn die Message schon abgeholt wurde, aber nicht beanwortet wird.

Deshalb hätte ich gedacht, daß in diesem Fall nur das System nicht mehr wartet und eine irgendwann doch noch eintretende Antwort ignoriert.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

20.06.2006, 14:16 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Holger:
Zitat:
Original von whose:
Ich kann mich aber ziemlich deutlich daran erinnern, daß es einige Intuition-Events mit Timeout gibt. Ich kann mich nur nicht so besonders konkret daran erinnern, welche das im einzelnen waren ("Libraries" immer noch nicht zur Hand, da unterwegs). IDCMP_SIZEVERIFY vielleicht? IDCMP_MENUVERIFY auf alle Fälle, das weiß ich aus leidvoller Erfahrung.


Ach so, klar. Da gibt's spätestens seit 2.0 einen Timeout. Allerdings bin ich mir da gar nicht sicher, ob wirklich die Events aus der Queue entfernt werden. Bei dem Timeout geht es ja primär darum, daß das System nicht ewig auf die Anwendung wartet, und das Problem besteht ja z.B. auch, wenn die Message schon abgeholt wurde, aber nicht beanwortet wird.

Deshalb hätte ich gedacht, daß in diesem Fall nur das System nicht mehr wartet und eine irgendwann doch noch eintretende Antwort ignoriert.


Das weiß ich auch nicht so wahnsinnig genau... aber wäre wohl die logischste Vorgehensweise, einfach die Antworten zu ignorieren... und wieder was gelernt (und hoffentlich behalten ;) )

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

21.06.2006, 14:43 Uhr

Mad_Dog
Posts: 1944
Nutzer
Hier kommt das leicht veränderte "Digitaluhr" Beispiel, diesmal unter Verwendung des timer.device:

code:
/*
 *  Eine einfache Digitaluhr
 *  Diese Version verwendet das timer.device.
 *
 */

#include <stdio.h>
#include <string.h>          // Include-Datei für Strings
#include <time.h>            // Include-Datei für Zeit

#include <exec/exec.h>
#include <exec/types.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <devices/timer.h>
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <graphics/text.h>

#include <proto/intuition.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/diskfont.h>  // Funktionsprototypen der diskfont.library

// Symbolische Konstanten
#define WIDTH 130   // Breite des Fensters
#define HEIGHT 70   // Höhe des Fensters

struct Window *Fenster;                // Zeiger auf Window-Struktur
struct IntuitionBase *IntuitionBase;   // Zeiger auf IntuitionBase-Struktur
struct RastPort *rp;                   // Zeiger auf RastPort Struktur
struct Library *DiskfontBase;          // Zeiger auf DiskfontBase
struct TextFont *textfont;             // Zeiger auf TextFont
struct TextAttr ta;                    // TextAttr Struktur

struct timerequest *TimerIO;
struct MsgPort *TimerMP;

/* Funktionsprototypen */
void SchreibeZeit(struct RastPort *rp,int x,int y);
void ShutDown(int code, STRPTR error);

int main(void)
{
  /* Variablen zur Message-Bearbeitung */
  struct MsgPort *Port;             // Zeiger auf Message Port Struktur
  struct IntuiMessage *Nachricht;   // Zeiger auf Intuition Message Struktur
  ULONG  klasse;
  USHORT code;
  ULONG Signale;
  int x,y;

  LONG black_pen,green_pen;         // Variablen für Pens
  int x0,y0,x1,y1;

  BOOL Ende = FALSE; // Boolsche Variable: Programmende?

  // Intuition Library öffnen
  IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",37L);
  if (IntuitionBase == NULL) ShutDown(10,"Konnte intuition.library 37 nicht öffnen.");

  // Disk Font Library öffnen
  DiskfontBase = OpenLibrary("diskfont.library",37L);
  if (DiskfontBase == NULL) ShutDown(10,"Konnte diskfont.library 37 nicht öffnen.");

  // Fenster mittels Tags öffnen
  Fenster = OpenWindowTags(NULL,
                           WA_Left, 100,       // Abstand vom linken Rand
                           WA_Top, 100,        // Abstand vom oberen Rand
                           WA_Width, WIDTH,    // Breite
                           WA_Height, HEIGHT,  // Höhe
                           WA_Title, "Digitaluhr",           // Fenstertitel
                           WA_CloseGadget, TRUE,             // Close-Gadget
                           WA_DragBar, TRUE,                 // Ziehleiste
                           WA_DepthGadget, TRUE,             // Depth-Gadget
                           WA_IDCMP,                         // IDCMP-Flags
                           IDCMP_CLOSEWINDOW,
                           WA_Activate, TRUE,                // Fenster aktivieren
                           TAG_DONE);

  if (Fenster == NULL) ShutDown(10,"Konnte Fenster nicht öffnen.");

  TimerMP = CreateMsgPort();
  if (TimerMP == NULL) ShutDown(10,"Konnte Message Port nicht erzeugen.");

  TimerIO = (struct timerequest *) CreateIORequest(TimerMP,sizeof(struct timerequest));
  if (TimerIO == NULL) ShutDown(10,"Konnte Timerrequest nicht erzeugen.");

  OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimerIO,0L);

  TimerIO->tr_node.io_Command = TR_GETSYSTIME;
  SendIO((struct IORequest *) TimerIO);

  rp = Fenster->RPort;

  /* TextAttr Struktur ausfüllen... */
  ta.ta_Name = "helvetica.font";  // Name des Fonts
  ta.ta_YSize = 24;               // Höhe des Fonts
  ta.ta_Style = FS_NORMAL;        // Normaler Textstil
  ta.ta_Flags = FPF_DISKFONT;     // Es ist ein Disk Font

  /* Die Funktion OpenDiskFont öffnet einen Font aus FONTS: */
  textfont = (struct TextFont *) OpenDiskFont(&ta);
  if (textfont == NULL) ShutDown(10,"Konnte helvetica.font 24 nicht öffnen.");

  /* Pens ermitteln: Schwarz und Grün */
  black_pen = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap,
                            0x00000000,0x00000000,0x00000000,
                            PRECISION_GUI, TAG_DONE);

  green_pen = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap,
                            0x00000000,0xFFFFFFFF,0x00000000,
                            PRECISION_GUI, TAG_DONE);

  /*  In diesem Beispiel benutzen wir KEIN GimmeZeroZero Fenster.
   *  Deshalb ermitteln die Maße der Zeichenfläche des Fensters
   *  selbst...
   */
  x0 = Fenster->BorderLeft;
  y0 = Fenster->BorderTop;
  x1 = Fenster->Width - Fenster->BorderRight-1;
  y1 = Fenster->Height - Fenster->BorderBottom-1;

  /* Jetzt übermalen wir die Zeichenfläche schwarz */
  SetAPen(rp,black_pen);
  RectFill(rp,x0,y0,x1,y1);

  SetFont(rp,textfont);  // Schriftart wählen

  SetAPen(rp,green_pen);  // Pen für Vordergrund
  SetBPen(rp,black_pen);  // Pen für Hintergrund

  /*  Der Text soll zentriert dargestellt werden.
   *  Deshalb errechnen wir, welchen Abstand der Text
   *  vom linken Fensterrand haben muß.
   */
  x = (x1-TextLength(rp,"00:00:00",8))/2;
  y = y0+30;

  SchreibeZeit(rp,x,y);

  Port = Fenster->UserPort;

  TimerIO->tr_node.io_Command = TR_ADDREQUEST;
  TimerIO->tr_time.tv_secs = 1;  // Eine Nachricht pro Sekunde
  TimerIO->tr_time.tv_micro   = 0;
  SendIO((struct IORequest *)TimerIO);

  /*  Schleife läuft so lange, bis das Programm
   *  durch Anklicken des Close-Gadgets beedet wird.
   */
   while (!Ende)
   {
     /*  Wir warten auf Signale von Intuition
      *  oder vom timer.device.
      */
     Signale = Wait((1UL << TimerMP->mp_SigBit) | (1UL << Port->mp_SigBit));

     /* Die Uhr hat sich gemeldet... */
     if(1UL << TimerMP->mp_SigBit)
     {
       WaitIO((struct IORequest *)TimerIO);
       TimerIO->tr_node.io_Command  = TR_ADDREQUEST;
       TimerIO->tr_time.tv_secs  = 1;  // Eine Nachricht pro Sekunde
       TimerIO->tr_time.tv_micro = 0;
       SchreibeZeit(rp,x,y);
       SendIO((struct IORequest *)TimerIO);
     }

     /* Schleife läuft bis alle Ereignisse
      * abgearbeitet sind.
      */
      while(Nachricht = (struct IntuiMessage *) GetMsg(Port))
      {
         klasse = Nachricht->Class;
         code =  Nachricht->Code;

         /* Welches Ereignis ist eingetreten? */
         switch(klasse)
         {
            /* Close Gadget wurde angeklickt */
            case CLOSEWINDOW :
                 Ende = TRUE; // Programmende
                 break;

         } // Ende der switch-Verzweigung

       /* Wir sind mit der Bearbeitung fertig
        * und beantworten die Nachricht.
        */
        ReplyMsg((struct Message *)Nachricht);

       } // Ende der inneren while-Schleife
     } // Ende der äußeren while-Schleife


   AbortIO((struct IORequest *)TimerIO);
   WaitIO((struct IORequest *)TimerIO);

   CloseDevice((struct IORequest *) TimerIO);
   DeleteIORequest((struct IORequest *)TimerIO);

   DeleteMsgPort(TimerMP);


  // Die Pens wieder freigeben
  ReleasePen(Fenster->WScreen->ViewPort.ColorMap,black_pen);
  ReleasePen(Fenster->WScreen->ViewPort.ColorMap,green_pen);

  ShutDown(0,NULL);

  return 0;

}

/*  SchreibeZeit
 *  Schreibt die aktuelle Zeit an den Koordinaten x,y
 *  in den RastPort rp.
 */
void SchreibeZeit(struct RastPort *rp,int x,int y)
{
  struct tm *tp;       // Zeiger auf tm Struktur
  time_t t;
  char Puffer[9];      // Puffer für 8 Zeichen + NULL

  time(&t);            // Aktuelle Systemzeit holen
  tp = localtime(&t);  // Zeitzonen berücksichtigen

  /*  Aktuelle Zeit in Textpuffer schreiben...
   *  Die Platzhalter des Format-Strings haben folgende Bedeutung:
   *
   *  %H : Stunden
   *  %M : Minuten
   *  %S : Sekunden
   */
  strftime(Puffer,sizeof(Puffer),"%H:%M:%S",tp);

  Move(rp,x,y);
  Text(rp,Puffer,8);

}


/* Resourcen freigeben */
void ShutDown(int code, STRPTR error)
{
  if (textfont) CloseFont(textfont);
  if (DiskfontBase != NULL) CloseLibrary((struct Library *)DiskfontBase);
  if (Fenster != NULL) CloseWindow(Fenster);
  if (IntuitionBase != NULL) CloseLibrary((struct Library *)IntuitionBase);

  if (error)
  {
    printf("Fehler: %sn", error);
  }
  exit(code);

}

--
http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

21.06.2006, 15:41 Uhr

whose
Posts: 2156
Nutzer
@Mad_Dog:

Auch ein schönes Beispiel,vielen Dank dafür :)

Eins ist mir aber aufgefallen: Wozu schickst Du das Kommando TR_GETSYSTIME? Für die Auslösung des Timerevents ist es nicht nötig und time() aus der Standardbibliothek macht meines Wissens nach das Gleiche nochmal.

Noch eine Kleinigkeit: Das simple AbortIO() sollte hier zwar keine Schwierigkeiten bereiten, "schöner" ist aber folgender Schnipsel:

code:
if(!(CheckIO()))
{
    AbortIO(TimerIO);
}
WaitIO(TimerIO);
CloseDevice((struct IORequest *)TimerIO);


AbortIO() kann Schwierigkeiten bereiten, wenn man einen Request versucht abzubrechen, der gar nicht (mehr) gesendet wurde. CheckIO() gibt in diesem Fall einfach ein TRUE zurück und ein AbortIO() ist nicht mehr notwendig.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

21.06.2006, 16:03 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von whose:

Eins ist mir aber aufgefallen: Wozu schickst Du das Kommando TR_GETSYSTIME? Für die Auslösung des Timerevents ist es nicht nötig und time() aus der Standardbibliothek macht meines Wissens nach das Gleiche nochmal.


Du hast natürlich Recht: In diesem Beispiel ist das doppelt gemoppelt. Das liegt daran, daß dies ein "mutierter Beispielcode" ist. ;)
Man könnte es auch so umbauen, daß die Zeit über das timer.device ermittelt wird.

Eigentlich wollte ich nur ein Beispiel für Ralf bringen, das zeigt, wie man einen "zyklischen Alarm" setzen kann.

--
http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

21.06.2006, 16:05 Uhr

whose
Posts: 2156
Nutzer
@Mad_Dog:

Ah, ok ;)

Mit OS4 funktionierts übrigens auch ganz nett :D

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

21.06.2006, 16:20 Uhr

thomas
Posts: 7716
Nutzer
@Mad_Dog:
Zitat:
OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimerIO,0L);

Du solltest prüfen, ob das Device erfolgreich geöffnet wurde. Immerhin gibt es nicht unbegrenzt Timer im System.



Zitat:
black_pen = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap,
0x00000000,0x00000000,0x00000000,
PRECISION_GUI, TAG_DONE);

green_pen = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap,
0x00000000,0xFFFFFFFF,0x00000000,
PRECISION_GUI, TAG_DONE);



Das muß OBP_Precision,PRECISION_GUI heißen ! So wie du es hier machst, hast du Glück, daß es nicht abstürzt, weil TAG_DONE fehlt (das TAG_DONE, das da steht wird als ti_Data von PRECISION_GUI genommen).


Zitat:
TimerIO = (struct timerequest *) CreateIORequest(TimerMP,sizeof(struct timerequest));
if (TimerIO == NULL) ShutDown(10,"Konnte Timerrequest nicht erzeugen.");


Wenn das fehlschlägt, wird TimerMP nicht freigegeben. Warum hast du die Device-Sachen nicht in der ShutDown-Prozedur berücksichtigt ?

Gruß Thomas

--
Email: thomas-rapp@web.de
Home: thomas-rapp.homepage.t-online.de/

[ - Antworten - Zitieren - Direktlink - ]

21.06.2006, 16:34 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von thomas:

Zitat:
TimerIO = (struct timerequest *) CreateIORequest(TimerMP,sizeof(struct timerequest));
if (TimerIO == NULL) ShutDown(10,"Konnte Timerrequest nicht erzeugen.");


Wenn das fehlschlägt, wird TimerMP nicht freigegeben. Warum hast du die Device-Sachen nicht in der ShutDown-Prozedur berücksichtigt ?


Danke für die Hinweise. Den Code habe ich eben auf die Schnell mal zusammengebastelt und nicht an alles gedacht.


--
http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

22.06.2006, 01:28 Uhr

whose
Posts: 2156
Nutzer
Hier in der korrigierten und erweiterten Fassung:

code:
/*
     *  Eine einfache Digitaluhr
     *  Diese Version verwendet das timer.device.
     *  (und geht, je nach Zeit zum Start, manchmal etwas nach ;) 
     */
    #define INTUITION_PRE_V36_NAMES /* Wir verwenden iobsolete.h! Ältere Compiler ignorieren das */

    #include <stdlib.h>
    #include <stdio.h>

    #include <exec/exec.h>
    #include <exec/types.h>
    #include <exec/io.h>
    #include <exec/memory.h>
    #include <devices/timer.h>
    #include <intuition/intuition.h>
    #include <graphics/gfx.h>
    #include <graphics/text.h>

    #include <proto/intuition.h>
    #include <proto/dos.h>
    #include <proto/exec.h>
    #include <proto/graphics.h>
    #include <proto/diskfont.h>  // Funktionsprototypen der diskfont.library

    // Symbolische Konstanten
    #define WIDTH 130   // Breite des Fensters
    #define HEIGHT 70   // Höhe des Fensters

    struct Window *Fenster;                // Zeiger auf Window-Struktur
    
    struct IntuitionBase *IntuitionBase;   // Zeiger auf IntuitionBase-Struktur
    struct RastPort *rp;                   // Zeiger auf RastPort Struktur
    struct Library *DiskfontBase;          // Zeiger auf DiskfontBase
    struct TextFont *textfont;             // Zeiger auf TextFont
    struct TextAttr ta;                    // TextAttr Struktur

    struct timerequest *TimerIO;
    struct MsgPort *TimerMP;
    LONG timer;

    /* Funktionsprototypen */
    void SchreibeZeit(struct RastPort *rp,int x,int y, ULONG sekunden, ULONG minuten, ULONG stunden);
    void ShutDown(int code, STRPTR error);

    int main(void)
    {
      /* Variablen zur Message-Bearbeitung */
      struct MsgPort *Port;             // Zeiger auf Message Port Struktur
      struct IntuiMessage *Nachricht;   // Zeiger auf Intuition Message Struktur
      ULONG  klasse;
      USHORT code;
      ULONG Signale;
      int x,y;

      LONG black_pen,green_pen;         // Variablen für Pens
      int x0,y0,x1,y1;

      ULONG stunden, minuten, sekunden;

      BOOL Ende = FALSE; // Boolsche Variable: Programmende?

      // Intuition Library öffnen
      IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",37L);
      if (IntuitionBase == NULL) ShutDown(10,"Konnte intuition.library 37 nicht öffnen.");

      // Disk Font Library öffnen
      DiskfontBase = OpenLibrary("diskfont.library",37L);
      if (DiskfontBase == NULL) ShutDown(10,"Konnte diskfont.library 37 nicht öffnen.");

      // Fenster mittels Tags öffnen
      Fenster = OpenWindowTags(NULL,
                               WA_Left, 100,       // Abstand vom linken Rand
                               WA_Top, 100,        // Abstand vom oberen Rand
                               WA_Width, WIDTH,    // Breite
                               WA_Height, HEIGHT,  // Höhe
                               WA_Title, "Digitaluhr",           // Fenstertitel
                               WA_CloseGadget, TRUE,             // Close-Gadget
                               WA_DragBar, TRUE,                 // Ziehleiste
                               WA_DepthGadget, TRUE,             // Depth-Gadget
                               WA_IDCMP,                         // IDCMP-Flags
                               IDCMP_CLOSEWINDOW,
                               WA_Activate, TRUE,                // Fenster aktivieren
                               TAG_DONE);

      if (Fenster == NULL) ShutDown(10,"Konnte Fenster nicht öffnen.");

      TimerMP = CreateMsgPort();
      if (TimerMP == NULL) ShutDown(10,"Konnte Message Port nicht erzeugen.");

      TimerIO = (struct timerequest *) CreateIORequest(TimerMP,sizeof(struct timerequest));
      if (TimerIO == NULL) ShutDown(10,"Konnte Timerrequest nicht erzeugen.");

      timer = OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)TimerIO,0L);
      
      if(timer != 0) ShutDown(10, "Konnte timer.device nicht öffnen.");


      rp = Fenster->RPort;

      /* TextAttr Struktur ausfüllen... */
      ta.ta_Name = "helvetica.font";  // Name des Fonts
      ta.ta_YSize = 24;               // Höhe des Fonts
      ta.ta_Style = FS_NORMAL;        // Normaler Textstil
      ta.ta_Flags = FPF_DISKFONT;     // Es ist ein Disk Font

      /* Die Funktion OpenDiskFont öffnet einen Font aus FONTS: */
      textfont = (struct TextFont *) OpenDiskFont(&ta);
      if (textfont == NULL) ShutDown(10,"Konnte helvetica.font 24 nicht öffnen.");

      /* Pens ermitteln: Schwarz und Grün */
      black_pen = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap,
                                0x00000000,0x00000000,0x00000000,
                                OBP_Precision, PRECISION_GUI, TAG_DONE);

      green_pen = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap,
                                0x00000000,0xFFFFFFFF,0x00000000,
                                OBP_Precision, PRECISION_GUI, TAG_DONE);

      /*  In diesem Beispiel benutzen wir KEIN GimmeZeroZero Fenster.
       *  Deshalb ermitteln die Maße der Zeichenfläche des Fensters
       *  selbst...
       */
      x0 = Fenster->BorderLeft;
      y0 = Fenster->BorderTop;
      x1 = Fenster->Width - Fenster->BorderRight-1;
      y1 = Fenster->Height - Fenster->BorderBottom-1;

      /* Jetzt übermalen wir die Zeichenfläche schwarz */
      SetAPen(rp,black_pen);
      RectFill(rp,x0,y0,x1,y1);

      SetFont(rp,textfont);  // Schriftart wählen

      SetAPen(rp,green_pen);  // Pen für Vordergrund
      SetBPen(rp,black_pen);  // Pen für Hintergrund

      /*  Der Text soll zentriert dargestellt werden.
       *  Deshalb errechnen wir, welchen Abstand der Text
       *  vom linken Fensterrand haben muß.
       */
      x = (x1-TextLength(rp,"00:00:00",8))/2;
      y = y0+30;

      /*  Hier initialisieren wir dir Uhr einmal
       *  "vorweg". Ansonsten wäre für eine
       *  Sekunde nach dem Start nichts zu sehen
       */

      TimerIO->tr_node.io_Command = TR_GETSYSTIME;
      /*  DoIO(), weil der IORequest sonst (noch) keine Werte enthalten würde,
       *  bis wir das Signal vom timer.device empfangen. Das ergäbe undefinierte
       *  Inhalte der TimerIO-Struktur->Absturz
       */
      DoIO((struct IORequest *) TimerIO); 

      sekunden = (ULONG)TimerIO->tr_time.tv_secs;
      minuten = sekunden / 60;
      stunden = minuten / 60;
      sekunden = sekunden % 60;
      minuten = minuten % 60;
      stunden = stunden % 24;

      SchreibeZeit(rp,x,y, sekunden, minuten, stunden);

      Port = Fenster->UserPort;

      TimerIO->tr_node.io_Command = TR_ADDREQUEST;
      TimerIO->tr_time.tv_secs = 1;  // Eine Nachricht pro Sekunde
      TimerIO->tr_time.tv_micro   = 0;
      SendIO((struct IORequest *)TimerIO);

      /*  Schleife läuft so lange, bis das Programm
       *  durch Anklicken des Close-Gadgets beedet wird.
       */
       while (!Ende)
       {
         /*  Wir warten auf Signale von Intuition
          *  oder vom timer.device.
          */
         Signale = Wait((1UL << TimerMP->mp_SigBit) | (1UL << Port->mp_SigBit));

         /* Die Uhr hat sich gemeldet... */
         if(Signale & (1UL << TimerMP->mp_SigBit))
         {
           WaitIO(); /* MessagePort von der Antwort des timer.device "befreien".
                             * WaitIO() "wartet" hier nicht wirklich, sondern kehrt sofort
                             * zurück. Hier nehmen wir es, weil WaitIO() freundlicherweise
                             * auch noch den MessagePort "aufräumt". Man könnte das auch
                             * selbst per GetMsg(TimerMP) erldigen.

           TimerIO->tr_node.io_Command = TR_GETSYSTIME;
           DoIO((struct IORequest *) TimerIO);

           sekunden = (ULONG)TimerIO->tr_time.tv_secs;
           minuten = sekunden / 60;
           stunden = minuten / 60;
           sekunden = sekunden % 60;
           minuten = minuten % 60;
           stunden = stunden % 24;
           
           TimerIO->tr_node.io_Command  = TR_ADDREQUEST;
           TimerIO->tr_time.tv_secs  = 1;  // Eine Nachricht pro Sekunde
           TimerIO->tr_time.tv_micro = 0;
           SendIO((struct IORequest *)TimerIO);

           SchreibeZeit(rp,x,y, sekunden, minuten, stunden);
         }

         /* Schleife läuft bis alle Ereignisse
          * abgearbeitet sind.
          */
          while(Nachricht = (struct IntuiMessage *) GetMsg(Port))
          {
             klasse = Nachricht->Class;
             code =  Nachricht->Code;

             /* Welches Ereignis ist eingetreten? */
             switch(klasse)
             {
                /* Close Gadget wurde angeklickt */
                case CLOSEWINDOW :
                     Ende = TRUE; // Programmende
                     break;

             } // Ende der switch-Verzweigung

           /* Wir sind mit der Bearbeitung fertig
            * und beantworten die Nachricht.
            */
            ReplyMsg((struct Message *)Nachricht);

           } // Ende der inneren while-Schleife
         } // Ende der äußeren while-Schleife

       if(!(CheckIO((struct IORequest *)TimerIO)))
       {
           AbortIO((struct IORequest *)TimerIO);
       }

       WaitIO((struct IORequest *)TimerIO);

       CloseDevice((struct IORequest *) TimerIO);
       timer = 1; // wir kommen ja noch zu ShutDown()...

       DeleteIORequest((APTR)TimerIO);
       TimerIO = NULL; // ...zwei Mal freigeben ist nie eine gute Idee ;) 

       DeleteMsgPort(TimerMP);
       TimerMP = NULL;


      // Die Pens wieder freigeben
      ReleasePen(Fenster->WScreen->ViewPort.ColorMap,black_pen);
      ReleasePen(Fenster->WScreen->ViewPort.ColorMap,green_pen);

      ShutDown(0,NULL);

      return 0;

    }

    /*  SchreibeZeit
     *  Schreibt die aktuelle Zeit an den Koordinaten x,y
     *  in den RastPort rp.
     */
    void SchreibeZeit(struct RastPort *rp,int x,int y, ULONG sekunden, ULONG minuten, ULONG stunden)
    {      
      char Puffer[9];      // Puffer für 8 Zeichen + NULL
      /*  kopieren der Zeitwerte in den Puffer,
       *  jeder Wert hat mindestens zwei Ziffern
       *  mit ggf. führender 0
       */
      sprintf(Puffer, "%02d:%02d:%02d", stunden, minuten, sekunden);

      Move(rp,x,y);
      Text(rp,Puffer,8);

    }


    /* Resourcen freigeben */
    void ShutDown(int code, STRPTR error)
    {
      // OpenDevice() gibt 0 zurück, falls Erfolg!
      if(!timer) CloseDevice((struct IORequest *)TimerIO);
      if(TimerIO) DeleteIORequest((APTR)TimerIO);
      if(TimerMP) DeletePort(TimerMP);
      if (textfont) CloseFont(textfont);
      if (DiskfontBase != NULL) CloseLibrary((struct Library *)DiskfontBase);
      if (Fenster != NULL) CloseWindow(Fenster);
      if (IntuitionBase != NULL) CloseLibrary((struct Library *)IntuitionBase);

      if (error)
      {
        printf("Fehler: %sn", error);
      }
      exit(code);

    }


Edit: Dussligen Fehler bei "if(Signale & (1UL << TimerMP->mp_SigBit))" (das "==") beseitigt, WaitIO() eingefügt (danke an thomas).

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233


[ Dieser Beitrag wurde von whose am 22.06.2006 um 01:39 Uhr geändert. ]

[ Dieser Beitrag wurde von whose am 22.06.2006 um 03:16 Uhr geändert. ]

[ Dieser Beitrag wurde von whose am 26.06.2006 um 16:22 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

22.06.2006, 01:52 Uhr

whose
Posts: 2156
Nutzer
Argh, ich seh grad, ich hätte in der Wait()-Schleife TR_ADDREQUEST vor TR_GETSYSTIME setzen sollen... naja, wers ausprobieren möchte, kann die Stelle ja umsortieren.

Hinweis für OS4-Nutzer (und OS4-C-Anfänger): Linken mit libauto.a und libamiga.a, zusätzlich #define __USE_INLINE__ setzen (wegen der geänderten Konventionen für Funktionsaufrufe ala "IFace->blablabla()", mit dem #define wird die herkömmliche Art benutzt) und die OpenLibrary()/CloseLibrary()-Geschichten auskommentieren/entfernen. Selbiges gilt für die Deklarationen der Library-Strukturen (IntuitionBase und DiskFontBase), auskommentieren/entfernen.
--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

22.06.2006, 11:47 Uhr

Reth
Posts: 1858
Nutzer
Mal ne dumme Frage:

Muss man das ReplyMsg nach Abarbeitung der Message oder davor rufen, oder ist das egal?

[ - Antworten - Zitieren - Direktlink - ]

22.06.2006, 13:03 Uhr

Ralf27
Posts: 2779
Nutzer
Zitat:
Original von Reth:
Mal ne dumme Frage:

Muss man das ReplyMsg nach Abarbeitung der Message oder davor rufen, oder ist das egal?


Hm, aus der reinen überlegung herraus würde ich tippen das man erst ReplyMsg aufrufen darf, wenn die Message bearbeitet wurde, bzw. erst aufrufen wenn alle Daten aus der Struktur gelesen worden sind.

Denn wenn noch mehr Messages warten, dann wird die aktuelle Message nach dem sofortigen Aufruf von ReplyMsg ja durch die neue überschrieben, die ja schon sozusagen hinten dran stehen könnte.

Also erst ReplyMsg, wenn alle Daten aus der Struktur gelesen worden sind, bzw. alles verarbeitet worden ist.
--
http://www.alternativercomputerclub.de.vu

[ - Antworten - Zitieren - Direktlink - ]

22.06.2006, 13:26 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Reth:
Mal ne dumme Frage:

Muss man das ReplyMsg nach Abarbeitung der Message oder davor rufen, oder ist das egal?


Aus Sicht einer resourcenschonenden Strategie sollte man sie so schnell wie möglich beantworten, damit der Speicher wiederverwendet werden kann. Wie hier aber schon gesagt wurde, muß man alle Daten, die man benötigt, vorher rauskopieren. Nach der Beantwortung (wird ja auch gerne als Zurückschicken bezeichnet), darf man nicht mehr auf die Nachricht zugreifen.

Und bei Nachrichten, die eine Antwort beinhalten, sollte man natürlich auch erst antworten, wenn man die Antwort kennt. Das gilt für die ...VERIFY Messages und natürlich auch für die TICKS, deren Beantwortung ja impliziert, daß jetzt ein neuer Tick gesendet werden darf.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

22.06.2006, 14:36 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Holger:

Und bei Nachrichten, die eine Antwort beinhalten, sollte man natürlich auch erst antworten, wenn man die Antwort kennt. Das gilt für die ...VERIFY Messages und natürlich auch für die TICKS, deren Beantwortung ja impliziert, daß jetzt ein neuer Tick gesendet werden darf.


Wie meinst Du das? Meinst Du mit Antwort eine Nachricht, die als Reply auf eine eigene Nachricht eintrifft? Die braucht man nicht wieder zu beantworten, da man selbst "Besitzer" des Speichers der Nachricht ist. Das ist z.B. bei den Nachrichten eines Devices als Antwort auf einen IORequest der Fall.

Solltest Du das anders meinen, wäre ne kleine Erläuterung nicht schlecht. Irgendwie ist der Satz mit den Antworten etwas verwirrend :glow:

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

22.06.2006, 17:39 Uhr

Holger
Posts: 8116
Nutzer
@whose:
Wenn Du z.B. eine MENUVERIFY Message beantwortest, teilst Du mit, ob Du mit dem Öffnen des Menüs einverstanden bist, oder nicht. Du kannst also die Message erst beantworten, wenn Du weißt ob Du mit Ok oder Cancel antworten willst. Das meinte ich mit, Du mußt Deine Antwort erst mal kennen.

Wenn diese Antwort das Ergebnis Deiner Verarbeitung ist, kannst Du natürlich die Message nicht vorher beantworten. Das ist eben etwas anderes, als die Verarbeitung eines Tastendrucks. Da kannst Du das Zeichen kopieren, Message zurückschicken, Dokument aktualisieren, Dokument neu zeichnen, nächste Nachricht bearbeiten...

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

22.06.2006, 18:59 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Holger:
@whose:
Wenn Du z.B. eine MENUVERIFY Message beantwortest, teilst Du mit, ob Du mit dem Öffnen des Menüs einverstanden bist, oder nicht. Du kannst also die Message erst beantworten, wenn Du weißt ob Du mit Ok oder Cancel antworten willst. Das meinte ich mit, Du mußt Deine Antwort erst mal kennen.


Ah, ok, so war das gemeint. Ja, in den Fällen ist das klar. Der Satz hatte mich halt etwas verwirrt ;)

Grüße


--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

22.06.2006, 21:56 Uhr

whose
Posts: 2156
Nutzer
Uiuiui, ich seh grad noch nen Patzer (der war schon in der ersten Fassung drin, total übersehen):
code:
/* Die Uhr hat sich gemeldet... */
     if(1UL << TimerMP->mp_SigBit)


das müßte
code:
if(Signale == (1UL << TimerMP->mp_SigBit))


lauten.

In der ursprünglichen Fassung ist es mehr oder weniger Zufall, daß es funktioniert, wie gedacht.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

26.06.2006, 11:23 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von whose:
Uiuiui, ich seh grad noch nen Patzer (der war schon in der ersten Fassung drin, total übersehen):
code:
/* Die Uhr hat sich gemeldet... */
     if(1UL << TimerMP->mp_SigBit)


das müßte
code:
if(Signale == (1UL << TimerMP->mp_SigBit))


lauten.

In der ursprünglichen Fassung ist es mehr oder weniger Zufall, daß es funktioniert, wie gedacht.


Warum denn das? Wenn TimerMP->mp_SigBit wahr ist, dann mach ich die folgende Anweisung, ansonsten nicht. Die Variable "Signale" ist in dem Code fehl am Platz... sorry :glow:
--
http://www.norman-interactive.com

[ Dieser Beitrag wurde von Mad_Dog am 26.06.2006 um 11:26 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

26.06.2006, 11:33 Uhr

thomas
Posts: 7716
Nutzer
Zitat:
Original von Mad_Dog:
Warum denn das? Wenn TimerMP->mp_SigBit wahr ist, dann mach ich die folgende Anweisung, ansonsten nicht.


1UL << TimerMP->mp_SigBit ist immer wahr.

Normalerweise macht man das so:

code:
sigflag1 = 1 << port1->mp_SigBit;
sigflag2 = 1 << port2->mp_SigBit;
sigflag3 = 1 << port3->mp_SigBit;

signals_received = Wait (sigflag1 | sigflag2 | sigflag3);

if (signals_received & sigflag1)
{
   while (msg1 = GetMsg (port1))
   {
      /* message(s) an port1 verarbeiten */
      ReplyMsg (msg1);
   }
}

if (signals_received & sigflag2)
{
   while (msg2 = GetMsg (port2))
   {
      /* message(s) an port2 verarbeiten */
      ReplyMsg (msg2);
   }
}

if (signals_received & sigflag3)
{
   while (msg3 = GetMsg (port3))
   {
      /* message(s) an port3 verarbeiten */
      ReplyMsg (msg3);
   }
}


Die Abfrage mit == ist genauso falsch wie ganz ohne Signale.

Gruß Thomas

--
Email: thomas-rapp@web.de
Home: thomas-rapp.homepage.t-online.de/


[ Dieser Beitrag wurde von thomas am 26.06.2006 um 11:42 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

26.06.2006, 11:45 Uhr

thomas
Posts: 7716
Nutzer

Ich sehe gerade, in eurem Code ist noch ein Fehler drin: nach dem Aufruf von SendIO muß unbedingt WaitIO aufgerufen werden, bevor der IORequest wieder verwendet werden darf.

Korrekt muß es also so lauten:

code:
/* Die Uhr hat sich gemeldet... */
if(Signale & (1UL << TimerMP->mp_SigBit))
{
   WaitIO ((struct IORequest *) TimerIO);

   TimerIO->tr_node.io_Command = TR_GETSYSTIME;
   DoIO((struct IORequest *) TimerIO);


Gruß Thomas
--
Email: thomas-rapp@web.de
Home: thomas-rapp.homepage.t-online.de/

[ - Antworten - Zitieren - Direktlink - ]

26.06.2006, 13:45 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von thomas:

Ich sehe gerade, in eurem Code ist noch ein Fehler drin: nach dem Aufruf von SendIO muß unbedingt WaitIO aufgerufen werden, bevor der IORequest wieder verwendet werden darf.

Korrekt muß es also so lauten:

code:
/* Die Uhr hat sich gemeldet... */
if(Signale & (1UL << TimerMP->mp_SigBit))
{
   WaitIO ((struct IORequest *) TimerIO);

   TimerIO->tr_node.io_Command = TR_GETSYSTIME;
   DoIO((struct IORequest *) TimerIO);



Ja, mit "==" war Bockmist, Weiß auch nicht, wie ich da drauf gekommen bin, hier bei mir stehts richtig im Programm :glow:

Zum WaitIO(): Aus welchem Grund muß denn, wenn das timer.device das Signal gesetzt hat, nochmal extra auf Beendigung des Requests gewartet werden? Darf man nicht davon ausgehen, daß der Request bearbeitet wurde, wenn das gewünschte Signal eintrifft? Ich frage so dusslig, weil ich zum WaitIO() an dieser Stelle weder in den RKMs noch in den AutoDocs was finde...

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

26.06.2006, 13:47 Uhr

gni
Posts: 1106
Nutzer
Zitat:
thomas:
Korrekt muß es also so lauten:
code:
/* Die Uhr hat sich gemeldet... */
if(Signale & (1UL << TimerMP->mp_SigBit))
{
   WaitIO ((struct IORequest *) TimerIO);

   TimerIO->tr_node.io_Command = TR_GETSYSTIME;
   DoIO((struct IORequest *) TimerIO);


Und ohne Casts wäre es noch viel besser...

[ - Antworten - Zitieren - Direktlink - ]


1 -2- 3 4 [ - Beitrag schreiben - ]


amiga-news.de Forum > Programmierung > Gesucht: Sekundentakt [ - Suche - Neue Beiträge - Registrieren - Login - ]


.
Impressum | Datenschutzerklärung | Netiquette | Werbung | Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten.
.