Forum: Mikrocontroller und Digitale Elektronik Bytes von der Seriellen Schnittstelle lesen


von Jan H. (janiiix3)


Lesenswert?

Moin Moin,

es dreht sich zwar um eine PC Anwendung aber es hat jedoch viel mehr mit 
der Logik zu tun als mit dem PC.. Daher poste ich jetzt mein Problem 
einfach mal hier..

Ich empfange von einem µC Kommandos. Diese sind verschieden lang.
So sieht mein Protokoll aus.
1
        /* Protokoll
2
            *
3
            *  Startbyte[0]                    : '-'
4
            *  Startbyte[1]                    : '+'
5
            *  Nachrichtenlänge[2]             : 0..255
6
            *  Anzahl Nutzdaten[3]             : 0..255
7
            *  Daten Type[4]                   : 0..6
8
            *  Nachrichten Identifikation[5]   : 0..255
9
            *  Funktionsrückgabe Code[6]       : 0..255
10
            *  Checksumme[7]                   : 0..255
11
            *  Nutzdaten[8..n]                 : 0..255
12
        */

Ich versuche jeden Befehl anhand der beiden "Startbytes" zu erkennen.
Nach den beiden "Startbytes" kommt dann die Länge des ganzen Frames.
Solange ich diese Daten nicht empfangen habe, ist auch noch kein 
"gültiges" Kommando im Speicher.

Das ganze klappt nicht zuverlässig. Mal werden Kommandos erkannt, mal 
nicht. Ich gehe 100 % nicht richtig vor. Es scheitert bei Mir an der 
Logik..
1
    int Length = 0;
2
    byte[] buffer = new byte[1024];
3
    public void Client_DataReceived(object sender, SerialDataReceivedEventArgs e)
4
    {
5
        /* Protokoll
6
            *
7
            *  Startbyte[0]                    : '-'
8
            *  Startbyte[1]                    : '+'
9
            *  Nachrichtenlänge[2]             : 0..255
10
            *  Anzahl Nutzdaten[3]             : 0..255
11
            *  Daten Type[4]                   : 0..6
12
            *  Nachrichten Identifikation[5]   : 0..255
13
            *  Funktionsrückgabe Code[6]       : 0..255
14
            *  Checksumme[7]                   : 0..255
15
            *  Nutzdaten[8..n]                 : 0..255
16
        */
17
18
        /*  Empfangene Daten abholen
19
        */
20
        try
21
        {
22
            Length += Client.Read(buffer, Length , Client.BytesToRead);
23
24
        }
25
        catch
26
        {
27
            return;
28
        }
29
    }

Hier werden die Daten in den "buffer" geschrieben..

Das habe ich bisher selbst geschafft..
1
    private int SearchCommandoFrame( byte[] buffer )
2
    {
3
        int x = 0;
4
        for ( x = 0; x < buffer.Length ; x++ )
5
        {
6
            if ( buffer[x] == (char)'-')
7
            {
8
                if ( buffer[x+1] == (char)'+')
9
                {
10
                    return x;
11
                }
12
            }
13
        }
14
15
        return -1;
16
    }
17
18
    private int GetCommandoLength( byte[] buffer )
19
    {
20
        int Length = 0;
21
22
        int FrameStartIndex = SearchCommandoFrame(buffer);
23
        if (FrameStartIndex != - 1)
24
        {
25
            Length = buffer[FrameStartIndex + 2];
26
            return Length;
27
        }
28
29
        return -1;
30
    }
Wie sollte ich vorgehen?!

von Andreas K. (andreasmc)


Lesenswert?

Lass dir mal den Puffer ausgeben wenn die Kommandos nicht erkannt 
werden.
Der Puffer wird nach jedem Kommando geleert?
Der Controller sendet die Kommandos so langsam dass der PC ein Kommando 
sicher abgearbeitet hat bevor das nächste kommt?

von Jan H. (janiiix3)


Lesenswert?

Andreas K. schrieb:
> Lass dir mal den Puffer ausgeben wenn die Kommandos nicht erkannt
> werden.
> Der Puffer wird nach jedem Kommando geleert?
> Der Controller sendet die Kommandos so langsam dass der PC ein Kommando
> sicher abgearbeitet hat bevor das nächste kommt?

