Serielle Schnittstelle unter C#

Hallo.
Ich hab eine klitzekleine C+±Applikation, die mir über eine Serielle schnittstelle ein paar Bytes an einen Drucker schickt.

Wenn ich das gleiche über C# versuche, funktioniert gar nichts.

Ich öffne den Port mit den richtigen Einstellungen. IsOpen liefert true zurück.
Dann schreibe ich
SerialPort port = new SerialPort(„COM1“, 9600, Parity.None, 8, StopBits.One);
port.Open();

port.Write("\x1B\x02\x11\x1B\x03"); //Start

ein serial-sniffer sagt mir, dass das Zeug meinen COM-Port verlassen hat. Nur der Empfänger reagiert nicht darauf. bzw. schickt er mir nichts zurück.

das ganze in c++:
char *start = „\x1B\x02\x11\x1B\x03“;
port.SendData(start, 0, strlen(start);
funktioniert aber.

Wenn ich zB ein port.WriteLine mache, hängt er mir halt ein \x0A an, aber ich komme auch nicht weiter.
So wirklich empfängt der Drucker meine Daten scheinbar auch nicht. Abgesehen davon dass er nichts zurückschickt, reagiert er auch nicht auf den gesandten Befehl.

Der Drucker ist übrigens ein Linx 4900.

Hi auch!

Nur mal ein Schuss ins Blaue: Hast Du’s mal mit port.BaseStream.Flush() probiert?
Eventuell hängen Deine Bytes noch im Ausgabepuffer fest…

Gruß,
Martin

Danke.

Probiert hab ichs, geändert hat es nichts.

was mir jetzt noch aufgefallen ist…:
ich sende meine 5 Bytes an die serielle Schnittstelle.
Im C# bleibt bytes to read auf 0.

Ich dreh meine C#schnittstelle ab, und schalte meinen sniffer von spy-Mode auf echte Kommunikation um. Dann empfängt er einmal Daten Daten. Zumindest sagt der einmal Len=irgendwas. Erwarten würde ich 7 Bytes, aber das diese Länge kann ja was anderes sein.

Und jetzt mal mein ganz blöder anderer Ansatz.
Ich schicke dem Drucker meine 5 Bytes, und er soll mir mit diesen Antworten:
\x1B\x06\x00\x00\x12\x1B\x03
man beachte die Nullvalues!!! kann das mein Problem sein?
dass er die 0values nicht lesen mag?

aber selbst wenn ich nur
port.BaseStream.ReadByte(); aufrufe, bleibt das Ding hängen.

Hab meine Writes und reads mittlerweile auf den BaseStream angewandt. Brachte aber auch keine Änderungen.

sodale… ich habe jetzt meinen simplen sniffer der mir nur die Bytes anzeigte durch was ordentlicheres ersetzt. und plötzlich kommen unterschiede zu tage.

alleine die Connection:
c++:
IRP_MJ_CREATE Serial0 SUCCESS Options: Open
IOCTL_SERIAL_SET_TIMEOUTS Serial0 SUCCESS RI:-1 RM:0 RC:0 WM:0 WC:5000
IOCTL_SERIAL_GET_BAUD_RATE Serial0 SUCCESS
IOCTL_SERIAL_GET_LINE_CONTROL Serial0 SUCCESS
IOCTL_SERIAL_GET_CHARS Serial0 SUCCESS
IOCTL_SERIAL_GET_HANDFLOW Serial0 SUCCESS
IOCTL_SERIAL_GET_BAUD_RATE Serial0 SUCCESS
IOCTL_SERIAL_GET_LINE_CONTROL Serial0 SUCCESS
IOCTL_SERIAL_GET_CHARS Serial0 SUCCESS
IOCTL_SERIAL_GET_HANDFLOW Serial0 SUCCESS
IOCTL_SERIAL_SET_BAUD_RATE Serial0 SUCCESS Rate: 9600
IOCTL_SERIAL_CLR_RTS Serial0 SUCCESS
IOCTL_SERIAL_CLR_DTR Serial0 SUCCESS
IOCTL_SERIAL_SET_LINE_CONTROL Serial0 SUCCESS StopBits: 1 Parity: NONE WordLength: 8
IOCTL_SERIAL_SET_CHAR Serial0 SUCCESS EOF:1a ERR:0 BRK:0 EVT:1a XON:11 XOFF:13
IOCTL_SERIAL_SET_HANDFLOW Serial0 SUCCESS Shake:0 Replace:0 XonLimit:2048 XoffLimit:512
IOCTL_SERIAL_SET_QUEUE_SIZE Serial0 SUCCESS InSize: 10000 OutSize: 10000
IRP_MJ_CLEANUP Serial0 SUCCESS
IRP_MJ_CLOSE Serial0 SUCCESS

die c#variante macht da mehr und leicht andere sachen:
IRP_MJ_CREATE Serial0 SUCCESS Options: Open
IOCTL_SERIAL_GET_PROPERTIES Serial0 SUCCESS
IOCTL_SERIAL_GET_MODEMSTATUS Serial0 SUCCESS
IOCTL_SERIAL_GET_BAUD_RATE Serial0 SUCCESS
IOCTL_SERIAL_GET_LINE_CONTROL Serial0 SUCCESS
IOCTL_SERIAL_GET_CHARS Serial0 SUCCESS
IOCTL_SERIAL_GET_HANDFLOW Serial0 SUCCESS
IOCTL_SERIAL_GET_BAUD_RATE Serial0 SUCCESS
IOCTL_SERIAL_GET_LINE_CONTROL Serial0 SUCCESS
IOCTL_SERIAL_GET_CHARS Serial0 SUCCESS
IOCTL_SERIAL_GET_HANDFLOW Serial0 SUCCESS
IOCTL_SERIAL_SET_BAUD_RATE Serial0 SUCCESS Rate: 9600
IOCTL_SERIAL_CLR_RTS Serial0 SUCCESS
IOCTL_SERIAL_CLR_DTR Serial0 SUCCESS
IOCTL_SERIAL_SET_LINE_CONTROL Serial0 SUCCESS StopBits: 1 Parity: NONE WordLength: 8
IOCTL_SERIAL_SET_CHAR Serial0 SUCCESS EOF:1a ERR:0 BRK:0 EVT:1a XON:11 XOFF:13
IOCTL_SERIAL_SET_HANDFLOW Serial0 SUCCESS Shake:0 Replace:0 XonLimit:1024 XoffLimit:1024
IOCTL_SERIAL_GET_BAUD_RATE Serial0 SUCCESS
IOCTL_SERIAL_GET_LINE_CONTROL Serial0 SUCCESS
IOCTL_SERIAL_GET_CHARS Serial0 SUCCESS
IOCTL_SERIAL_GET_HANDFLOW Serial0 SUCCESS
IOCTL_SERIAL_SET_BAUD_RATE Serial0 SUCCESS Rate: 9600
IOCTL_SERIAL_CLR_RTS Serial0 SUCCESS
IOCTL_SERIAL_CLR_DTR Serial0 SUCCESS
IOCTL_SERIAL_SET_LINE_CONTROL Serial0 SUCCESS StopBits: 1 Parity: NONE WordLength: 8
IOCTL_SERIAL_SET_CHAR Serial0 SUCCESS EOF:1a ERR:0 BRK:0 EVT:1a XON:11 XOFF:13
IOCTL_SERIAL_SET_HANDFLOW Serial0 SUCCESS Shake:0 Replace:0 XonLimit:1024 XoffLimit:1024
IOCTL_SERIAL_CLR_DTR Serial0 SUCCESS
IOCTL_SERIAL_SET_TIMEOUTS Serial0 SUCCESS RI:-1 RM:-1 RC:-2 WM:0 WC:0
IOCTL_SERIAL_SET_WAIT_MASK Serial0 SUCCESS Mask: RXCHAR RXFLAG CTS DSR RLSD BRK ERR RING
IOCTL_SERIAL_SET_QUEUE_SIZE Serial0 SUCCESS InSize: 4096 OutSize: 2048
IRP_MJ_FLUSH_BUFFERS Serial0 SUCCESS
IOCTL_SERIAL_SET_WAIT_MASK Serial0 SUCCESS Mask:
IOCTL_SERIAL_CLR_DTR Serial0 SUCCESS
RP_MJ_FLUSH_BUFFERS Serial0 SUCCESS
IOCTL_SERIAL_PURGE Serial0 SUCCESS Purge: RXABORT RXCLEAR
IOCTL_SERIAL_PURGE Serial0 SUCCESS Purge: TXABORT TXCLEAR
IRP_MJ_CLEANUP Serial0 SUCCESS
IRP_MJ_CLOSE Serial0 SUCCESS

Unterschiede sind zB bei den Timeouts oder beim XonXoff-Limit. super sache. und ich dachte schon mit
port = new SerialPort(„COM1“, 9600, Parity.None, 8, StopBits.One);
wäre es getan…

mein Problem ist noch nicht gelöst, aber ich hab immerhin eine neue Spur wo ich googeln kann. :smile:

Hi!

Ich nutze die Schnittstelle schon eine Weile und habe keine Probleme. Nach Deinen Ausführungen zu urteilen sollte es eigentlich klappen. Poste doch mal Deinen Code.

Sebo

„meinen Code“ finde ich gerade cool. ich bin ständig am umschreiben und erkenne meinen eigenen Code gar nicht so wirklich wieder…
aber eigenltich reduziert es sich auf folgendes:

byte[] start = new byte[] {0x1B, 0x02, 0x11, 0x1b, 0x03};

port.Handshake = Handshake.RequestToSendXOnXOff; //alle mögl. probiert
port.WriteBufferSize = 2048;
port.Encoding = Encoding.ASCII; //ist standardmäßig schon drin
port.RtsEnable = true; //bei meinem C++ programm ist das auch true
port = new SerialPort(„COM1“, 9600, Parity.None, 8, StopBits.One);
port.Open(); //Port öffnet sich auch!!!
//dann gibts bei mir immer neue Codevarianten:
//zB port.BaseStream.Write(start, 0, start.Length);
foreach (byte b in start)
{
port.BaseStream.WriteByte(b);
}
// Thread.Sleep(180); testweise gabs hier mal das eine oder andere sleep.

//Die Zeichenfolge die ich da sende veranlaßt den Drucker einen JOB zu beginnen. woraufhin er mir 7 Bytes zurückschickt. (sind weiter oben schon gepostet. rückgabe enthält „\x00“
beim c++ programm tut er dann auch was (ein Lämpchen geht an). beim c# rührt sich nix. und weil er wahrscheinlich dieses statement irgendwie falsch empfängt, schickt er mir auch keine Antwort

laut Druckerhandbuch muss nach jedem schreiben gelesen werden.

port.BytesToRead bleibt immer auf 0. und wenn ich trotzdem eine Lesemethode aufrufe hängt sich das Read, Readbyte, Readline oder was es noch alles gibt einfach ab!
ich schätze mal dass das sogar stimmt… und der Drucker mir noch nichts geschickt hat. aber so wirklich sicher bin ich auch nicht.
Wenn ich jedenfalls die serielle verbindung dann schließe und einen serial sniffer aktiv auf den Port zugreifen lasse, dann liest er mal einen haufen bytes. meine c++ app die sich sonst ganz gut bewährt liest aber nix. das sind halt vielleicht Indizien für irgendwas. zur Beweisführung reicht mir das noch nicht.

aktuell sehe ich gerade zu wie meine c++ applikation munter vor sich hin kommuniziert.
Wie in meinem letzten Thread schon bemerkt verbindet sich das C# etwas anders mit meinem Drucker.
zB ist beim c++ der Lese/Schreibpuffer nur 1000 Bytes groß.
Im C# kann ich das aber leider nur auf 4096 und 2048 einstellen. Kleinere werte werden ignoriert. aktuell theorisiere ich dass der Drucker einfach mit dem Buffer überfordert ist? bin da kein spezialist, aber wenn ich

port.Handshake = Handshake.RequestToSendXOnXOff; //alle mögl.

bist Du Dir sicher, dass Du das Du das Handshake Protokoll brauchst? Ist ist ziemlich selten, dass man es braucht.

port.WriteBufferSize = 2048;
port.Encoding = Encoding.ASCII; //ist standardmäßig schon drin
port.RtsEnable = true; //bei meinem C++ programm ist das auch
true

brauchste nicht, 2048 ist eh die Voreinstellung

port = new SerialPort(„COM1“, 9600, Parity.None, 8,
StopBits.One);
port.Open(); //Port öffnet sich auch!!!

klar macht der des.

//dann gibts bei mir immer neue Codevarianten:
//zB port.BaseStream.Write(start, 0, start.Length);
foreach (byte b in start)
{
port.BaseStream.WriteByte(b);
}

warum so kompliziert?

// Thread.Sleep(180); testweise gabs hier mal das eine oder
andere sleep.

versuchst Du etwas in dieser Methode auch gleich die Antwort auszulesen? Das funzt natürlich nicht! :smile:

Wenn über die serielle Schnittstelle Daten reinkommen wird das Event DataReceived gefeuert und genau dort kannst Du die Bytes dann lesen. Gaaaanz einfach, guggst Du … :smile:

Ich habe gerade nur ein Beispiel in VB und keine Lust das in C# umzuschreiben, aber es sind dieselben Methodenaufrufe:

Private receiveBuffer() As Byte
Private expectedBytes As Integer
Private WithEvents pSerialPort As SerialPort
Private Sub DoWorkContinue()
Me.pSerialPort = New SerialPort(PortName, Baud, Parity.None, 8, StopBits.Two)
Me.pSerialPort.Open()
Me.expectedBytes = 3
Me.pSerialPort.Write(New Byte(2) {&HA6, &H55, &H0}, 0, 3)
End Sub

Private Sub SerialPort_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs) Handles pSerialPort.DataReceived
Dim Index As Integer = 0
ReDim Me.receiveBuffer(Me.expectedBytes - 1)

