amiga-news DEUTSCHE VERSION
.
Links| Forums| Comments| Report news
.
Chat| Polls| Newsticker| Archive
.

amiga-news.de Forum > Programmierung > SDCMD_QUERY-io_Actual [ - Search - New posts - Register - Login - ]

-1- [ - Post reply - ]

2007-01-16, 17:12 h

MaikG
Posts: 5172
User
Wie verwendet man SDCMD_QUERY richtig?
Ich rufe es auf um zu erfahren wieviel Bytes im Puffer sind,
sind es nicht soviele wie ich erwarte rufe ich es wieder auf,
solange bis die gewünschte Anzahl von Bytes da ist.
Auf meinem 060 ist das auch gar kein Problem, aber auf einem 020 geht
das nicht, da kommt eine zeit gar nichts an und dann scheint es
einen Buffer overflow zu geben, wo dann nur noch müll rauskommt.

Im NDK hab ich gelesen(serial.device) man soll Query aufrufen und
wenn nichts da ist einen 1 Byte Read Request schicken und dann nochmal
Query aufrufen.

Da steht aber das es der beste weg ist, aber ist das auch Pflicht?

[ - Answer - Quote - Direct link - ]

2007-01-16, 17:41 h

VMC
Posts: 115
User
Hallo MaikG,

es ist so wie du oben beschrieben hast aus dem NDK.

Über das Query abfragen wieviel schon im Puffer des
Treibers an Daten liegt. Wenn es genug sind einfach
einen READ mit der Anzahl schicken die du brauchst.

Die meisten Programme handlen das indem Sie einen
READ für 1 Zeichen schicken, wenn der vom Device in
erhalt ausreichender Daten quitiert wird den READ
nochmal schicken mit der Anzahl von Daten auf die
du noch wartest.

Die Idee dahinter ist aufwendiges Pollen des Puffers
zu verhindern und sich quasi wecken zu lassen wenn
der 1 Zeichen READ Request erledigt ist. Wenn man
das noch verfeinert kann man parallel zu dem READ
auch noch einen eigenen Timer Request laufen lassen
um hierüber einen Timeout zu implementieren.

Mit freundlichen Grüßen,

Harald Frank

[ - Answer - Quote - Direct link - ]

2007-01-16, 18:05 h

geit
Posts: 332
[Former member]
Ich schätze mal der Grund warum Du Probleme auf dem 020 bekommst ist das Polling, das Du durch den ständigen Query erzeugst. Dein Task schluckt die Rechenzeit und wenn der Devicetask mal dran kommt, ist der Buffer voll.

Du solltest, wenn du schon eine auf query basierende Methode verwendest einen Timerwait oder Delay() durchführen.

Generell ist folgendes zu bevorzugen, wenn man nicht warten will. (abstraiert)

code:
do{

 if( CheckIO() ) {
  SendIO( CMD_READ, Length 1 );
 }

 sigs = Wait( 1<<portsignal | SIGBREAKF_CTRLC );

 if( sigs & (1<<portsignal) ) {
  if( CheckIO() ) {
   DoIO( SDCMD_QUERY );
   if( actual ) {
    DoIO( CMD_READ, Length actual);
    total += actual;
   }
  }
 }
} until( total >= wanted );


Ggf. natürlich nicht all actual bytes lesen, sondern nur noch die fehlenden Bytes.

Es wird gewartet, bis 1 Byte gelesen wurde und dann nachgesehen, ob weitere Bytes anliegen, die man dann abholt. Wenn man sicher ist, dass mehrere Daten kommen, kann man natürlich statt einem Byte auch 100 oder 1000 lesen.

Der Query sollte nur verwendet werden, um nicht mehr Daten zu lesen, als bereits vorhanden sind.

Dinge wie

While( actual < 100 ) { DoIO( SDCMD_QUERY ); }

sollte man natürlich vermeiden, weil man eine Endlosschleife mit 100% Tasklast verursacht, bis alle Daten komplett eintreffen. Selbst mit einem Delay() dazwischen ist das nicht so clever.

Mit dem asyncronen Lesen von einem Byte verhindert man, das man direkt in DoIO() wartet und zweitens bekommt man einen Trigger, der den eigenen Task bei eintreffen von Daten aufweckt.

Einfach gesagt, mit SDCMD_Query fragt man nach der Anzahl der *NOCH* im Puffer verbliebenen Daten *NACH* einem CMD_READ Event.

Geit

[ - Answer - Quote - Direct link - ]

2007-01-16, 19:21 h

MaikG
Posts: 5172
User
>Über das Query abfragen wieviel schon im Puffer des
>Treibers an Daten liegt. Wenn es genug sind einfach
>einen READ mit der Anzahl schicken die du brauchst.

