String an der COM-Schnittstelle

hallo,
habe heute mal einPHP Problem.
ich lese Daten von der seriellen Schnittstelle. das funktioniert auch bis jetzt sehr gut.

$mein_string  = GetValueString("test");

/* Sowohl das Tabulator- als auch das 
   Leerzeichen als Token zum Zerlegen verwendet */

$tok = strtok($mein_string, "	");
  $i=0;

while ($tok !== false) {
      $temp[$i]=$tok;
    $tok = strtok("	");
      $i++;

}
     $i=0;
   settype($temp[],"float");
   for($i=0; $i<2;$i++) {
      $temp[$i]=$temp[$i]/10;

      }

Wie man sieht, kommt immer nur ein Datensatz an, der als String weiterbehandelt wird. Soweit , sogut.

Jetzt möchte ich fünf Datensätze von der Com-Schnittstelle lesen . Wie fange ich das am besten an?

Grüße

Wolfi

keiner, da der mich versteht?

iich will einfach nur fünf Strings die durch "
\r " getrennt sind und hintereinander an der COM anliegen, lesen. Bei oben aufgführter Methode klappt das nicht. Da liest man nur einen String.

KEIN wISSENENDER hier?

Grüße

Wolfi

Hallo Wolfi,
wenn ich dich recht verstehe, stehen im String 5 Datensätze drin. Also per Schleife einen Datensatzt nach dem anderem aus dem String lesen.


  $mein_string = GetValueString ("test");

  for ($nIndex=0; $nIndex<5; $nIndex++)
  {
    .... // hier deine Codezeilen einfügen
  }

Das „$temp[$i]“ müßte dann noch zwei Dimensional angelegt werden, also „$temp[$nIndex][$i]“.
Vielleicht hlift dir das.

Grüße,
Jörg

ne, ich glaube das ist anders,

es kommen 5 strings getrnnt durch carriage return auf der com an.

ich probiere jetzt aber erst mal deinen Code

Wolfi

for ($nIndex=0; $nIndex<5; $nIndex++)
    $mein_string[$nIndex]  = GetValueString("test");

    echo    $mein_string[1],"    ",$mein_string[2],"    ",$mein_string[3];

die Strings auf der COM vom Sender sehen so aus:

A1:wert1
A2:wert2
A3:wert3
A4:wert4
A5:wert5

Meine empfangenen Strings sind jedoch immer gleich
A5:wert5 A5:wert5 A5:wert5

Wolfi

Guck dir mal den CutChars Splitter an. Der macht genau das ohne eine Zeile Code.

Dann ist die Reihenfolge so:

ComPort -> CutChars -> RegisterVariable

paresy

@paresey

genau so mache ich es z.Zt.

das Problem liegt offentsichtlich im Timing.
Im Debugger sieht es so aus,:
…Variablenmanager variable test(string),Value: a1:0
…Variablenmanager variable test(string),Value: a2:0
…Variablenmanager variable test(string),Value: a3:123
…Variablenmanager variable test(string),Value: a4:245
Ich kann offentsichtlich die Variable nicht schnell genug abfragen. sie wird dann vom nächsten wert schon wieder überschrieben.

Grüße

Wolfi

Hallo Wolfi,

das Problem mit der seriellen Schnittstelle liegt darin, dass man nicht vorhersehen kann, wann der Trigger wirklich erfolgt. Windows liefert die Daten meist dann, wenn sein interner Puffer zu einem bestimmten Prozentsatz gefüllt ist oder wenn nach dem letzten Zeichen ein Timeout eingetreten ist. Dadurch werden die Daten in kleineren Portionen an IPS übergeben, wobei jedesmal ein Schreibzugriff auf die Registervariable und somit auch ein OnUpdate Trigger eintritt. Leider kann man daraus häufig keine Zuordnung zwischen Datensatz und Trigger ableiten. Man kann also nicht sagen, dass nach dem ersten Trigger der erste Datensatz ansteht und nach dem zweiten der nächste usw. Die Trigger können durchaus auch mittendrin auftreten. Es ist daher meist nötig, den Datenstrom erst einmal aufzusammeln und ihn anschließend zu trennen.