'read only the expected count of Bytes
Do While (Me.pSerialPort.BytesToRead > 0) And (Index

bist Du Dir sicher, dass Du das Du das Handshake Protokoll
brauchst? Ist ist ziemlich selten, dass man es braucht.

hat mit .None und allen anderen Methoden eh auch ned funktioniert.

foreach (byte b in start)
{
port.BaseStream.WriteByte(b);
}

warum so kompliziert?

weil port.WriteLine, oder port.Write("\x1B\x02\x11\x1B\x03"); auch ned funktionert hat. man probiert halt aus…

// Thread.Sleep(180); testweise gabs hier mal das eine oder
andere sleep.

versuchst Du etwas in dieser Methode auch gleich die Antwort
auszulesen? Das funzt natürlich nicht! :smile:

Wenn über die serielle Schnittstelle Daten reinkommen wird das
Event DataReceived gefeuert und genau dort kannst Du die Bytes
dann lesen. Gaaaanz einfach, guggst Du … :smile:

nicht gaaaanz einfach. denn auch das habe ich natürlich schon probiert.
nur wird datareceived nie aufgerufen, weil nie lesbare daten anstehen, weil (ich glaube) dass der Drucker mit dem Empfangen der Daten nicht klarkommt. ich probier zwecks spaß an der Freude deine VB-Variante aber auch aus.

weil (ich glaube) dass der Drucker mit dem Empfangen
der Daten nicht klarkommt.

Kann nicht sein, wenn die Porteinstellungen richtig sind und Du die richtigen Bytes sendest und das Kabel ok ist und der Drucker eingeschaltet ist und sonst auch funktioniert, dann geht das auch.

Wenn Du einen zweiten Rechner hast, kannste ja ausprobieren, ob die Kommunikation überhaupt funktioniert. Dann schaue Dir die Kommunikations-Einstellungen Deiner Druckerkonfiguration an und übernehme die. Nimm’ einen Monitor und horche auf dem seriellen Port was über die Leitung geht wenn Du den Befehl mit den Druckertools (oder was auch immer) absendest und das bildest Du dann mit meiner Methode nach. Vergiss nicht, den Event-Handler an das Event zu knüpfen (gilt wenn Du den serialPort im Code erzeugst).