Hallo zusammen. Ich möchte mit einem Python-Skript ein Bild von einem Scanner abholen. Dieser ist im CDC Modus, ist also per USB angeschlossen aber taucht als COM Port im Geräte-Manager auf. Ich benutze pySerial, um ein Befehl zu senden und dann die Antwort zu lesen. Bei einem JPEG Bild im Verhältnis 1:16 (man kann im Befehl u.a. angeben, ob es 1:1, 1:4 oder 1:16 sein soll) funktioniert es einwandfrei. Den Header und die letzten 3 Byte, die das Ende der Übertragung angeben, werden weggeworfen und der Rest kommt direkt in eine name.jpg Datei geschrieben. Diese ist ca. 10kB groß.
Nun wollte ich das Bild im Verhältnis 1:1 abholen, doch das funktioniert nicht so recht. Mit der Software vom Scanner-Hersteller kann ich das Bild direkt abholen und anzeigen lassen. Außerdem hat es ein Terminal, mit dem ich den Befehl senden und die Antwort-Daten in HEX anzeigen lassen kann. Wenn ich die kopiere und in eine Datei schreibe, ist dort auch das Bild korrekt beim Anzeigen (siehe 1zu1_test_terminal.jpg). In meinem Python Skript nutze ich die Funktion s.read_until(b'\x06\x3b\x03'), um das Ende der Übertragung abzuwarten. Das wird auch durchgehend erfolgreich erkannt. Allerdings ist das Bild (siehe 1zu1_test_python.jpg) korrupt. Der Grund liegt wohl daran, dass Pakete während der Übertragung irgendwie untergehen. Im Header der Antwort steht am Ende die Anzahl der Bytes der Nutzdaten die im Anschluss folgen. Diese ist 87835 (Byte). Wenn ich dann aber die Länge der gelesenen Antwort ermittle, schwankt diese bei jedem mal lesen (z.B. 87006, 87198, 87134, 87070, 86942, ...). Daher ist es plausibel, dass Das Bild komisch aussieht. Außerdem fällt auf, dass zwischen den schwankenden "gelesene-Byte-Längen" immer ein Vielfaches von 64 liegt.
Nach etwas Recherche habe ich rausbekommen, dass es echt ein Problem in Kombination mit dem neuen Treiber (mit Win10 eingeführt) "usbser.sys" und dem pySerial Pakets zu sein scheint. Der letzte Stand von pySerial ist auch ca. 3 Jahre alt und ich bezweifle, dass daran noch aktiv gearbeitet wird.
Beim Googlen nach serieller Kommunikation mit Python wird pySerial aber in 90%+ der Fälle verwendet. Alternativ dazu gibt es ein WinUsbCDC Paket, welches in der Beschreibung direkt auf das oben genannte Phänomen hinweist: https://pypi.org/project/WinUsbCDC/#description
Eine weitere Möglichkeit scheint pyUSB zu sein. Beide Pakete nutzen den libusb-1.0 Treiber.
Aus mehreren Gründen würde ich die Pakete aber nicht nutzen wollen:
- Die Verbindung scheint über pID und vID zu laufen, doch es können auch mehrere gleiche Scanner am PC angeschlossen sein, wodurch eine Unterscheidung darüber nicht möglich wäre.
- Man muss den Treiber des Port aktiv wechseln. Ich bin mir nicht sicher, ob das an die pID und vID geknüpft ist und es egal ist, wo und wie viele Scanner angeschlossen sind, aber es ist ein händischer Vorgang, den ich gerne umgehen würde (das Skript soll auf mehreren PCs laufen und dort müsste es überall manuell geändert werden).
- Die Software des Herstellers funktioniert bei umgestelltem Treiber nicht mehr bzw. findet den Scanner erst gar nicht, um sich mit ihm dann verbinden zu können. Ohne ein Wechsel des Treibers für die Schnittstelle geht also entweder die Herstellersoftware ODER das Python-Script.
Um nun endlich auf den Punkt zu kommen:
Kennt jemand das Problem mit pySerial und Windows 10 und weiß von einem Workaround? Oder gibt es ein anderes Paket, das den usbser.sys Treiber nutzt? Ich habe dazu nirgends was gefunden. Da die Software vom Hersteller offenbar auch den usbser.sys Treiber nutzt, ist dort anscheinend kein Fehler per se drin. Sonst müsste die Software die Daten ja auch nicht korrekt lesen. Den Berichten zu folge taucht das Problem mit pySerial aber z.B. unter Win7 nicht auf. Ich bin aber an Win10 gebunden.
Hat jemand eine Idee oder eine Alternative? Ist es z.B. möglich, die usbser.sys in Python einzubinden? Ich würde allerdings auch ungern pySerial ungern neu schreiben müssen. Doch ich kann mir nicht vorstellen, dass seit Win10 da niemand an einer Lösung gearbeitet hat, die weiterhin den "Standard-Treiber" nutzt.
Vielen Dank schonmal Grüße Michael