Na dann bekomme ich einerseits einen enforcer Hit von der
vmcresource.libarary und andererseit kommt nur 1 Byte zu
wenig an hängt mein Programm und die Serielle Karte ist auch
auf dem anderen Port blockiert.

>Du solltest, wenn du schon eine auf query basierende Methode
>verwendest einen Timerwait oder Delay() durchführen.

Ja, aber nehmen wir an ich mache ein Delay und grade in der
Zeit läuft der Puffer voll, ist doch dann das selbe.

>Generell ist folgendes zu bevorzugen, wenn man nicht warten will.
>(abstraiert)

Also sowas ähnliches wie bei einem Fenster, das prinzip
kann ich erkennen, aber wie man nun wirklich auf einem
Port wartet weiss ich nicht.

>Einfach gesagt, mit SDCMD_Query fragt man nach der Anzahl der *NOCH* im Puffer verbliebenen Daten *NACH* einem CMD_READ Event.

Wenn jetzt aber 0 Bytes ankommen, weil meinetwegen einer das
kabelrauszieht hängt das auch.

[ - Answer - Quote - Direct link - ]

2007-01-16, 22:39 h

VMC
Posts: 115
User
@MaikG:

>Na dann bekomme ich einerseits einen enforcer Hit von der
>vmcresource.libarary und andererseit kommt nur 1 Byte zu
>wenig an hängt mein Programm und die Serielle Karte ist auch
>auf dem anderen Port blockiert.

hui, das ist doch schon mal eine Information :)

Also, von dem was du bisher geschrieben hast und der
Info hier würde ich sagen da ist irgendwie der von
dir verwendete IORequest Kaputt oder nicht richtig
initialisiert worden.

Wie genau erstellst du deinen IORequest? Hast du evtl.
ein Stück Sourcecode, weil vieleicht ist es nur ein
einfacher Fehler den man leicht sehen kann :)

Mit freundlichen Grüßen,

Harald Frank

[ - Answer - Quote - Direct link - ]

2007-01-16, 22:42 h

geit
Posts: 332
[Former member]
Zitat:
Original von MaikG:

>Einfach gesagt, mit SDCMD_Query fragt man nach der Anzahl der *NOCH* im Puffer verbliebenen Daten *NACH* einem CMD_READ Event.
Wenn jetzt aber 0 Bytes ankommen, weil meinetwegen einer das
kabelrauszieht hängt das auch.


Nein, eben nicht. Du startest mit SendIO einen ReadRequest von 1 Byte. Der SendIO() kehrt *sofort* zurück, darum machen wir das ja. DoIO() wartet gnadenlos bis zum Ende und wenn jemand das Kabel zieht ist das Programm tod.

Ob jemand das Kabel sieht oder nicht ist hier egal. Alles was du braucht ist ein Timer, den du zusätzlich vor dem Transfer startest und mit dem gleichen Wait() abfragst. Das habe ich mit dem Control-C oben angedeutet. Du kannst den Kram zu jederzeit abbrechen mit einem Timer würde dieses Abbrechen automatisch nach einiger Zeit passieren.

Wenn der Request ageschlossen ist und SDCMD_Query 200 Bytes ausgibt, dann ist ein CMD_READ über 200 Bytes sicher und zwar egal ob jemand ein Kabel zieht oder nicht. Die Daten sind ja schon im Rechner angekommen.

Zitat:
Original von MaikG:

Ja, aber nehmen wir an ich mache ein Delay und grade in der
Zeit läuft der Puffer voll, ist doch dann das selbe.


Nein, ich meine nicht einen Delay von Sekunden oder so, sondern einen Delay(1). Der verhindert, das der Task 100% Systemlast bekommt. Für Testzwecke zu empfehlen, aber für die finale Benutzung ehr nicht.

Geit

[ - Answer - Quote - Direct link - ]

2007-01-16, 23:41 h

MaikG
Posts: 5172
User
>Also, von dem was du bisher geschrieben hast und der
>Info hier würde ich sagen da ist irgendwie der von
>dir verwendete IORequest Kaputt oder nicht richtig
>initialisiert worden.