Mein ganzes Vorgehen ist einfach nur für den Ars***..

von georg (Gast)


Lesenswert?

Jan H. schrieb:
> /* Protokoll
>             *
>             *  Startbyte[0]                    : '-'
>             *  Startbyte[1]                    : '+'
>             *  Nachrichtenlänge[2]             : 0..255

Das kann auch nicht funktionieren. Damit Startbytes zuverlässig erkannt 
werden, dürfen sie im den restlichen Daten nicht vorkommen. Ein gültiges 
Protokoll besteht z.B. aus einem Startbyte STX und Daten nur aus 
lesbaren ASCII-Zeichen wie Ziffern und Buchstaben - dann kann das 
Startzeichen nicht in den Daten vorkommen. Es gibt auch viele andere 
Möglichkeiten eindeutig zu kodieren. Für das Ende, z.B. EOT, ETX, CR, 
gilt das Gleiche.

Wird nicht zwischen Start/Stop und Nutzdaten unterschieden, kann die 
Software falsche Start- oder Stopbedingungen erkennen.

Georg

von Jan H. (janiiix3)


Lesenswert?

georg schrieb:
> Wird nicht zwischen Start/Stop und Nutzdaten unterschieden, kann die
> Software falsche Start- oder Stopbedingungen erkennen.

Ich bin offen für gute Ideen. Also lieber nicht die Länge mitgeben, 
dafür ein End Byte?

von Stefan F. (Gast)


Lesenswert?

Ich nehme an, dass es um einen TCP Datenstrom geht. Du liest diesen 
Blockweise in deinen Buffer und wertest ihn aus. Dabei gehst du davon 
aus, dass der Block beim Empfänger so ankommt, wie er gesendet wurde.

Das ist aber reine Glücks-Sache. Es wird nur im lokalen Netz zuverlässig 
funktionieren - wenn überhaupt.

Du musst immer davon ausgehen, dass diene Blöcke von den 
Netzwerk-Geräten in mehrere kleine zerstückelt werden und dass diese 
wiederum in anderen Gruppierungen zusammengefügt werden.

Das heißt für deine Anwendung, dass du nach dem Empfang der 
"Nachrichtenlänge" so lange hereinkommende Daten einsammeln musst, bis 
diese Länge tatsächlich empfangen wurde.

Paketorientierte Übermittlung macht man übrigens besser mit dem UDP 
Protokoll. Damit kannst du 1kB (eventuell auch etwas mehr) sicher am 
Stück übermitteln. UDP stellt sicher, dass das ganze Paket entweder am 
Stück ankommt, oder komplett verloren geht. Bei UDP fehlt allerdings 
eine automatische Wiederholung der Übertragung  nach Paketverlust. Die 
müsstest du ggf. selbst implementieren.

von Jan H. (janiiix3)


Lesenswert?

Es geht rein um die Serielle Schnittstelle. Ich kann nicht erwarten, 
dass wenn ich etwas empfangen habe, das auch wirklich das komplette 
Kommando schon angekommen ist das ist glaube ich das größte Problem

von Stefan F. (Gast)


Lesenswert?

Jan H. schrieb:
> Es geht rein um die Serielle Schnittstelle.

Ach so.

> Ich kann nicht erwarten,
> dass wenn ich etwas empfangen habe, das auch wirklich das komplette
> Kommando schon angekommen ist das ist glaube ich das größte Problem

Ja.

von yesitsme (Gast)


Lesenswert?

Hast du mal ein komplettes Beispiel, das man auch compilieren kann?

Irgendwie seh ich nicht, wie der Buffer wieder geleert wird.

von Kalle O. (Gast)


Lesenswert?

yesitsme schrieb:
> Hast du mal ein komplettes Beispiel, das man auch compilieren
> kann?
>
> Irgendwie seh ich nicht, wie der Buffer wieder geleert wird.

Bringt dir ja nichts da du die Hardware nicht hast.

von Jan H. (janiiix3)


Lesenswert?

Ja das stimmt.
Eigentlich sollte es ja so ne art Ringbuffer sein, wo die ganzen 
Kommandos landen.

von Jan H. (janiiix3)


Lesenswert?

georg schrieb:
> Jan H. schrieb:
> /* Protokoll
>             *
>             *  Startbyte[0]                    : '-'
>             *  Startbyte[1]                    : '+'
>             *  Nachrichtenlänge[2]             : 0..255
>
> Das kann auch nicht funktionieren. Damit Startbytes zuverlässig erkannt
> werden, dürfen sie im den restlichen Daten nicht vorkommen
> Georg
Dafür habe ich ja auch einen Header dort stehen die Infos drin. Dieser 
hat eine bestimmte Länge. Klar kann das auch mal in die Hose gehen.. Ist 
aber sicherer als ohne Start Bytes..

von Theor (Gast)


Lesenswert?

Jan H. schrieb:
> georg schrieb:
>> Wird nicht zwischen Start/Stop und Nutzdaten unterschieden, kann die
>> Software falsche Start- oder Stopbedingungen erkennen.
>
> Ich bin offen für gute Ideen. Also lieber nicht die Länge mitgeben,
> dafür ein End Byte?

Nein, so ist das nicht gemeint.

Das Problem kann daran liegen, dass die Sequenz aus den Zeichen '-' 
und '+' zusätzlich auch in den Nutzdaten vorkommen.
Wenn Du nach diesen beiden Zeichen suchst, wie Du es ja tust, ist dass 
alleine also kein Zeichen, dass an dieser Stelle ein Datenrahmen 
beginnt.

Das Problem wird durch ein zusätzliches Ende-Zeichen nicht gelöst. Denn 
auch dieses Zeichen kann in den Daten vorkommen und ist also kein 
zuverlässiges Kriterium für das Ende eines Datenrahmens.

Daher der Vorschlag, den Rahmenanfang und das Ende durch solche Zeichen 
zu kennzeichnen die garantiert nicht in den Nutzdaten vorkommen. Da Du 
aber bisher alle Werte zwischen 0 und 255 als Daten zulassen willst, 
müsstest Du von dieser zweiten Bedingung abgehen. Dafür gibt es mehrere 
Möglichkeiten.

1. Du lässt in den Nutzdaten die Zeichen '-' oder '+' nicht zu.
2. Du lässt in den Nutzdaten die Folge von '-' und '+' nicht zu.
3. Du lässt in den Nutzdaten überhaupt keine nicht-druckbaren 
ASCII-Zeichen zu; oder anders herum: nur druckbare Zeichen. Genauer 
gesagt keine ASCII-Steuerzeichen; nur solche die wir Menschen 
interpretieren können. Zusätzlich wählst Du für den Rahmenanfang gerade 
eines der ASCII-Steuerzeichen.

Da gibt es so einige Varianten. Vielleicht fallen Dir noch welche ein.


Es gibt noch einen anderen Aspekt.

Die einfachste Variante so einer Kommunikation ist eigentlich, dass 
jemand eine Nachricht sendet, der Empfänger die Nachricht empfängt, 
verarbeitet und eine Antwort sendet. Dann erst sendet der Sender eine 
neue Nachricht auf die eine Antwort kommt.

Im Gegensatz dazu mag ein Sender, nicht immer auf ein Kommando warten, 
sondern einfach willkürlich senden. Oder er mag vielleicht für bestimmte 
empfangende Nachrichten länger brauchen als für andere, so das die 
Reihenfolge der Antworten, nicht immer strikt der Reihenfolge der 
empfangenen Nachrichten folgt.

Was ich damit sagen will: Falls der erste Fall zutrifft, bräuchtest Du 
den Beginn der Nachricht nicht zwingend zu "suchen". Du wüsstest ja 
definitiv, dass im Buffer die nächste Nachricht steht und wo sie steht.

Dazu gibt es einige Nebenbedingungen, wie etwa ein hoher Grad an 
Sicherheit der Datenübertragung und weitere.

Aber vielleicht überlegst Du Dir das mal.


Zusätzlich fällt mir an Deinem Code noch auf, dass du an dieser Stelle:
1
Length = buffer[FrameStartIndex + 2];

nur eines der Längenbytes aus dem Buffer liest, aber als Länge zwei 
Bytes vorgesehen hast:
1
            *  Nachrichtenlänge[2]             : 0..255


Auffällig ist auch, dass Du hier:
1
            *  Nachrichtenlänge[2]             : 0..255
2
            *  Anzahl Nutzdaten[3]             : 0..255

an sich eine doppelte, redundante Information zu haben scheinst .
Ich habe jedenfalls keine Idee, warum sich beide Grössenangaben anders 
als durch die Differenz der Längen aus den immer gleichen Kopf-Daten 
unterscheiden sollten. Und die ist ja konstant; immer die selbe.

Ausserdem ist mir unklar, warum die Nutzdaten ein Byte mehr als die 
Nachrichtenlänge haben sollen, wenn ich (vielleicht fälschlich) annehme, 
dass die Nutzdaten Teil der Nachricht sind. Dann könnten die Nutzdaten 
nicht länger als die gesamte Nachrichtenlänge sein.

von Purzel H. (hacky)


Lesenswert?

Kein Ringbuffer.. nee... Die Meldung muss im Rx Interrupt 
auseinandergenommen werden. Mit einer Zustandsmaschine.
zB wie in https://www.ibrtses.com/embedded/shortmsgprotocol.html

Und das Hauptprogramm bekommt nur etwas mit, wenn eine Meldung da ist, 
als solche erkannt wurde.

von Framulestigo (Gast)


Lesenswert?

Jan H. schrieb:
> Mein ganzes Vorgehen ist einfach nur für den Ars***..

Vielleicht etwas suboptimal, weil:
- das DataReceived-Ereignis in der Regel nicht das vollständige 
Telegramm beinhaltet. Das ist ein eigener Thread, der Dir die Daten 
zurückgibt, die bis zum Zeitpunkt eines erneuten Aufrufes im Puffer 
angekommen sind. Abhilfe: Schreib die Daten zuerst in einen eigenen 
Puffer (z.B. Ringpuffer mit eigenem Lese- und Schreibindex) und 
betrachte die Daten über mehrere Events im Zusammenhang.

- die Sache mit dem Telegrammrahmen so noch nicht eindeutig ist, wenn 
die eigentlichen Nutzdaten des Telegrammes eben die Rahmenbytes auch 
enthalten dürfen. Abhilfe wäre hier z.B. beim Senden zu prüfen, ob in 
den Nutzdaten just das "+"-Byte auftaucht um es dann eindeutig doppelt 
zu senden. Der Empfänger weiß dann: Ein einzelnes + ist der Start, ein 
doppeltes + liegt irgendwo in den Daten.

Vielleicht noch ein kleiner Tipp zum Schluss:
So einen Protokollparser muss man nicht unbedingt sofort an der 
seriellen Schnittstelle testen. Es geht einfacher durch eine 
Sendersimulation (den PC also erst mal selber in einen imaginären Puffer 
Bruchstücke von Telegrammen schreiben lassen), bei der man auch mal 
gezielt einen Übertragungsfehler einstreuen kann.

georg schrieb:
> Das kann auch nicht funktionieren. Damit Startbytes zuverlässig erkannt
> werden, dürfen sie im den restlichen Daten nicht vorkommen. Ein gültiges
> Protokoll besteht z.B. aus einem Startbyte STX und Daten nur aus
> lesbaren ASCII-Zeichen wie Ziffern und Buchstaben - dann kann das
> Startzeichen nicht in den Daten vorkommen. Es gibt auch viele andere
> Möglichkeiten eindeutig zu kodieren. Für das Ende, z.B. EOT, ETX, CR,
> gilt das Gleiche.

Excel macht es mit csv völlig sonderzeichenfrei vor. Die zeichnen die 
Trennzeichen eben nur so aus, dass eine Verwechslung mit Nutzdaten 
ausgeschlossen ist (',' im Text wird zu '","' und '"' im Text wird zu 
'""').

von Theor (Gast)


Lesenswert?

Jan H. schrieb:
> georg schrieb:
>> Jan H. schrieb:
>> /* Protokoll
>>             *
>>             *  Startbyte[0]                    : '-'
>>             *  Startbyte[1]                    : '+'
>>             *  Nachrichtenlänge[2]             : 0..255
>>
>> Das kann auch nicht funktionieren. Damit Startbytes zuverlässig erkannt
>> werden, dürfen sie im den restlichen Daten nicht vorkommen
>> Georg
> Dafür habe ich ja auch einen Header dort stehen die Infos drin.

Ja schon. Aber du wertest diese Tatsache nicht aus und falls Du es 
tätest, gäbe es kein zuverlässiges positives Kriterium; nur ein 
negatives.

Anders ausgedrückt: Du kannst zwar für gewisse Fälle feststellen, dass 
eine Nachricht nicht korrekt formatiert ist, aber nicht, dass sie 
korrekt formatiert ist.

Das ist gleichwertig zu der Frage ob ein gültiger Rahmenkopf gefunden 
wurde.

D.h. Du kannst zwar für gewisse Fälle feststellen, dass ein Rahmenkopf 
fehlerhaft ist (hauptsächlich wegen des Feldes "Daten Type") aber nicht, 
dass er nicht fehlerhaft ist, das also kein Rahmenkopf vorliegt.

von Theor (Gast)


Lesenswert?

Ah. Ganz übersehen. Da ist ja noch eine Prüfsumme! Beinhaltet die auch 
die nachfolgenden Nutzdaten?

Jedenfalls wäre das auch noch ein Kriterium um einen korrekten 
vollständigen Rahmen festzustellen und dessen Position im Buffer.


Aber das wird dann schon sehr aufwendig. Viel einfacher ist, den Rahmen 
ohne jeden Zweifel mit unverwechselbaren Zeichen oder Zeichenfolgen zu 
kennzeichnen.

von Thomas S. (thschl)


Lesenswert?

du musst zuerst auf das Startbyte warten, also wenn ein Zeichen an der 
Seriellen anliegt nur 1 Byte lesen also auf '-' warten dann das gleiche 
für '+', also BytesToRead=1, wenn die 2 Zeichen kommen dann ist das 3. 
Byte was kommt die Länge und das liest du auch einzeln, danach machst du 
einen BytesToRead=Längenbyte, so mit Timeout dass der Frame empfangen 
wird

von Jan H. (janiiix3)


Lesenswert?

Theor schrieb:
> Ah. Ganz übersehen. Da ist ja noch eine Prüfsumme! Beinhaltet die auch
> die nachfolgenden Nutzdaten?
>
> Jedenfalls wäre das auch noch ein Kriterium um einen korrekten
> vollständigen Rahmen festzustellen und dessen Position im Buffer.
>
>
> Aber das wird dann schon sehr aufwendig. Viel einfacher ist, den Rahmen
> ohne jeden Zweifel mit unverwechselbaren Zeichen oder Zeichenfolgen zu
> kennzeichnen.

Ja. Header + Nutzdaten.

von Otto Mans (Gast)


Lesenswert?

Jan H. schrieb:

>         for ( x = 0; x < buffer.Length ; x++ )
>         {
>             if ( buffer[x] == (char)'-')
>             {
>                 if ( buffer[x+1] == (char)'+')
>                 {
>                     return x;
>                 }
>             }
>         }

Hier aufgepasst: wenn x das letzte Zeichen ist, dann ist x+1 außerhalb 
Deines Buffers! Ich weiß, hilft nicht bei Deinem Kernproblem... ;-)

von georg (Gast)


Lesenswert?

Jan H. schrieb:
> Dafür habe ich ja auch einen Header dort stehen die Infos drin. Dieser
> hat eine bestimmte Länge

Du verstehst das Problem überhaupt nicht: das System rennt irgendwann 
los und es kommt als nächstes Byte keineswegs unbedingt ein Startbyte. 
Es muss also gewartet werden, bis ein gültiges Startbyte eintrifft, aber 
das ist eben nur eindeutig zu erkennen, wenn es in den restlichen Daten 
NICHT vorkommen kann.

Ebenso muss nach einem Übertragungsfehler neu synchronisiert werden, 
d.h. der nächste Start einer Nachricht erkannt - gleiches Problem.

Dazu wurden, nicht nur von mir, schon einige Möglichkeiten erwähnt, aber 
eines ist sicher: Bytes von 0..255 sind NICHT zulässig, weil sie eben 
JEDEN Wert annehmen können, auch den eines Start- oder Endbytes. Eine 
einfache Möglichkeit ist, nicht ein Byte 00..FF zu senden, sondern einen 
Text "000" bis "255". Dass das länger ist, spielt nur sehr selten 
überhaupt eine Rolle, ausserdem nützt eine schnelle Übertragung wenig 
wenn sie fehlerhaft ist.

Georg

von Stefan F. (Gast)


Lesenswert?

Man kann als Trennzeichen auch die Zeit benutzen, wie es gewöhnliche 
analoge und ISDN Modems tun.

Wenn man <Pause>+++<Pause> an das Modem sendet, wechselt es in den 
Befehlsmodus.

Wenn aber die Pause davor oder dahinter fehlt, wird die Zeichenfolge wie 
Nutzdaten behandelt.

von Joachim B. (jar)


Lesenswert?

ascii Tabelle
https://de.wikipedia.org/wiki/Steuerzeichen

STX abwarten (Beginn der Nachricht)
Zeichen sammeln bis
ETX (End of Text)

von Jan H. (janiiix3)


Lesenswert?

Joachim B. schrieb:
> ascii Tabelle
> https://de.wikipedia.org/wiki/Steuerzeichen
>
> STX abwarten (Beginn der Nachricht)
> Zeichen sammeln bis
> ETX (End of Text)

Das heißt damit kann ich aber auch nur ASCII übertragen? Wollte 
eigentlich mit reinen Bytes arbeiten.

von grundschüler (Gast)


Lesenswert?

Jan H. schrieb:
> Das heißt damit kann ich aber auch nur ASCII übertragen? Wollte
> eigentlich mit reinen Bytes arbeiten.

Du kannst das ganze auch z.B. von 8bit auf 7bit verschlüsseln. Das erste 
bit ist dann für Steuerzeichen reserviert. Für die Datenübertragung 
werden nur 7bits benutzt. Das erste Byte wird dann 7bit+ 1bit zerlegt, 
das nächste in 6bit+2bit usw.

von georg (Gast)


Lesenswert?

Jan H. schrieb:
> Wollte
> eigentlich mit reinen Bytes arbeiten.

Du hast es immer noch nicht verstanden: Binärbytes können JEDEN Wert 
annehmen, also gibt es keine Möglichkeit ein Startzeichen eindeutig zu 
erkennen, ausser wie Stefanus vorschlägt, du fügst Pausen ein. Dann 
musst du aber eine zuverlässige Pausenerkennung programmieren!!

Georg

von Jan H. (janiiix3)


Lesenswert?

georg schrieb:
> Jan H. schrieb:
>> Wollte
>> eigentlich mit reinen Bytes arbeiten.
>
> Du hast es immer noch nicht verstanden: Binärbytes können JEDEN Wert
> annehmen, also gibt es keine Möglichkeit ein Startzeichen eindeutig zu
> erkennen, ausser wie Stefanus vorschlägt, du fügst Pausen ein. Dann
> musst du aber eine zuverlässige Pausenerkennung programmieren!!
>
> Georg

… Ich meinte damit eher das ich nicht mit Strings arbeiten will. Z.B 
wenn ich jetzt den Wert "100" über die Serielle jage, brauche ich ja in 
ASCII 3 Bytes.
Das in den Nutzdaten die gleiche Zeichenfolge auftauchen kann wie in 
meinem Header ( sprich Startbyte(s) ) habe ich jetzt erstmal 
unterbunden.

Wie gehe ich denn jetzt am besten an die Auswertung?

von c-hater (Gast)


Lesenswert?

Jan H. schrieb:

> … Ich meinte damit eher das ich nicht mit Strings arbeiten will. Z.B
> wenn ich jetzt den Wert "100" über die Serielle jage, brauche ich ja in
> ASCII 3 Bytes.

ASCII ist zwar schick, weil man es leicht mitlesen kann und genug 
Redundanz für die Kontrolle läßt, aber sicher nicht für jedes Problem 
die optimale Lösung. Wie du ja bereits erkannt hast, ergibt sich da ein 
kleines Effizienzproblem.

> Das in den Nutzdaten die gleiche Zeichenfolge auftauchen kann wie in
> meinem Header ( sprich Startbyte(s) ) habe ich jetzt erstmal
> unterbunden.
>
> Wie gehe ich denn jetzt am besten an die Auswertung?

OK, dein Problem ist offensichtlich einfach nur: du müsstest zunächst 
erst einmal programmieren lernen. Wer es nicht alleine hinbekommt, 
ASCII-Übertragungen vernünftig zu parsen und auszuwerten, dem fehlen 
einfach ganz grundlegende Programmier-Fähigkeiten...

Nein, die kannst du nicht durch den Konsum von YT-Videos erwerben und 
auch nicht durch dümmliche Anfragen in irgendwelchen Webforen. Da hilft 
nur: 1) selber machen, 2) Fehler machen, 3) überlegen, was schief 
gelaufen sein könnte, 4) goto 1).

von W.S. (Gast)


Lesenswert?

Jan H. schrieb:
> Ich empfange von einem µC Kommandos. Diese sind verschieden lang.
> So sieht mein Protokoll aus.

Ja. Gruselig. Zuerst hast du zwei Kennbytes und dann hast du Zahlen von 
0..255. Was meinst du, was dabei an Verwirrung herauskommt?

Ich würde dir anraten, die Übertragung ganz anders zu organisieren. Aber 
dazu müßtst du dir Gedanken machen, was und wie du zu senden 
beabsichtigst.

Hier nur ein paar einfache Vorschläge:
1. sende die Nutzdaten nur als ASCII-Ziffernfolgen, ggf. einschließlich 
Minuszeichen, Punkt und dem kleinen 'e'.
2. sende formatfrei, aber atomar und mit abschließendem 
Kenn-Großbuchstaben. Damit hast du ein Protokoll, was sich von selbst 
synchronisiert.
3. lasse auf dem PC in deinem Programm den Empfang in einem separaten 
Thread laufen, der im Gegensatz zum Haupt-Thread rein prozedural abläuft 
und deshalb schlichtweg fast immer in der Empfangsschleife auf ein neues 
Zeichen von de Seriellen wartet.

So, wie sieht das Ganze dann aus:
zum Beispiel so:
1234X-1.7345e-3Q4711A
die Zahl 1234 wird im PC dekodiert und da sie mit 'X' abgeschlossen ist, 
wird sie für das verwendet, was du mit 'X' gemeint hast, z.B. ne 
Koodinate.
die Zahl -1.7345e-3 wird für das verwendet, was du unter 'Q' machen 
willst und die Zahl 4711A wird z.B. für ne Adresse in Köln benutzt.

Egal, wo bei so einem Kommandostrom die Kommunikation zustande kommt, 
hast du schon nach wenigen Zeichen die Synchronisation erreicht und ab 
da kannst du ohne feste Datenlängen übetragen, weil du ja das Ende 
zugleich mit der Marke für deren Verwendung am jeweiligen Buchstaben 
erkennst.

Ist nur ein Beispiel von vielen, wie man sowas anpacken könnte.

W.S.

von Jan H. (janiiix3)


Lesenswert?

Wie sieht es mit dem TLV Protokoll ( Type Length Value) aus?

von derjaeger (Gast)


Lesenswert?

In Anlehnung das genannte TLV Protokoll:


Stell die Länge ganz nach vorne. Gib der Länge ein Maximal zulässigen 
Wert zur Plausiblitätsprüfung. Dann vergleichst du ob die Anzahl der 
empfangenen Bytes die Anzahl der vorangestellten Länge übereinstimmt.


Zusätzlich hängst du als letztes Byte eine Prüfsumme über die gesamten 
Daten an. Wenn die Validierung der Prüfsumme in Ordnug war hast du was 
vollständiges intaktes bekommen.

von Jan H. (janiiix3)


Lesenswert?

derjaeger schrieb:
> In Anlehnung das genannte TLV Protokoll:
>
>
> Stell die Länge ganz nach vorne. Gib der Länge ein Maximal zulässigen
> Wert zur Plausiblitätsprüfung. Dann vergleichst du ob die Anzahl der
> empfangenen Bytes die Anzahl der vorangestellten Länge übereinstimmt.
>
>
> Zusätzlich hängst du als letztes Byte eine Prüfsumme über die gesamten
> Daten an. Wenn die Validierung der Prüfsumme in Ordnug war hast du was
> vollständiges intaktes bekommen.

So ähnlich habe ich mir das auch gedacht..

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.