Frage

Ich sende / Daten über eine serielle Schnittstelle in Linux empfangen, und ich möchte die Verzögerung zwischen Zeichen finden.

Modbus verwendet einen 3,5 Zeichenverzugs Nachricht Rahmengrenzen zu erkennen. Wenn es mehr als eine 1,5 Zeichen Verzögerung ist, wird der Nachrichtenrahmen für unvollständig erklärt.

Ich bin ein schnelles Programm in C schreiben, die im Grunde ist

fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
// setup newtio
....
tcsetattr(fd, TCSANOW, &newtio);
for(;;) {
    res = read(fs, buf, 1);
    if (res > 0) {
        // store time in milliseconds?
        //do stuff
    }
}

Gibt es eine Möglichkeit, die Zeit hier die Messung? Oder muß ich bei Abrufen von Daten aus der seriellen Leitung in einem anderen Weg suchen müssen?

Ich habe auch Einhaken in SIGIO versucht, ein Signal zu erhalten, wann immer Daten gibt es aber ich scheine Daten 8 Bytes zu einer Zeit zu erhalten.

(ja, ich weiß, gibt es einige modbus Bibliotheken, aber ich möchte dies in anderen Anwendungen verwenden)

War es hilfreich?

Lösung

MODbus wie viele alte Protokolle und hasst wirklich moderne Hardware.

Der Grund, Sie bekommen 8 Bytes zu einer Zeit ist: Ihr PC hat einen (mindestens) 16 byteseriell FIFO auf Empfangs- und Sende, in der Hardware. Die meisten sind 64Byte oder größer.

Es ist möglich über das uart Gerät zu Zeit zu erzählen und gibt ein nach einer Reihe von char mal empfangenen Interrupt.

Der Trigger Level ist einstellbar, aber die Low-Level-Treiber setzt es "intelligent". versuchen, Low-Latency-Modus unter Verwendung von setserial) Sie können in den seriellen Treiber mit dem Code Geige, wenn Sie müssen. Google es (jugendfreie Inhalte Warnung), ist es nicht schön.

so die Routine ist als Pseudo-Code

int actual=read (packet, timeout of 1.5 chars)

look at actual # of received bytes

if less than a packet, has issues, discard.

nicht groß.

Andere Tipps

Die einfache Antwort ist ... Sie können nicht (nicht ohne Schreiben Sie besitzen serielle Treiber)!

Wenn Sie eine MODBUS schreiben Master es einige Hoffnung ist: Sie entweder das Ende einer Slave-Antwort durch das Warten erkennen kann, jeder Menge an Zeit (sofern seine mehr als 3.5 Zeichen), ohne etwas zu empfangen (wählen (2) können Sie sich hier) helfen, oder indem man die Antwort on the fly Parsen, wie Sie es (die zweite Methode Abfälle viel weniger Zeit) lesen. Sie müssen auch vorsichtig sein, zu warten, mindestens 3.5 Zeichen-Zeit, bevor eine neue Anfrage zu senden starrt, nach der Antwort auf die vorherige Anfrage erhalten. „Wenigstens“ ist hier wirksam! Warten mehr spielt keine Rolle. Warten weniger der Fall ist.

Wenn Sie eine MODBUS ein Schreiben von Sklave dann Sie‘re aus Glück . Sie einfach kann nicht tut es zuverlässig von Anwenderseite Linux. Sie müssen schreiben Sie serielle Treiber besitzen.

BTW, ist dieser Fehler ist nicht Linux. Dies ist auf die unglaubliche Dummheit des MODBUS des Framing-Methode.

Ich glaube, Sie über das den falschen Weg gehen. Es gibt einen Mechanismus eingebaut ist, um sicherzustellen, dass die Zeichen in allen zusammen kommen.

Grundsätzlich Sie gehen ioctl() verwenden wollen und die VMIN und VTIME Parameter entsprechend gesetzt. In diesem Fall scheint es, wie Sie VMIN (Mindestanzahl von Zeichen in einem Paket) wollen würden 0 und VTIME (Mindestzeitraum zwischen Zeichen erlaubt seinem 15 zu sein (sie sind Zehntelsekunden).

Einige wirklich Grundbeispielcode:

struct termio t;
t.c_cc[ VMIN ] = 0;
t.c_cc[ VTIME ] = 15;
if (ioctl( fd, TCSETAW, &t ) == -1)
{
    printf( msg, "ioctl(set) failed on port %s. Exiting...", yourPort);
    exit( 1 );
}

Tun Sie dies, bevor Sie Ihre open() aber vor Ihrer read(). Ist hier ein paar Links, dass ich wild hilfreich:

Serien Programming Guide

Verständnis VMIN und VMAX

Ich hoffe, dass zumindest hilft / Punkte, die Sie in der richtigen Richtung, auch wenn es nicht eine perfekte Antwort auf Ihre Frage ist.

Sie können nicht Timeouts verwenden. Auf höheren Baudraten 3,5 Zeichen Timeout bedeutet, ein paar Millisekunden oder sogar Hunderte von Mikrosekunden. Solche Timeouts können im Linux-User-Space nicht behandelt werden.

Auf der Client-Seite ist es kein großes Problem, da Modbus keine asynchronen Nachrichten senden. So ist es nicht an Sie bis senden 2 aufeinanderfolgende Nachrichten innerhalb von 3,5 Zeichen Timeout.

Auf der Serverseite, das Problem ist, dass, wenn Sie Ihren Kunden eine extrem kurze Reaktions Timeouts haben und Linux ist zu beschäftigt, nicht eine kugelsichere Framing Lösung schreiben kann. Es gibt eine Chance, dass read () Funktion mehr zurückkehren wird als ein Paket. Hier ist (ein wenig gekünstelt) Beispiel.

  1. Client schreibt ein Paket an Server. Timeout ist lasst uns 20 ms sagen.

  2. Lassen Sie uns sagen, dass Linux im Moment sehr beschäftigt, so Kernel Thread innerhalb der nächsten 50 ms nicht aufwacht.

  3. Nach 20 ms Client erkennt, dass sie keine Antwort erhalten haben, so dass es ein weiteres Paket an den Server sendet (vielleicht die vorherige übel nehmen).

  4. Wenn Linux weckt den Lesefaden nach 50 ms auf, lesen () Funktion 2-Pakete bekommen oder sogar 1 und die Hälfte je nachdem, wie viele Bytes durch die seriellen Port-Treiber empfangen wurden.

In meiner Implementierung verwende ich eine einfache Methode, die versucht, Parse-Bytes on-the-fly - zuerst den Funktionscode zu erfassen und dann versuche ich, alle verbleibenden Bytes für eine bestimmte Funktion zu lesen. Wenn ich die Eineinhalb Paket bekommen analysiere ich nur die ersten und die verbleibenden Bytes in dem Puffer belassen. Wenn mehr Bytes innerhalb einer kurzen Timeout kommen füge ich sie und versuchen zu analysieren, sonst ich sie verwerfen. Es ist keine perfekte Lösung (zum Beispiel einige Untercodes für die Funktion 8 keine feste Größe haben), aber da MODBUS RTU keine STX ETX-Zeichen haben, ist es das beste, ich in der Lage waren, um herauszufinden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top