code:
Sub OpenSerialDevice
 port& = CreateMsgPort&()
 SerIO&=CreateIORequest&(port&,IOExtSer_sizeof%) 
 POKEB(SerIO&+io_ReadLen%), 8
 POKEB(SerIO&+io_WriteLen%),8
 device& = OpenDevice&(SADD(dev$), Unit&, SerIO&, 0&)
 IF device&<>0 THEN Fehlerausgabe("Kann "+LEFT$(dev$,LEN(dev$)-1)+" Unit"+STR$(unit&)+" nicht öffnen"):EXIT SUB
 POKEW(SerIO&+IORequestio_Command%), SDCMD_SETPARAMS&
 POKEL(SerIO&+io_Baud%), 115200
 POKEL(SerIO&+io_RBufLen%), 32768
 POKE(SerIO&+io_StopBits%), 1
 IF DoIO&(SerIO&) THEN Fehlerausgabe("Kann Serial Parimeter nicht setzten"):EXIT SUB
End Sub

FUNCTION SerInput&(BYVAL laenge&, buffer&)
 LOCAL in&
 t!=TIMER
 10 IF TIMER-t!>2 THEN EXIT FUNCTION
    POKEW(SerIO&+IORequestio_Command%), SDCMD_QUERY&
    junk&=DoIO&(SerIO&) 'Query Ist immer erfolgreich(NDK)
    in&=PEEKL(SerIO&+IOStdReqio_Actual%)
    IF in&>=laenge& OR in&>0 AND TIMER-t!>1 THEN
      POKEW(SerIO&+IORequestio_Command%), CMD_READ&
      POKEL(SerIO&+IOStdReqio_Length%),MIN(laenge&,in&)
      POKEL(SerIO&+IOStdReqio_Data%), buffer&
      IF DoIO&(SerIO&) THEN Fehlerausgabe("Fehler DOIO4"):EXIT FUNCTION
    ELSE GOTO 10
    END IF
    SerInput&=MIN(laenge&,in&)
END FUNCTION





>Wie genau erstellst du deinen IORequest? Hast du evtl.
>ein Stück Sourcecode, weil vieleicht ist es nur ein
>einfacher Fehler den man leicht sehen kann :)

Ja, klar, ist aber Basic. Diese Methode mit dem Anfordern der
Byteanzahl die benötigt wird zeigt die selbe Fehlfunktion.



>Nein, eben nicht. Du startest mit SendIO einen ReadRequest
>von 1 Byte. Der SendIO() kehrt *sofort* zurück, darum machen wir
>das ja. DoIO() wartet gnadenlos bis zum Ende und wenn jemand das
>Kabel zieht ist das Programm tod.

Ja, SendIO, aber wie warte ich auf das SendIO denn?

Fenster ist so:

code:
junk&= xWait&(1& << PEEKB(PEEKL(win&+UserPort%)+mp_SigBit%))



>Nein, ich meine nicht einen Delay von Sekunden oder so, sondern
>einen Delay(1). Der verhindert, das der Task 100% Systemlast
>bekommt. Für Testzwecke zu empfehlen, aber für die finale Benutzung
>ehr nicht.

Ich habe Delay 1, 5 und 10 Probiert, immer das selbe.
Dann hab ich die Taskpriorität des Programms auf -1 und -5 geändert,
nicht erfolgreich.
Immerhin konnte ich durch das abschalten aller Caches das ganze
auf meinem 68060 System reproduzieren.

[ - Answer - Quote - Direct link - ]

2007-01-17, 00:39 h

geit
Posts: 332
[Former member]
Zitat:
Original von MaikG:

>Nein, eben nicht. Du startest mit SendIO einen ReadRequest
>von 1 Byte. Der SendIO() kehrt *sofort* zurück, darum machen wir
>das ja. DoIO() wartet gnadenlos bis zum Ende und wenn jemand das
>Kabel zieht ist das Programm tod.

Ja, SendIO, aber wie warte ich auf das SendIO denn?

Fenster ist so:

code:
junk&= xWait&(1& << PEEKB(PEEKL(win&+UserPort%)+mp_SigBit%))




Genauso. Du hast ja den Port für den IOrequest allokiert. Den benutzt du genauso.

code:
junk&= xWait&(1& << PEEKB(PEEKL(win&+UserPort%)+mp_SigBit%) | 1& << PEEKB(PEEKL(port%)+mp_SigBit%))


Ist jetzt warscheinlich falsch, aber dieses Basic &% Zeugs versteh ich nicht wirklich. Du verschiebst eine
1 um die Signalnummer aus dem Port vom IORequest. Diese Maske oderst du z.B. zu dem Wert , den du aus dem
Fensterport emittelst. Dann wartet der Wait() auf beide Signale. Mit dem junk Feld und dem Masken Wert kannst
du dann geziehlt Abfragen, ob eines oder mehere der Signale aktiv sind und entsprechend handeln.


Zitat:
Original von MaikG:

