Autor |
Beitrag |
RalfB
Hält's aus hier
Beiträge: 10
|
Verfasst: Sa 29.04.17 12:53
Hallo, ich arbeite zur Zeit an einem C#-Projekt zur Anbindung mehrerer Gas-Messgeräte.
Einer davon macht mir ein paar Probleme.
Schnittstellenbeschreibung:
Sende Wert an Gerät.
Warte 0,2 sec
Sende nächsten Wert.
Bekomme Antwort
Sende nächsten Wert....
...
2 der Antworten (6. und 7.) zusammen ergeben dann einen Wert, mit dem ich weiterberechnet dann den gemessenen CO2 Wert bekomme.
Funktionierend in Python:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48:
| #!/usr/bin/python import sys import serial import binascii import time try: ser = serial.Serial( 'COM4', baudrate=9600, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, timeout=0 ) except Exception as e: print -1 try: ser.write("\x02") time.sleep(0.2) ser.write("\x80") time.sleep(0.001) a1 = ser.readline() ser.write("\x4F") time.sleep(0.001) a2 = ser.readline() ser.write("\x00") time.sleep(0.001) a3 = ser.readline() ser.write("\x00") time.sleep(0.001) a4 = ser.readline() ser.write("\x03") time.sleep(0.001) a5 = ser.readline() ser.write("\x06") time.sleep(0.001) a6 = ser.readline() ser.write("\x06") time.sleep(0.001) a7 = ser.readline() time.sleep(0.001) ser.write("\x06") time.sleep(0.001) a8 = ser.readline() x1 = binascii.b2a_hex(a6) x2 = binascii.b2a_hex(a7) x = "0x"+x1+x2 x=int(str(x),0) y = x-8192 y = round((y/320.0),3) print y except Exception as e: print -2 |
Versuche ich das in C#, sollte wohl so aussehen:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104:
| private void COM4__() { try { } catch {
} try { serialPort1.PortName = "COM4"; serialPort1.BaudRate = 9600;
serialPort1.DataBits = 8; serialPort1.DtrEnable = true; serialPort1.Open(); } catch { } if (serialPort1.IsOpen) { richTextBox1.Text = "0"; serialPort1.Write("\x02"); int h = serialPort1.ReadBufferSize; richTextBox1.Text = h.ToString(); int bytes = serialPort1.BytesToRead; richTextBox1.Text += "\n1 " + bytes.ToString(); Thread.Sleep(200); serialPort1.Write("\x80"); Thread.Sleep(10); bytes = serialPort1.BytesToRead; richTextBox1.Text += "\n2 " + bytes.ToString(); byte[] buffer = new byte[bytes]; serialPort1.Read(buffer, 0, bytes); richTextBox2.Text = "\n"+ BitConverter.ToString(buffer); serialPort1.Write("\x4F"); Thread.Sleep(10); bytes = serialPort1.BytesToRead; richTextBox1.Text += "\n3 " + bytes.ToString(); buffer = new byte[bytes]; serialPort1.Read(buffer, 0, bytes); richTextBox2.Text += "\n" + BitConverter.ToString(buffer); serialPort1.Write("\x00"); Thread.Sleep(10); bytes = serialPort1.BytesToRead; richTextBox1.Text += "\n4 " + bytes.ToString(); buffer = new byte[bytes]; serialPort1.Read(buffer, 0, bytes); richTextBox2.Text += "\n" + BitConverter.ToString(buffer); serialPort1.Write("\x00"); Thread.Sleep(10); bytes = serialPort1.BytesToRead; richTextBox1.Text += "\n5 " + bytes.ToString(); buffer = new byte[bytes]; serialPort1.Read(buffer, 0, bytes); richTextBox2.Text += "\n" + BitConverter.ToString(buffer); serialPort1.Write("\x03"); Thread.Sleep(10); bytes = serialPort1.BytesToRead; richTextBox1.Text += "\n6 " + bytes.ToString(); buffer = new byte[bytes]; serialPort1.Read(buffer, 0, bytes); richTextBox2.Text += "\n" + BitConverter.ToString(buffer); serialPort1.Write("\x06"); Thread.Sleep(10); bytes = serialPort1.BytesToRead; richTextBox1.Text += "\n7 " + bytes.ToString(); buffer = new byte[bytes]; serialPort1.Read(buffer, 0, bytes); richTextBox2.Text += "\n" + BitConverter.ToString(buffer); serialPort1.Write("\x06"); Thread.Sleep(10); bytes = serialPort1.BytesToRead; richTextBox1.Text += "\n8 " + bytes.ToString(); buffer = new byte[bytes]; serialPort1.Read(buffer, 0, bytes); richTextBox2.Text += "\n" + BitConverter.ToString(buffer); serialPort1.Write("\x06"); Thread.Sleep(10); bytes = serialPort1.BytesToRead; richTextBox1.Text += "\n9 " + bytes.ToString(); buffer = new byte[bytes]; serialPort1.Read(buffer, 0, bytes); richTextBox2.Text += "\n" + BitConverter.ToString(buffer); serialPort1.Close();
} else { richTextBox1.Text = "NO"; }
} |
Damit bekomme ich ... Nichts
Wenn ich das versuche über den SerialDataReceivedEventHandler(serialPort1_DataReceived); zu lösen, feuert das abbonierte event auch nicht (die Port-reads mache ich dann natürlich nur da)
Egal ob ich .Read oder .ReadExisting benutze.
Wenn ich alle Zeichen als Gesamtstring ( serialPort1.Write("\x02\x80\x4F\x00\x00\x03\x06\x06\x06")) sende und dann noch einmal einzeln hinterher bekomme ich Antworten, aber nur 5 Byte statt 8. Und auch nicht jedes mal, sondern so bei 2 von 5 versuchen...
Hat jemand eine Idee?
Ist Thread.Sleep() hier vielleicht nicht richtig?
Moderiert von Th69: Code und C#-Tags hinzugefügt
Moderiert von Th69: C#-Tags hinzugefügt
|
|
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Sa 29.04.17 17:49
- Nachträglich durch die Entwickler-Ecke gelöscht -
|
|
RalfB
Hält's aus hier
Beiträge: 10
|
Verfasst: Mo 01.05.17 14:36
Hallo und Danke für den Tip.
Leider führt das nicht zum Erfolg.
.Readline führt zu keiner Antwort - Der Code bleibt da hängen.
Die Antworten müssten sein:
ACK (06)
ACK (06)
ACK (06)
ACK (06)
STX (02)
Datenbyte, z.B. 20
Datenbyte, Z.B. 0C
ETX (03)
wenn ich das .ReadLine ersetze durch .Read und mir die BytesToRead anzeigen lasse:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91:
| private List<string> COM4(SerialPort ser) { List<string> list = new List<string>(); try { list.Add("# Start"); richTextBox2.Text = "Start"; ser.PortName = "COM4"; ser.BaudRate = 9600; ser.DataBits = 8; ser.Parity = System.IO.Ports.Parity.None; ser.Open();
ser.WriteLine("\x02"); Thread.Sleep(200); ser.WriteLine("\x80"); Thread.Sleep(10); int bytes = ser.BytesToRead; byte[] buffer = new byte[bytes]; ser.Read(buffer, 0, bytes); richTextBox1.Text += "\n1 " + bytes.ToString(); richTextBox2.Text += BitConverter.ToString(buffer);
ser.WriteLine("\x4F"); Thread.Sleep(10);
bytes = ser.BytesToRead; buffer = new byte[bytes]; ser.Read(buffer, 0, bytes); richTextBox1.Text += "\n1 " + bytes.ToString(); richTextBox2.Text += BitConverter.ToString(buffer);
ser.WriteLine("\x00"); Thread.Sleep(10);
bytes = ser.BytesToRead; buffer = new byte[bytes]; ser.Read(buffer, 0, bytes); richTextBox1.Text += "\n1 " + bytes.ToString(); richTextBox2.Text += BitConverter.ToString(buffer);
ser.WriteLine("\x00"); Thread.Sleep(10);
bytes = ser.BytesToRead; buffer = new byte[bytes]; ser.Read(buffer, 0, bytes); richTextBox1.Text += "\n1 " + bytes.ToString(); richTextBox2.Text += BitConverter.ToString(buffer);
ser.WriteLine("\x03"); Thread.Sleep(10);
bytes = ser.BytesToRead; buffer = new byte[bytes]; ser.Read(buffer, 0, bytes); richTextBox1.Text += "\n1 " + bytes.ToString(); richTextBox2.Text += BitConverter.ToString(buffer);
ser.WriteLine("\x06"); Thread.Sleep(10);
bytes = ser.BytesToRead; buffer = new byte[bytes]; ser.Read(buffer, 0, bytes); richTextBox1.Text += "\n1 " + bytes.ToString(); richTextBox2.Text += BitConverter.ToString(buffer);
ser.WriteLine("\x06"); Thread.Sleep(10);
bytes = ser.BytesToRead; buffer = new byte[bytes]; ser.Read(buffer, 0, bytes); richTextBox1.Text += "\n1 " + bytes.ToString(); richTextBox2.Text += BitConverter.ToString(buffer); ser.WriteLine("\x06"); Thread.Sleep(10);
bytes = ser.BytesToRead; buffer = new byte[bytes]; ser.Read(buffer, 0, bytes); richTextBox1.Text += "\n1 " + bytes.ToString(); richTextBox2.Text += BitConverter.ToString(buffer);
ser.Close(); return list; } |
bekomme ich nur bei der ersten Abfrage 3 Bytes zum auslesen, jeweils immer 00
Moderiert von Christian S.: C#-Tags hinzugefügt
|
|
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mo 01.05.17 15:34
- Nachträglich durch die Entwickler-Ecke gelöscht -
|
|
RalfB
Hält's aus hier
Beiträge: 10
|
Verfasst: Mo 01.05.17 17:31
Hallo, danke für die Tips.
der Zugriff auf die Steuerelemente dient hier nur dazu, die Daten, die ich erhalte, möglichst schnell auf die Oberfläche zu bekommen (ist halt das Testprojekt..).
und dass mit der Liste scheiterte halt daran, dass die Funktion beim .ReadLine einfach ausgestiegen ist, auch ohne eine Exception zu werfen - da blieb die Oberfläche leer ....
mit einem .ReadExisting übrigens auch...
Ich danke dir für die guten Tips, ich denke aber, das Senden ist nicht das Problem, da ich in meinem eigentlichen Projekt schon einen anderen COM-Port eingebunden habe, bei dem ich auf dieselbe Art sende und die gewünschte Antwort bekomme. Der Unterschied ist, dass ich einen HEX-String sende und dann die Antwort bekomme, während ich bei diesem Port erst "eine Konversation führen muss"...
Aber natürlich werde ich dem Vorschlag folgen und das mit den anders konvertierten Hex-Werten mal testen.
Intuitiv denke ich allerdings, dass die Sache mit dem .Sleep(x) das Problem darstellt.
Hoffentlich liege ich falsch ...
Im Moment löse ich das Problem im eigentlich Prokjekt damit, das Python aus C# aufzurufen.
Klappt, aber ist nicht der Sinn eines C# Projektes...
|
|
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mo 01.05.17 17:42
- Nachträglich durch die Entwickler-Ecke gelöscht -
|
|
RalfB
Hält's aus hier
Beiträge: 10
|
Verfasst: Mi 03.05.17 07:33
Hallo,
mit .Readline() und .ReadExisting() laufe ich gesichert immer in einen Timeout.
mit:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42:
| private List<string> COM4Test(SerialPort ser) { List<string> list = new List<string>();
byte[] msg = { 0x02, 0x80, 0x4f, 0x00, 0x00, 0x03, 0x06, 0x06, 0x06 }; try { ser.PortName = "COM4"; ser.BaudRate = 9600; ser.DataBits = 8; ser.Parity = System.IO.Ports.Parity.None; ser.ReadTimeout = 0; ser.Open(); StringBuilder sb = new StringBuilder(); ser.WriteLine(msg[0].ToString()); Thread.Sleep(200); int x = 500; for (int i = 1; i < msg.Count(); i++) { ser.WriteLine(msg[i].ToString()); x = ser.BytesToRead; byte[] buffer = new byte[x]; ser.Read(buffer, 0, buffer.Length); for (int j = 0; j < buffer.Length; j++) sb.AppendFormat("{0:X2} ", buffer[j]); list.Add(sb.ToString()); } ser.Close(); return list; } catch (Exception ex) { list.Add(ex.Message); ser.Close(); return list; } } |
bekam ich 10 mal hintereinander Antworten (unabhängig, ob ich den String, Int oder den byte hineingab), allerdings immer 3 0x00 pro Schleifendurchlauf.
danach bekam ich keine Antwort mehr...
den Aufruf mit Python habe ich dann 100 mal fehlerfrei ausführen können.
Ist das Python-Script nicht zu C# übersetzbar?
In Python habe ich auch ein wenig mit den Sleeps herumexperimentiert: Im Gegensatz zur Schnittstellenbeschreibung funktionierte es auch mit 100 mls statt 200 mls.
Moderiert von Th69: C#-Tags hinzugefügt
|
|
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 03.05.17 11:41
- Nachträglich durch die Entwickler-Ecke gelöscht -
|
|
RalfB
Hält's aus hier
Beiträge: 10
|
Verfasst: Mi 03.05.17 13:39
Danke, das klingt nach dem richtigen Ansatz.
In Python wird einzeln geschickt.
Ich werde das bei nächster Gelegenheit testen.
|
|
Ralf Jansen
Beiträge: 4706
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mi 03.05.17 18:48
Zitat: | .WriteLine() schickt zeilenweise einen Befehl weg, .Write() schickt aneinadergereihte Befehle auf einmal weg. |
Write und WriteLine machen genau das gleiche. WriteLine schickt halt noch das Zeilenende-Zeichen hinterher, bzw. den string den man an der NewLine Property hinterlegt hat.
WriteLine sieht letztlich so aus
C#-Quelltext 1: 2: 3:
| public void WriteLine(string text) { Write(text + NewLine); } |
Gefühlt sollte man write benutzen und nicht für einzelne Bytes sondern für einen ganzen Befehl ohne sleeps dazwischen. So funktioniert der serielle Port nicht. Für etwas wo ich ein Signal für eine bestimmte Zeit anlege (also Byte setzen, warten, Byte ändern, warten etc.) setzt das Protokoll des seriellen Ports zu spät an. Da wäre gefühlt alles zu spät wo es schon eine Baudrate gibt. Oder was erwartest du wenn du ein Byte schickst und dann 200ms wartest? Das dann das Byte bei 9600 Baud ungefähr 9600/5 = 1920 mal gesendet wird?
@ RalfB Wenn das mit readline in php funktioniert was ist denn das Zeilenende-Zeichen dort? In .Net ist das erstmal '\n' (bzw. LF bzw. 10 bzw. 0x0a) wenn man es nicht geändert hat.
Zitat: | mit .Readline() und .ReadExisting() laufe ich gesichert immer in einen Timeout. |
Sicher? ReadLine wartet darauf das ein Zeilenende-Zeichen kommt. Das kann in einen Timeout laufen. Ich sehe aber nicht wie ReadExistingin einen Timeout laufen sollte. Es kommt halt das zurück was gerade jetzt im Empfangsbuffer ist. Wenn der leer ist bekommt man halt nix aber eigentlich keinen Timeout. Übrigens der Timeout steht erstmal auf Infinite. Sollte also auch bei Readline nicht auftreten. Außer natürlich du hast den ReadTimeout vom SerialPort geändert.
|
|
Frühlingsrolle
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: Mi 03.05.17 19:11
- Nachträglich durch die Entwickler-Ecke gelöscht -
|
|
RalfB
Hält's aus hier
Beiträge: 10
|
Verfasst: Do 04.05.17 11:06
Da ich wenig Zeit hatte, konnte ich nur kurz testen, die Benutzung von .Write statt . WriteLine löste das Problem.
Danke für die guten Tips und Denkanstöße.
Ich werde bald den kompletten Code hier posten, wenn es von Interesse ist.
|
|
RalfB
Hält's aus hier
Beiträge: 10
|
Verfasst: Do 04.05.17 13:07
Ralf Jansen hat folgendes geschrieben : | Zitat: | .WriteLine() schickt zeilenweise einen Befehl weg, .Write() schickt aneinadergereihte Befehle auf einmal weg. |
Write und WriteLine machen genau das gleiche. WriteLine schickt halt noch das Zeilenende-Zeichen hinterher, bzw. den string den man an der NewLine Property hinterlegt hat.
|
Und das ist das Problem anscheinend: Ich schicke nicht 0x02, sondern 0x02 + 0x0a. Will dass Gerät nicht haben ...
Ralf Jansen hat folgendes geschrieben : |
WriteLine sieht letztlich so aus
C#-Quelltext 1: 2: 3:
| public void WriteLine(string text) { Write(text + NewLine); } |
Gefühlt sollte man write benutzen und nicht für einzelne Bytes sondern für einen ganzen Befehl ohne sleeps dazwischen. So funktioniert der serielle Port nicht. Für etwas wo ich ein Signal für eine bestimmte Zeit anlege (also Byte setzen, warten, Byte ändern, warten etc.) setzt das Protokoll des seriellen Ports zu spät an. Da wäre gefühlt alles zu spät wo es schon eine Baudrate gibt. Oder was erwartest du wenn du ein Byte schickst und dann 200ms wartest? Das dann das Byte bei 9600 Baud ungefähr 9600/5 = 1920 mal gesendet wird?
|
Ich habe einfach die Beschreibung nachprogrammiert, die mir gedruckt gegeben wurde, funktionierte mit Python ...
Man findet Sie elektronisch noch nicht mal über Google, das genutzte Gerät ist anscheinend etwas älter.
Das man write benutzen sollte seh ich genauso, habe aber vorher noch keine Ansteuerung des COM-Ports über C# umgesetzt, suchte nach Bespielen, fand eines mit WriteLine und beim ersten Port funktionierte es.
Der angesteuerte Messfühler hat zwei Anschlüsse, einen für O2, den habe ich mit .WriteLine angesprochen (der Sendestring ist ähnlich, laut Beschreibung ohne Pausen und ich bekam sofort eine Antwort), die mit .Reaadline abgefragt ergibt einen ASCII-String, der von Stelle 10 bis 17 den O2 gehalt angibt.
Der andere ist für CO2, Temperatur und Luftdruck, die sollen laut Beschreibung mit den beschriebenen Pausen (also das erste Mal mit 0,2 Sekunden, dann sollte halt die oben beschriebene "Kommunikation", die ich jeweils durch eine Pause ersetzt habe, stattfinden) ablaufen.
Ralf Jansen hat folgendes geschrieben : |
@RalfB Wenn das mit readline in php funktioniert was ist denn das Zeilenende-Zeichen dort? In .Net ist das erstmal '\n' (bzw. LF bzw. 10 bzw. 0x0a) wenn man es nicht geändert hat.
|
readline in Python liest alles was da ist...
Ralf Jansen hat folgendes geschrieben : |
Zitat: | mit .Readline() und .ReadExisting() laufe ich gesichert immer in einen Timeout. |
Sicher? ReadLine wartet darauf das ein Zeilenende-Zeichen kommt. Das kann in einen Timeout laufen. Ich sehe aber nicht wie ReadExistingin einen Timeout laufen sollte. Es kommt halt das zurück was gerade jetzt im Empfangsbuffer ist. Wenn der leer ist bekommt man halt nix aber eigentlich keinen Timeout. Übrigens der Timeout steht erstmal auf Infinite. Sollte also auch bei Readline nicht auftreten. Außer natürlich du hast den ReadTimeout vom SerialPort geändert. |
Ich hatte den ReadTimeout auf 5000 gesetzt...
|
|
RalfB
Hält's aus hier
Beiträge: 10
|
Verfasst: Fr 05.05.17 15:02
Der funktionierende Code für den Zugriff:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64:
| private List<string> COM4Test(SerialPort ser) { List<string> list = new List<string>();
byte[] msg = { 0x02, 0x80, 0x4f, 0x00, 0x00, 0x03, 0x06, 0x06, 0x06 }; try { ser.PortName = "COM4"; ser.BaudRate = 9600; ser.DataBits = 8; ser.Parity = System.IO.Ports.Parity.None; ser.ReadTimeout = 0; ser.Open(); StringBuilder sb = new StringBuilder(); StringBuilder a1 = new StringBuilder(); StringBuilder a2 = new StringBuilder(); ser.Write(msg, 0,1); Thread.Sleep(100); int x = 0; for (int i = 1; i < msg.Count(); i++) { ser.Write(msg,i,1); byte[] buffer = new byte[ser.BytesToRead]; ser.Read(buffer, 0, buffer.Length); Thread.Sleep(10); for (int j = 0; j < buffer.Length; j++) { sb.AppendFormat("{0:X2} ", buffer[j]); if (i == 7) { a1.AppendFormat("{0:X2} ", buffer[j]); } if (i == 8) { a2.AppendFormat("{0:X2} ", buffer[j]); } } } x = Convert.ToInt32(("0x"+ a1.ToString().Replace(" ", "") + a2.ToString().Replace(" ", "")), 16); double y = x - 8192; y = Math.Round((y / 320.0), 3); list.Add("y = " + y.ToString()); list.Add(a1.ToString() + a2.ToString()); list.Add(sb.ToString()); list.Add("0x" + a1.ToString() + a2.ToString()); ser.Close(); return list; } catch (Exception ex) { list.Add(ex.Message); ser.Close(); return list; } } |
Moderiert von Christian S.: C#-Tags hinzugefügt
Und damit mein Dank an die Tipgeber und den mod, der die C#-Tags hinzugefügt hat.
|
|
Th69
Beiträge: 4791
Erhaltene Danke: 1059
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Fr 05.05.17 17:17
Die C#-Tags kannst (und darfst) du auch selbst hinzufügen.
|
|
|