Eigentlich sollte das von Paresy vorgeschlagene Verfahren funktionieren. Falls nicht, dann versuche mal folgendes:

  1. den COM-Port direkt mit der Registervariablen verbinden, ohne CutChars
  2. die Registervariable im „Append“-Modus betreiben
  3. das zugehörige Skript von der Registervariablen OnUpdate triggern lassen
  4. im Skript eine Wartezeit (z.B. 500ms) einfügen, um dem Datenstrom Zeit zu geben vollständig einzutreffen
  5. dann erst die Registervariable mit GetValueString(…) auslesen (nicht mit $IPS_VALUE !)
  6. nach dem Auslesen nicht vergessen, die Registervariable wieder zu löschen
  7. den ausgelesenen String mit explode("
    ", String) aufsplitten (explode liefert ein Array mit den Teil-Strings)
IPS_Sleep(500);
$regvar = "Name der Registervariablen";
$data = GetValueString($regvar);
SetValueString($regvar, "");

$datasets = explode("
", $data); // String in Zeilen zerlegen

$dataset1 = $datasets[0];
$set1 = explode(":", $dataset1);    // am Doppelpunkt trennen
$var1 = $set1[0];                   // sollte "A1" enthalten
$value1 = $set1[1];                 // sollte den Wert von A1 enthalten

$dataset2 = $datasets[1];
$set2 = explode(":", $dataset1);
$var2 = $set2[0];
$value2 = $set2[1];

$dataset3 = $datasets[2];
$set3 = explode(":", $dataset1);
$var3 = $set3[0];
$value3 = $set3[1];

$dataset4 = $datasets[3];
$set4 = explode(":", $dataset1);
$var4 = $set4[0];
$value4 = $set4[1];

$dataset5 = $datasets[4];
$set5 = explode(":", $dataset1);
$var5 = $set5[0];
$value5 = $set5[1];

Der Vollständigkeit halber müsste man das Skript noch vor Mehrfachtriggerung schützen. Aber das kannst Du erst einmal weglassen.

Gruß
HJH

mach mal im Script ein


echo $IPS_VALUE;

Dann hast du den Wert, den du haben willst :wink:

Register Variable muss im Overwrite Modus stehen.

paresy

Hallo,

Paresy, das verstehe ich nicht ganz. Für mich ergibt sich dann folgender Ablauf:

[ol]
[li]ComPort kann nicht gewährleisten, dass immer ein ganzer Datensatz auf einmal weitergegeben wird.
[/li][li]RegisterVariable empfängt dann das Datensatzfragment.
[/li][li]Zielvariable wird mit dem Fragment beschrieben.
[/li][li]PHP kann das natürlich nicht auswerten.
[/li][li]ComPort liefert Rest des Datensatz.
[/li][li]RegisterVariable überschreibt damit im Overwrite-Modus die Var.
[/li][li]PHP kann erst nichts auswerten -> Datensatz verloren!
[/li][/ol]
Habe ich da einen Überlegungsfehler?:confused: Kannst Du das mal etwas erläutern, damit wir den richtigen Weg zum Ziel finden.

Ich betreibe das bei mir auch im Append-Modus und warte einfach, bis ein ganzer Datensatz zusammengekommen ist. Dann wird er ausgewertet und aus der Quellvariable entfernt.

Gruß
Erich

Der Trick ist, dass zwischen ComPort <> RegisterVariable ein CutChars Splitter hängt

paresy

Hallo Erich,

wie schon oben erwähnt sollte das von Paresy beschriebene verfahren problemlos funktionieren.

Es basiert auf dem „Overwrite“-Modus der Registervariablen. Zusätzlich wird hier auch das CutChars-Modul benötigt. Der Ablauf ist etwa so:

  1. der COM-Port liefert „häppchenweise“ Daten an das CutChars-Modul
  2. das CutChars-Modul wartet auf einen CutChar (z.B. CR)
  3. wurde vom CutChars-Modul ein CutChar empfangen, werden alle bis dahin empfangenen Daten an die Registervariable weitergereicht
  4. die Übergabe an die Registervariable ist ein Schreibvorgang und stellt damit ein Trigger-Ereignis dar
  5. das zugehörige Skript wird gestartet
  6. die System-Variable $IPS_VALUE enthält dann den Datensatz (ohne den CutChar)

Das Overwrite-Verfahren erfordert ein eindeutiges Kriterium, anhand dessen der Datenstrom zuverlässig an der gewünschten Stelle unterteilt werden kann. In diesem Falle ist das CR-Zeichen das geeignete Kriterium. Die Unterteilung übernimmt das CutChars-Modul. Es funktioniert aber auch ohne CutChars, wenn sich zwischen den einzelnen Datensätzen eine kurze Pause befindet.

Das „Append“-Verfahren hat den Nachteil, dass man per Skript alles „zu Fuß“ erledigen muss. Dafür funktioniert es aber immer. Man muss allerdings wissen, was man zu tun hat.

Gruß
HJH

Danke paresy,
Danke HJH,

mir war das mit den CutChars nicht so ganz klar. Werde glaube ich mal meine Empfangsroutinen etwas verbessern :smiley:

Gruß
Erich

Hallo,
vielen Dank an alle die sich hier für mich Gedanken gemacht haben.

Meine Lösung funktioniert jetzt folgendermaßen:

Script wird immer dann ausgeführt, wenn an der COM-Schnittstelle sich etwas tut.
D.h. es wird auf die Registervariable Test getriggert.
Die Registervariable ist im Mode override und split = CR

@Paresey: was meinst du mit echo IPS_value??

Grüße

Wolfi

Siehe dazu: http://www.ipsymcon.de/~hjh/HelpStudio/html/IPS-Manual/Variablen.html
Das macht es verständlich, denke ich…