>Nein, ich meine nicht einen Delay von Sekunden oder so, sondern
>einen Delay(1). Der verhindert, das der Task 100% Systemlast
>bekommt. Für Testzwecke zu empfehlen, aber für die finale Benutzung
>ehr nicht.

Ich habe Delay 1, 5 und 10 Probiert, immer das selbe.
Dann hab ich die Taskpriorität des Programms auf -1 und -5 geändert,
nicht erfolgreich.
Immerhin konnte ich durch das abschalten aller Caches das ganze
auf meinem 68060 System reproduzieren.


Sollte nicht sein. Wo hast du den eingebaut. Der sollte in "Zeile 10" oder direkt vor dem Goto nach 10 liegen, um bei jedem Schleifenumlauf zu wirken. Wie gesagt diese Lösung ist nicht perfekt und tuagt allenfalls für Testzwecke (wenn man keinen timer öffnen will).

Geit

[ - Answer - Quote - Direct link - ]

2007-01-17, 03:26 h

Holger
Posts: 8116
User
Zitat:
Original von geit:
code:
junk&= xWait&(1& << PEEKB(PEEKL(win&+UserPort%)+mp_SigBit%) | 1& << PEEKB(PEEKL(port%)+mp_SigBit%))


Ist jetzt warscheinlich falsch, aber dieses Basic &% Zeugs versteh ich nicht wirklich.


foo& ist eine 32 Bit Variable, bar% eine 16 Bit Variable. Dass die MB-includes mal das ein und mal das andere benutzen, ist nicht wirklich immer begründbar. Es gibt jedenfalls keine Unterschiedung zwischen Pointer und 32 Bit-Integer.

PEEKL(win&+UserPort%) ist vergleichbar mit win->UserPort in C und fällt für den Device-Port komplett weg.

Und dann gibt's vermutlich kein | in Basic, aber es gibt definitiv OR.

Also:
code:
junk&= xWait&((1& << PEEKB(PEEKL(win&+UserPort%)+mp_SigBit%)) OR (1& << PEEKB(port&+mp_SigBit%)))


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

[ - Answer - Quote - Direct link - ]

2007-01-17, 04:09 h

VMC
Posts: 115
User
@MaikG:

hallo und um das ganze ein wenig besser zu verstehen,
welches Device verwendest du denn genau (inkl. Version)
und welche Schnittstelle auf welchem Rechner versuchst
du damit anzusprechen?

Mit freundlichen Grüßen,

Harald Frank

[ - Answer - Quote - Direct link - ]

2007-01-17, 10:29 h

MaikG
Posts: 5172
User
>Genauso. Du hast ja den Port für den IOrequest allokiert. Den
>benutzt du genauso.

Stimmt, irgendwo müsste ich noch ein Beispiel für "auf Port warten"
haben.
Aber leider ist Query nicht das Problem, ich habs komplett
rausgenommen und immer genau die menge Byte angefordert die
ich brauche.


>Ist jetzt warscheinlich falsch, aber dieses Basic &% Zeugs versteh
>ich nicht wirklich.

% = integer
& = Long

>Sollte nicht sein. Wo hast du den eingebaut. Der sollte in "Zeile 10"
>oder direkt vor dem Goto nach 10 liegen, um bei jedem Schleifenumlauf
>zu wirken. Wie gesagt diese Lösung ist nicht perfekt und tuagt
>allenfalls für Testzwecke (wenn man keinen timer öffnen will).

vor dem Goto 10.

>hallo und um das ganze ein wenig besser zu verstehen,
>welches Device verwendest du denn genau (inkl. Version)
>und welche Schnittstelle auf welchem Rechner versuchst
>du damit anzusprechen?

hyperCOM3.device 2.98 (24.12.00)
SilverSurfer 2.104 (13.11.00)

serial.device 43.7 (25.02.02)

Obwohl das letzte für diese Baudrate ungeignet ist liefert
es die Daten die am nächsten am Original sind.

Rechner ist nicht wichtig 68060 @60MHZ, 68030 @50MHZ, 68020 @14MHZ.
Auf dem 060 mit Caches an geht es, ohne caches nicht, sowie
auf den anderen.

Der Datenaufbau ist folgender

0-807 Okay
807-3899 &hFF Fehlerhaft
Ende der Datei an falscher Position und unbekanntes
11612-20283 &hFF Fehlerhaft
Ende der Datei an falscher Position und unbekanntes
27996-36667 &hFF Fehlerhaft
Ende der Datei an falscher Pos und unbek.

usw.

Der Serial buffer hat 32768, von daher dürften die Daten erst
ab da falsch sein beim buffer Overrun.




[ - Answer - Quote - Direct link - ]

2007-01-17, 16:36 h

