Forum: PC-Programmierung Protokoll-Kommunikation mit einem IC in .NET abbilden -> HowTo?


von Ralf (Gast)


Lesenswert?

Hallo,

ich möchte die Kommunikation mit einem IC in .NET/C# abbilden. Der 
generelle Protokoll-Frame selbst ist relativ simpel:
Länge, Kommando, kommandospezifische Daten, CRC-Prüfsumme.
Die Antwort des ICs verwendet den gleichen Aufbau mit dem Unterschied, 
das zwischen Kommando-Byte und den Daten ein Statusbyte eingefügt ist, 
um Fehler zu signalisieren:
Länge, Kommando, Status, kommandospezifische Daten, CRC-Prüfsumme.

Knackig wird die ganze Sache dadurch, dass die kommandospezifischen 
Daten unterschiedlich aufgebaut sein können. Das heisst beispielsweise, 
dass die Daten in Abhängigkeit vom Kommando mal als 8-Bit- und mal als 
16-Bit-Werte zu interpretieren sind und ggf. auch Kombinationen daraus 
auftreten (8/16-Bit in einem Kommando). Die Anzahl der Daten kann auch 
variieren, das heisst alleine am Kommando-Byte kann man die Länge des 
gesamten Frames nicht immer eindeutig festmachen.

Wie geht man nun am besten vor? Die ersten Versuche habe ich mit simplen 
Byte-Arrays gemacht, hat auch soweit funktioniert. Jedes Kommando wird 
in einer Funktion bearbeitet, anhand der übergebenen Parameter wurde die 
Größe des Byte-Arrays berechnet und dieses danach gefüllt. Einer der 
Nachteile war, dass man die Größe explizit berechnen muss, bevor man die 
"eigentliche" Arbeit machen kann.

Ich frage mich nun, ob der Ansatz an sich geschickt ist, oder ob sich 
das beispielsweise mit ArrayList bzw. HashTable besser lösen lässt.
Bei beiden kann man einfach Elemente anfügen, die Größe ändert sich 
entsprechend dynamisch und die Vorberechnung der Größe entfällt. Diese 
benötige ich zwar für das Längenbyte, aber ich würde eher dazu 
tendieren, das Kommando an sich zu behandeln, und Längenbyte sowie 
Checksumme erst am Ende (in einer separaten Funktion) um das eigentliche 
Kommando zu wrappen, da Längenbyte und Prüfsumme nichts mit dem Kommando 
zu tun haben.
Die HashTable hätte zudem den Vorteil, dass man den jeweiligen Werten 
auch die entsprechenden Feldnamen des Kommandos bzw. dessen Parametern 
geben kann, was die Übersicht vereinfacht. Hier muss ich aber prüfen ob 
die Reihenfolge immer eingehalten wird.
Umgekehrt wird es wohl etwas schwieriger aus ArrayList/HashTable wieder 
ein normales Byte-Array zu machen, welches dem seriellen Port übergeben 
werden kann.

Wie löst man sowas geschickt und flexibel für Erweiterungen?

Ralf

von bluppdidupp (Gast)


Lesenswert?

Byte-Array zusammenbauen mache ich immer per MemoryStream (einfach 
rein-schreiben und anschließen .ToArray() aufrufen)

Ich würds vermutlich einfach so bauen:

Für Senden eine Helfer-Funktion wie z.B. sendMessage(byte commandId, 
byte[] payload) basteln.

Beim Empfangen: Nachricht parsen, und an eine Funktion übergeben:
1
void handleMessage(byte commandId, byte[] payload)
2
{
3
    if (commandId==XYZ)
4
    {
5
        handleCommandXYZ(payload); // handleCommandXYZ darf dann den payload irgendwie zerflücken.
6
    }
7
    ....
8
}
...sofern man nicht gerade tausende oder riesige Nachrichten bekommt, 
dürfte das ständige Kopieren von Daten praktisch nicht bemerkbar sein.

von Ralf (Gast)


Lesenswert?

@ bluppdidupp:
> per MemoryStream
Danke, ich les mir das mal durch.

> ...sofern man nicht gerade tausende oder riesige Nachrichten bekommt,
> dürfte das ständige Kopieren von Daten praktisch nicht bemerkbar sein.
Sehe ich auch so, da bei diesem IC die UART-Übertragungsrate max. 
115200Bd ist. Im SPI-Modus isser natürlich schneller, aber da ist dann 
eh das SPI-Interface zwischen Rechner und IC der Flaschenhals.

Ralf

von Reinhard Kern (Gast)


Lesenswert?

Hallo,

die Schichtenmodelle haben schon ihre Vorteile. Start, Länge, CRC 
gehören in eine andere Ebene wie die Nutzlast. Z.B. muss man sich mit 
der Bedeutung der einzelnen Bytes erst beschäftigen, wenn eine Message 
mit CRC korrekt empfangen wurde, bei einem Fehler fordert die 
Protokoll-Ebene selbstständig ein erneutes Senden an.

In embedded Systemen würde ich daher den Empfang bis zur CRC-Auswertung 
im Treiber lösen und nur fertig empfangene Messages an die nächsthöhere 
Ebene übergeben. Unter Windows will man natürlich Treiber-Programmierung 
vermeiden, da würde ich 3 Ebenen verwenden, den Windows-Treiber, auf den 
man keinen Einfluss hat, den Protokolltreiber und die 
Nutzlastauswertung. Dadurch kann man z.B. den Protokolltreiber wechseln 
ohne an der Nutzlast was ändern zu müssen. Auf die Art schreibe ich 
Protokolle, die je nach Einstellung mit einer seriellen Schnittstelle, 
Ethernet oder USB betrieben werden.

Ich erstelle für Antwort-Messages normalerweise eine Klassen-Hierarchie 
mit einer Grundklasse und Ableitungen für jede Kommandoart. D.h. die 
Message ist ein Objekt. Verschiedene abgeleitete Klassen können durchaus 
mal ein Array, eine Struktur usw. oder eine Zusammensetzung davon als 
Felder haben. Für ein bestimmtes Kommando z.B. ein Zeit-Record mit Jahr 
(word), Monat, Tag usw. (byte), danach 10 Messwerte (IEEE float), und so 
weiter.

Gruss Reinhard

von Ralf (Gast)


Lesenswert?

Hallo Reinhard,

das hört sich gut an. Den IC selbst wollte ich ebenfalls als Objekt 
implementieren, da ich evtl. mehrere gleichzeitig betreibe. Die 
Kommandos und deren Antworten als Objekte zu implementieren war auch ein 
Gedanke, den ich hatte, aber dazu fehlt mir noch ein ausgereifter 
Ansatz.
Ich werd mich mal ransetzen und notieren, was denn ein Objekt "Kommando" 
so an Eigenschaften hat. Vielleicht komm ich dann der Lösung einen 
Schritt näher :)

Ralf

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.