Laden...

Gleichzeitig von zwei SerialPort lesen

Erstellt von ill_son vor 9 Jahren Letzter Beitrag vor 9 Jahren 805 Views
Hinweis von herbivore vor 9 Jahren

Titel geändert, das das eigentliche Problem das gleichzeitige Lesen ist, und kein Grund besteht, sich von Anfang an auf eine bestimmte Vorgehensweise festzulegen. Möglicherweise gibt es bessere Wege, um das Ziel zu erreichen.

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 9 Jahren
Gleichzeitig von zwei SerialPort lesen

Hallo,

ich versuche gerade folgendes Problem zu lösen. Ich möchte synchron von zwei SerialPorts lesen. Nun habe über die CurrentThreadID heraus gefunden, dass das Lesen zwar in einem separaten Thread passiert, dieser aber für beide Ports derselbe ist, was auch zum Verhalten passt, dass der zweite Port nicht reagiert, wenn der Erste Daten empfängt.
Deshalb habe ich folgendes versucht:


 private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
 {
     SerialPort port = sender as SerialPort;
     if (port != null)
     {
         if (!bwRead.IsBusy)
             bwRead.RunWorkerAsync(port);
     }
}

private void bwRead_DoWork(object sender, DoWorkEventArgs e)
{
     SerialPort port = e.Argument as SerialPort;
     ThreadedPortRead(port);
}

Dann funktioniert das gleichzeitige Lesen. Nun ergibt sich daraus aber das Problem, dass, wenn gerade gelesen wird und noch Daten hinzukommen, das Event Data-Received Event zwar ausgelöst wird, dies aber wegen bwRead.Busy ins Leere läuft. Kann mir jemand einen Hinweis geben, wie ich das am besten lösen kann. Warten auf !busy, wenn ja wie am elegantesten? Ich hatte noch überlegt, vor dem Lesen das Data_Received Event auszuhängen und dann im bw_Complete Event wieder zu abonnieren, in der Hoffnung, dass dann das Event kommt, wenn zwischenzeitlich Daten angefallen sind. Hab's aber noch nicht probiert.

Beste Grüße,

Alex

Final no hay nada más

F
10.010 Beiträge seit 2004
vor 9 Jahren

Wenn daten hinzukommen wärend du liest, machst du etwas grundsätzlich falsch im ThreadedPortRead.

Lies alle Daten in eine List<byte> und verarbeite sie dann erst, dann sind da auch keine klimmzüge notwendig.

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 9 Jahren

Hallo FZelle,

ich lese mit Read alle port.BytesToRead und schreibe sie in ein byte[]. Wenn ich im Debug-Mode anhalte vor dem Lesen, sozusagen bis alle Bytes reingepurtzelt sind, funktioniert das und das Event wird nur einmal ausgelöst. Ich möchte aber auch nicht den Theshold raufsetzen.

Grüße, Alex

Final no hay nada más

185 Beiträge seit 2005
vor 9 Jahren

Du must immer damit rechnen, das du die Daten nicht in einem rutsch einlesen kannst.

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 9 Jahren

Hallo Martin,

ich poste mal noch die Read-Methode. Ich lese in einen Ringpuffer ein, der bei Auftreten des Problems jedoch noch lange nicht übergelaufen ist.
Wie würdest Du sicherstellen, dass man alle Bytes erwischt beim lesen?


private void ThreadedPortRead(SerialPort port2ReadFrom)
{
    try
    {
        while (port2ReadFrom.BytesToRead > 0)
        {
            if (port2ReadFrom.IsOpen)
            {
                int bytes2Read = port2ReadFrom.BytesToRead;
                if (port2ReadFrom.BytesToRead <= this.portResult.BytesTillOverrun)
                       this.portResult.ReadBufferInCount += port2ReadFrom.Read(this.portResult.ReadBuffer, portResult.ReadBufferInCount, port2ReadFrom.BytesToRead);
                else
                {
                    this.portResult.ReadBufferInCount += port2ReadFrom.Read(this.portResult.ReadBuffer, portResult.ReadBufferInCount, this.portResult.BytesTillOverrun);
                   this.portResult.ReadBufferInCount += port2ReadFrom.Read(this.portResult.ReadBuffer, portResult.ReadBufferInCount, port2ReadFrom.BytesToRead);
                }
                this.transmissionState.Progress = this.portResult.ReadBufferInCount;
            }
        }
    }
    catch (Exception exc) { /*throw new Exception(exc.Message, exc);*/ }
}

Grüße, Alex

Final no hay nada más

W
123 Beiträge seit 2008
vor 9 Jahren

Wie würdest Du sicherstellen, dass man alle Bytes erwischt beim lesen?

Das sollte eigentlich durch das Datenübertragungsprotokoll sichergestellt werden, dass entsprechende Infos über Anfang/Ende oder Länge eines Datenblocks enthält.

Gruß
wolpertinger

I
ill_son Themenstarter:in
227 Beiträge seit 2009
vor 9 Jahren

Das mache ich auch. Ich verwende das KISS-Protokoll. Das ist aber eine Schicht drüber. Meine Frage war eher, wie ich feststelle, dass der komplette Puffer ausgelesen wurde. Ich prüfe ja BytesToRead, aber das schein nicht zu genügen.

Könnte man nicht statt des Backgroundworkers einen normalen Thread nehmen und den ganzen Port darin kapseln und so das Problem irgendwie umschiffen? Wenn ich ohne den Backgroundworker arbeite, funktioniert alles prima, nur kann ich dann icht beide Port simultan lesen.

Grüße, Alex

Final no hay nada más

F
10.010 Beiträge seit 2004
vor 9 Jahren

Evtl solltest du nochmal genau schauen wozu ein BGW ist.
Der ist dazu da mit einer UI zu kommunizieren wärend nebenläufige Aufgaben zu erledigen sind.

Aber dein problem ist wohl eher das du nicht verstanden hast wie das überhaupt zusammenhängt.

port_DataReceived wird in einem ThreadpoolThread ausgeführt, das heisst das die Daten hier bereits nebenläufig zu dir kommen.

Jetzt musst du hier doch nur die Daten auslesen, an eine List<Byte> hängen ( warum array? oder Ringbuffer? ) und die routine wieder verlassen.

Ein weiterer Thread oder besser Task kann sich jetzt um die Daten kümmern.

Ich denke du machst es dir viel komplizierter als es sein muss.


Dictionary<SerialPort, List<byte>> DataList = new Dictionary<SerialPort, List<byte>>();

..
DataList.Add(serialPort1, new List<byte>() );
DataList.Add(serialPort2, new List<byte>() );
..

void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    SerialPort port = sender as SerialPort;
	List<byte>	currentList = DataList[port];
		
	int BytesToRead = port.BytesToRead;
	byte[] buffer= new byte[BytesToRead];
	int BytesCount = portRead(buffer, 0, BytesToRead);
	currentList.Add(buffer);
}

Jetzt sind die Daten in den Listen.
Die Verarbeitung machst du jetzt in einem anderen Task, den du benachrichtigen kannst.