Holger
Posts: 8116
User
@MaikG:
So, wie ich das verstehe, soll Deine FUNCTION SerInput& einen Wert zurückliefern, wohl die Anzahl gelesener bytes. Ich sehe aber mindestens zwei EXIT FUNCTION Anweisungen, bei denen keinerlei Rückgabewert angegeben wird. Was wird da an den Aufrufer zurückgegeben? Schon mal überprüft?

Außerdem beginnt Deine Funktion bereits mit
t!=TIMER
10 IF TIMER-t!>2 THEN EXIT FUNCTION

Auch wenn die Wahrscheinlichkeit sehr gering ist, dass zwischen diesen Anweisungen 2 Sekunden vergehen, ist es doch eine Annahme, die man in einem Multitasking-System nicht treffen sollte. Schon gar nicht, wenn man Probleme auf langsamen Rechnern, die zudem mit serieller Daten bombardiert werden, feststellt.

Die Routine sollte wenigstens einmal abgefragt haben, ob Daten anliegen, unabhängig von der Systemzeit.

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

[ - Answer - Quote - Direct link - ]

2007-01-17, 18:30 h

MaikG
Posts: 5172
User
>@MaikG:
>So, wie ich das verstehe, soll Deine FUNCTION SerInput& einen Wert
>zurückliefern, wohl die Anzahl gelesener bytes. Ich sehe aber
>mindestens zwei EXIT FUNCTION Anweisungen, bei denen keinerlei
>Rückgabewert angegeben wird. Was wird da an den Aufrufer
>zurückgegeben? Schon mal überprüft?

Bei MB ist das dann ein wert im Negativen bereich.
Bei einigen sachen im Programm wird die Länge überprüft, wenn
diese unerwartet ist wird eine Fehlermeldung ausgegeben.
Der rest prüft die länge gar nicht und daher macht Negativ dann
auch nichts.

>Außerdem beginnt Deine Funktion bereits mit
>t!=TIMER
>10 IF TIMER-t!>2 THEN EXIT FUNCTION
>Auch wenn die Wahrscheinlichkeit sehr gering ist, dass zwischen
>diesen Anweisungen 2 Sekunden vergehen, ist es doch eine Annahme,
>die man in einem Multitasking-System nicht treffen sollte.
>Schon gar nicht, wenn man Probleme auf langsamen Rechnern, die
>zudem mit serieller Daten bombardiert werden, feststellt.

Ja, das stimmt, ich werde das mal korregieren.

[ - Answer - Quote - Direct link - ]

2007-01-17, 19:20 h

Holger
Posts: 8116
User
Zitat:
Original von MaikG:
Bei MB ist das dann ein wert im Negativen bereich.


Irgendein Wert im negativen Bereich?! Steht das so im Handbuch oder irgendeiner Spezifikation?
Oder nimmst Du an, dass er immer negativ ist, nur weil der nicht initialisierte, sprich zufällige Wert bei Deinem ersten Test gerade negativ war?

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

[ - Answer - Quote - Direct link - ]

2007-01-17, 21:40 h

MaikG
Posts: 5172
User
>Irgendein Wert im negativen Bereich?! Steht das so im Handbuch oder
>irgendeiner Spezifikation?

Ich hab das kürzlich bei einem anderen Programm ausprobiert,
da war der Rückgabewert undefiniert und ich bekam immer die
gleiche Zahl.

Also ich hab mein Programm jetzt normal Optimiert,
auch den Cluser von 1024 Bytes auf 2048,4096, 8192 und 16384
erhöht ohne erfolg.

Interressant ist der Serial Puffer zustand:

Puffer Angeforderte Bytes

0 2
0 2
0 2
0 2
0 2
0 2
0 2
0 2
0 2
0 2
0 2
0 2
2 2
0 217
0 217
0 217
0 217
0 217
0 217
0 217
0 217 - ca. Hier stragniert der Statusbalken was normal
185301 217 - nicht so ist, Maus cursor hängt in der Zeit
185084 807
184277 8192
176085 8192

usw.

Einmal ist der Serialpuffer auf 31k eingestellt und sollte
daher 1853084 nie erreichen können. Dann ist fraglich warum an
dieser stelle auf einmal so eine CPU Last ist und warum der
Puffer dann nicht gelert werden kann.

[ - Answer - Quote - Direct link - ]


-1- [ - Post reply - ]


amiga-news.de Forum > Programmierung > SDCMD_QUERY-io_Actual [ - Search - New posts - Register - Login - ]


.
Masthead | Privacy policy | Netiquette | Advertising | Contact
Copyright © 1998-2024 by amiga-news.de - all rights reserved.
.